汇编指令是机器指令的助记符,与机器指令一一对应。汇编存在多种形式,8086CPU目前主流的有AT&TINTEL两种,Windows使用INTEL语法,UNIX平台的编译器一直使用AT&T语法。本文以8086CPU为例,主要介绍AT&T语法的基础汇编指令。

1. 寄存器

CPU由运算器、控制器和寄存器等构成,寄存器用于进行数据存储。8086有14个寄存器,这14个寄存器可按用途分为:8个通用寄存器、指令指针、标志寄存器和段寄存器四类。

E--表示32位寄存器,R--表示64位寄存器。

1.1 通用寄存器

寄存器说明
EAX(累加寄存器)常用于运算,在乘除等指令中指定用来存放操作数,用于I/O指令传送数据。
EBX(基址寄存器)常做内存数据的指针(地址索引),用于访问内存。
ECX(计数器)用于保存计算值,在移位、循环和串处理指令中做隐含的计数器。
EDX(数据寄存器)进行乘、除运算时作为默认的操作数参与运算,也用于存放I/O的端口地址。
ESI(源变址寄存器)可用于存放相对DS段的源变址指针,常用作内存数据指针和源字符串指针。
EDI(目的变址寄存器)存放存储单元在段内的偏移量,用它们可实现多种存储器操作数的寻址方式。
ESP(堆栈指针寄存器)只做堆栈的栈顶指针,不能用于算术运算和数据传送。
EBP(基址指针寄存器)只用做堆栈指针,可以访问堆栈内任意地址。

通用寄存器中EAXEBXECXEDX都属于数据寄存器,他们都可以再分为独立的寄存器。这里以EAX为例。

  1. EAX是32位的寄存器;
  2. AX是16位的寄存器(EAX的低16位);
  3. AH是8位寄存器(AX的高8位);
  4. AL是8位寄存器(AX的低8位)。

1.2 指令指针

32位CPU把指令指针记为EIP扩展到32位,在EIP的低16位与CPU中的IP作用相同。

指令指针用于存放下次将要执行的指令在代码段中的偏移量,在具有预取功能的系统中,下次要执行的指令通常已被预取到指令队列中,除非发生转移情况。

1.3 标志寄存器

标志寄存器称为FLAG,也称为PSW(Processor Status Word)。共其中有6个运算结果状态标志位:OF、SF、ZF、AF、PF、CF,及3个控制标志位DF、IF、TF。

运算结果状态标志位

  1. 进位标志CF(Carry Flag):进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。

  2. 奇偶标志PF(Parity Flag):奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则其值为0。利用PF可进行奇偶校验检查,或产生奇偶校验位。

  3. 辅助进位标志AF(Auxiliary Carry Flag):当发生低字节向高字节进位或借位时,或低4位向高4位进位或借位时,辅助进位标志AF的值被置为1,否则其值为0。

  4. 零标志ZF(Zero Flag):零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。

  5. 符号标志SF(Sign Flag):符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同,所以SF也就反映运算结果的正负号。运算结果为正数时,SF的值为0,否则其值为1。

  6. 溢出标志OF(Overflow Flag):溢出标志OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。

状态控制标志位

状态控制标志位是用来控制CPU操作的,它们要通过专门的指令才能使之发生改变。

  1. 追踪标志TF(Trap Flag):当追踪标志TF被置为1时,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求。这种方式主要用于程序的调试。指令系统中没有专门的指令来改变标志位TF的值,但程序员可用其它办法来改变其值。

  2. 中断允许标志IF(Interrupt-enable Flag):中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求,CPU的指令系统中也有专门的指令来改变标志位IF的值。

  3. 方向标志DF(Direction Flag):方向标志DF用来决定在串操作指令执行时有关指针寄存器发生调整的方向。

32位标志寄存器增加的标志位

  1. I/O特权标志IOPL(I/O Privilege Level):I/O特权标志用两位二进制位来表示,也称为I/O特权级字段。该字段指定了要求执行I/O指令的特权级。如果当前的特权级别在数值上小于等于IOPL的值,那么,该I/O指令可执行,否则将发生一个保护异常。

  2. 嵌套任务标志NT(Nested Task):嵌套任务标志NT用来控制中断返回指令IRET的执行,当NT=0,用堆栈中保存的值恢复EFLAGS、CS和EIP,执行常规的中断返回操作,当NT=1,通过任务转换实现中断返回。

  3. 重启动标志RF(Restart Flag):重启动标志RF用来控制是否接受调试故障。RF=0时表示“接受”调试故障。

  4. 虚拟8086方式标志VM(Virtual 8086 Mode):如果该标志的值为1,则表示处理机处于虚拟的8086方式下的工作状态,否则,处理机处于一般保护方式下的工作状态。

1.4 段寄存器

寄存器说明
ECS(代码段寄存器)代码段的段值
EDS(数据段寄存器)数据段的段值
EES(附加段寄存器)附加数据段的段值
ESS(堆栈段寄存器)堆栈段的段值

2. AT&T与INTEL区别

AT&TINTEL的区别在语法表示上,没有质的区别。

  1. 运算表达式的顺序相反:

    AT&T:<cmd> <src> <tar>

    INTEL:<cmd> <tar> <src>

  2. 赋值符号不同:

    **AT&T:**使用->赋值

    **INTEL:**使用=赋值

  3. 寄存器和立即数的书写方式不同:

    **AT&T:**寄存器前需加%,立即数前加$

    **INTEL:**直接书写寄存器或立即数。

  4. 括号不同:

    **AT&T:**使用圆括号()

    **INTEL:**使用方括号[]

  5. 指令操作码后缀不同:

    **AT&T:**操作码后追加一个字母,l表示长整数(32位),w表示字(16位),b表示字节(8位)。

    **INTEL:**在操作数前面加对应指令,dword ptr表示长整数,word ptr表示字,byte ptr表示字节。

    示例:

    // AT&T
    movl     (%ebx),%eax
    
    // INTEL
    Mov     eax, dword ptr [ebx]
    
  6. 间接寻址方式不同:

    **AT&T:**间接寻址指令格式:%segreg:disp(base,index,scale)

    **INTEL:**间接寻址指令格式:segreg:[base+index*scale+disp]

    示例:

    // AT&T
    Subl     -0x20(%ebx,%ecx,0x4),%eax
    // INTEL
    sub     eax,[ebx+ecx*4h-20h]
    

3. 常见汇编指令

以下介绍的语法都是AT&T语法,除非有特

3.1 数据传送指令

这些指令主要在寄存器与内存、寄存器与输入/输出端口之间传送数据。

1. mov

数据传送指令

AT&TINTEL说明
movl 1, %eaxMOV EAX, 1将自然数1传送到eax寄存器
movl %ebx,%eaxMOV EAX,EBX将ebx的值传给ebx寄存器

2. pop

出栈用一个寄存器接收数据

AT&T说明
pop %eax将栈顶数据弹出到eax寄存器

3. push

将一个寄存器中的数据入栈

AT&T说明
push1 %ebp将ebp寄存器的输入压入栈

3.2 算数运算指令

包括算术基本四则运算、浮点运算、数学运算(正弦、反弦)等。

1. add

加法运算

AT&T说明
add 3, %eax将自然数3与eax寄存器中的数相加,结果存储在eax中

2. inc

加1指令

AT&T说明
inc %ebx对ebx寄存器中的数加1

3. dec

减1指令

AT&T说明
dec %ebx对ebx寄存器中的数减1

3.3 逻辑运算指令

与、或、非、左移、右移等指令。

3.4 串指令

连续空间分配,连续空间取值,传送等。高级语言的字符串即是通过串指令实现。

3.5 程序转移指令

if...else...判断、for循环、while循环、函数调用等都依靠程序转移指令实现。