本文转载自点击打开链接
GCC采用的是AT&T的汇编格式, 也叫GAS格式(GnuASembler GNU汇编器), 而微软采用Intel的汇编格式. 语法上主要有以下几个不同.
1、寄存器命名原则
AT&T |
Intel |
说明 |
%eax |
eax |
Intel的不带百分号 |
2、源/目的操作数顺序
AT&T |
Intel |
说明 |
movl %eax, %ebx |
mov ebx, eax |
Intel的目的操作数在前,源操作数在后 |
3、常数/立即数的格式
AT&T |
Intel |
说明 |
movl $_value,%ebx |
mov eax,_value |
Intel的立即数前面不带$符号 |
movl $0xd00d,%ebx |
mov ebx,0xd00d |
规则同样适用于16进制的立即数 |
4、操作数长度标识
AT&T |
Intel |
说明 |
movw %ax,%bx |
mov bx,ax |
Intel的汇编中, 操作数的长度并不通过指令符号来标识 |
在AT&T的格式中, 每个操作都有一个字符后缀, 表明操作数的大小. 例如:mov指令有三种形式:
movb 传送字节
movw 传送字
movl 传送双字
因为在许多机器上, 32位数都称为长字(longword), 这是沿用以16位字为标准的时代的历史习惯造成的.
---------摘自《深入理解计算机系统》
5、寻址方式
AT&T |
Intel |
imm32(basepointer,indexpointer,indexscale) |
[basepointer + indexpointer*indexscale + imm32) |
两种寻址的实际结果都应该是
imm32 + basepointer +indexpointer*indexscale
AT&T的汇编格式中, 跳转指令有点特殊.
直接跳转, 即跳转目标是作为指令的一部分编码的.
例如: jmp Label_1
间接跳转, 即跳转目标是从寄存器或存储器位置中读出的. 写法是在" * "后面跟一个操作数指示符.
例如:
jmp *%eax
用寄存器%eax中的值作为跳转目标
jmp *(%eax)
以%eax中的值作为读入的地址, 从存储器中读出跳转目标
--------摘自《深入理解计算机系统》
下面是一些寻址的例子:
AT&T: `-4(%ebp)' 相当于 Intel: `[ebp - 4]'
AT&T: `foo(,%eax,4)' 相当于 Intel: `[foo + eax*4]'
AT&T: `foo(,1)' 相当于 Intel `[foo]'
AT&T: `%gs:foo' 相当于 Intel`gs:foo'