Intel和ATT汇编代码差异

下面是 CSAPP 原文

我们的表述是 ATT 可以产生 multstore 函数的 Intel 格式的代码: linux> gcc -0g -s -masm=intel mstore. c 这个命令得到下列汇编代码:

multstore:
	push    rbx
	mov     rbx, rdx
	call    mult2
	mov     QWORD PTR [rbx], rax
	pop     rbx
	ret

我们看到 Intel 和 ATT 格式在如下方面有所不同:

  • Intel 代码省略了指示大小的后缀。我们看到指令 pushmov,而不是 pushqmovq.
  • Intel 代码省略了寄存器名字前面的%符号,用的是 rbx,而不是%rbx
  • Intel 代码用不同的方式来描述内存中的位置,例如是 QWORD PTR[rbx] 而不是 (%rbx)
  • Intel 立即数 (immediate), 也就是常数值,不使用前缀 $,如,十进制数 123,不是 $123;十六进制数 123h,不是 $0x123
  • Intel 指令一般使用从右到左的顺序,而 ATT 使用从左到右,如 Intel 是 mov dst, src,而 ATT 是 mov src, dst
  • AT&T 语法中立即数前面加一个字符 $;寄存器操作数名前要加字符百分号 %;绝对跳转/调用(相对于与程序计数器有关的跳转/调用)操作数前面要加星号 *。而 Intel 汇编语法均没有这些限制。
  • AT&T 语法中内存操作数的长度(宽度)由操作码最后一个字符来确定。操作码后缀‘b’、‘w’和‘l’分别指示内存引用宽度为 8 位字节(byte)、16 位字(word)和 32 位长字(long)。Intel 语法则通过在内存操作数前使用前缀 byte prtword ptrdword ptr 来达到同样的目的。因此,Intel 的语句 mov al, byte ptr foo 对应于 AT&T 的语句 movb $foo, %al

代码示例

int main(){
    int a = 1;
    int b = 2;
    int c = a + b;
    return 0;
}

上述代码经过编译后, objdump 观察到:

0000000000001129 <main>:
	...
    1131:       c7 45 f4 01 00 00 00    movl   $0x1,-0xc(%rbp)
    1138:       c7 45 f8 02 00 00 00    movl   $0x2,-0x8(%rbp)
    113f:       8b 55 f4                mov    -0xc(%rbp),%edx
    1142:       8b 45 f8                mov    -0x8(%rbp),%eax
    1145:       01 d0                   add    %edx,%eax
    1147:       89 45 fc                mov    %eax,-0x4(%rbp)
    114a:       b8 00 00 00 00          mov    $0x0,%eax
    114f:       5d                      pop    %rbp
    1150:       c3                      retq
	...

通过 1145 和 1147 ,可以发现 %eax 是 dst, 代码格式为 ATT。