Say hello to x86_64 Assembly 系列的第六篇。这里会看一看 AT&T 汇编语法。先前我们使用的都是 nasm 汇编工具,但也有其他不同语法的汇编工具,比如 fasm,yasm。接下的的部分我们会看到 gas(GNU 汇编工具)及其与 nasm 语法的不同之处。GCC 使用 GNU 汇编工具。因此若查看下列代码的汇编输出:
1 |
|
会看到这样的输出:
1 | .file "test.c" |
译者注:文件命名为 test.c,$gcc -o test.s -S test.c
,可得之。
恩,看起来的确大不相同,接着看吧。
AT&T 语法
段(Section)
我并不知道你的习惯是怎样的,但我的汇编程序通常起于段定义。一个简单的栗子:
1 | .data |
可以注意到两点微小的不同:
- 段定义起于 .symbol
- main routine 定义以
.globl
开始,并非我们使用 nasm 写的global
gas 定义数据也使用不同的指令:
1 | .section .data |
操作数指令(Operands order)
使用 nasm 写汇编程序的时候,对数据操作有下列通用的语法:
1 | mov destination, source |
而使用 GNU 汇编工具,顺序却相反:
1 | mov source, destination |
举个栗子:
1 | ;; |
寄存器起始于 % 标志;若使用立即数(direct operands),需要使用 __$__。
1 | movb $10, %rax |
操作数字长与操作语法(Size of operands and operation syntax)
有时候需要指定操作数的字长,比如 64 位寄存器的第一个字节,使用下面的语法(译者注:这是 nasm 语法):
1 | mov ax, word [rsi] |
这是在 gas 中的一种操作方法。并不需要在操作数中定义大小,而是在指令中:
1 | movw (%rsi), %ax |
GNU 汇编工具的操作码有 6 种后缀:
- b – 1 字节操作数
- w – 2 字节操作数
- l – 4 字节操作数
- q – 8 字节操作数
- t – 10 字节操作数
- o – 16 字节操作数
这规则不仅仅用于 mov
指令,也用于所有类似于 addl, xorb, cmpw 等类似的指令。
内存访问(Memory access)
注意到在前面的 gas 栗子中使用了 () 代替了 nasm 栗子中的 **[]**。在 gas 中取消对值的访问(寻址)为 **(%rax)**,例如:
1 | movq -8(%rbp), %rdi |
跳转(Jumps)
GNU 汇编工具支持下列的远程函数调用与跳转(far functions call and jumps)操作:
- lcal $section, $offset
- 远程跳转(far jump) – 跳转到一个指令,这个指令不在当前代码段(code segment)中,而是位于不同的段(segment),也具有相同的特权等级,有时也被成为段间跳转(intersegment jump)。
注释(comments)
GNU 编译工具支持下面三种形式的注释:
- # -- 单行注释
- // – 单行注释
- /* */ -- 多行注释
结语
…
原文
译者的罗嗦:讲真,我也没看懂多少,我又没接触过 gas,撇嘴 =_= 意思应该差不多,因为我参考了这。