汇编学习笔记-汇编程序的基本语法(NASM)

Posted 蹦蹦骑士

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编学习笔记-汇编程序的基本语法(NASM)相关的知识,希望对你有一定的参考价值。

前言

  从本博文开始,我将主要学习NASM的语法格式,辅以MASM语法的相关了解

 

一个最简单的helloword 

; 功能描述 helloword
org 07c00h ; 告诉编译器程序加载到7c00处,否则strMess位置的计算会出错的
section .data
     strMess: db "Hello, OS world!"
     strlen equ $-strMess       ; 计算 strmess的长度
section .text mov ax, strMess mov bp, ax ; ES:BP = 串地址 mov cx, strlen ; CX = 串长度 mov ax, 01301h ; AH = 13, AL = 01h mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮) mov dl, 0 int 10h ; 10h 号中断 ret jmp $ ; 无限循环

 流程控制

  1. if-else

    if-else 语句其实就是 cmp +  条件判断语句(如, je,ja,jb jne...)语句的组合

      原理: 1. 使用cmp来调整标记寄存器的的标记位

          2. 使用对应的条件判断指令来实现条件转跳,条件转跳指令会根据CMP指令对标志寄存器进行判断从而根据结果进行转跳

  例子:

        mov ax, 2
        cmp ax, 2
        je a            ; if( eax = 2)
        jmp  exit        ;else

a:      cmp ax, 1
        ja b            ; if(eax > 1)
        jmp  exit        ;else

b:      cmp ax, 3       
        jb c            ; if(eax < 3)
        jmp  exit        ;else
c:

 

   2. while 和 for 循环

      while是使用了loop指令,loop指令就是判断CX是否为0,如果cx=0,那么啥都不做,如果cx 不等于 0 则 cx-- 然后转跳

   例子 

   ; while循环
mov cx, 10 mov bx, 0 add: add bx,1 loop add ; while(ecx != 0)

 

 调用子程序

       调用子程序其实不像C/C++那样有明确的界限,你可以使用任意的过程转跳指令去调用子程序,可以用非条件转移指令jmp也可以使用条件转移指令 je ja jb 等等,我现在所说的就是一般意义上用到的子程序调用指令 call和ret、retf。

       Call和jmp一样也分为段内和段间调用,对应的返回函数就风别是ret和retf,ret是段内返回,retf就是段间返回。

       Call和jmp的区别在于 call指令在jmp之前将当前地址给压栈了。

;段内调用
Call:       Push ip
            Jmp newip

Ret         pop ip

;段间转移

Call:       Push cs
            Push ip
       Jmpnewcs:newip

Retf:      pop ip
           Pop cs

 具体语法MASM和NASM是略有不同的 

MASM:

       段内:
              Call sub1      ; sub1是子过程
              Call bx
              Call [bx]
              Call var         ; var是变量

       段间:
              Call sub1
              Call far ptr sub1
              Call dword ptr [bx]
              Call var

        nasm 有proc伪指令,用于声明过程调用语句,具体语法如下  

过程调用名  PROC [NEAR|FAR]

....

过程调用名 ENDP

 

  所以MASM可以显式的指明过程调用需要的是段内还是段间调用。 

 

NASM

       段内:
              Call sub1
         Call 立即数
              Call bx
         Call var 

       段间:
              Call far [bx]
              Call 立即数:立即数
              Call dword var 

       我不清楚nasm是否能正对标签识别出是段内和段间调用,但是我没发现显式声明使用标签的段间调用指令,但是我看到有博客说,nasm的16位汇编模式是没有段这个概念。我猜意思可能是段这个概念需要编程者自己去管理,nasm认为所有代码都在同一个段内。

 

参数传递

  汇编的参数传递是很灵活,具体只要调用方和被调用方约定好基本是随便传递,基本有三种方式

  1. 寄存器传递参数

  2.内存传递参数

  3.堆栈传递参数

  其中有几点需要注意

  1. 环境的保护,意思是在子过程中肯定要用到标志寄存器和一些其他寄存器,但是如果这里面有调用者重要的信息的话数据就被破坏了会导致调用者的异常。

  2. 数据的清理,比如使用堆栈传递数据,使用完之后由调用者清理还是被调用者清理。

  具体可以看一下c/c++的几个调用约定,stdcall fastcall 等等。。

 

 

 

 

 

以上是关于汇编学习笔记-汇编程序的基本语法(NASM)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 gcc 生成可以用 nasm 编译的汇编代码 [重复]

NASM汇编学习系列——获取命令行参数

汇编语言---指令格式和基本语法

NASM汇编学习系列——示例打印0到10

汇编器的NASM

NASM汇编学习系列——使用bss段和获取用户输入