ATT汇编语法简介
这里,我们介绍三种类型的ATT汇编指令操作数的表示方法,其中指令参考对应体系的指令集(ISA)。
第一种类型是立即数(immediate),其书写方式是'$'后面跟一个用标准C表示法表示的整数,比如$-577或$0x1F。任何能够放进一个64位字里的数值都可以用作立即数,不过汇编器在可能时会使用一个、两个、四个或八个字节的编码。
第二种类型是寄存器(register),其表示某个寄存器的内容,对四字操作来说,可以是16个64位寄存器中的一个(例如,%rax),对双字操作来说,可以是16个32位寄存器中的一个(例如,%eax),对于字或字节操作类同。我们用符号Ea来表示任意的寄存器a,用引用R[Ea]来表示它的值,这是将寄存器集合看成一个数组R,用寄存器标识符作为索引。
第三类操作数是存储器(memory)引用,其会根据计算出来的地址(通常是有效地址)访问某个存储器位置。因为将存储器看成一个很大的字节数据,我们用符号Mb[Addr]来表示存储在存储器中从地址Addr开始的b个字节值的引用。为了方便,我们省去下方的b。
寻址模式,其允许不同形式的存储器引用。语法Imm(Eb,Ei,s)表示的是最常用的形式。这样的引用有四个组成部分:一个立即数偏移Imm,一个基址寄存器Eb,一个变址寄存器Ei和一个比例因子s,这里的s必须是1、2、4或8(这个表达式也就是我们初中数学中学到的线性函数y=ax+b+C的ATT语法啦)。然后,有效地址被计算为Imm+R[Eb]+R[Ei]×s。引用数组元素时,会用到这种通用形式。其他形式都是这种通用形式的特殊情况,只是省略了某些部分。如下图:
类 型 |
格 式 |
操作数值 |
名 称 |
示 例 |
立即数 |
$Imm |
Imm |
立即数寻址 |
movq $0x1234,%rax |
寄存器 |
Ea |
R[Ea] |
寄存器寻址 |
movq %rax,%rdx |
存储器 |
Imm |
M[Imm] |
绝对寻址 |
movq 0x80064,%rbx |
存储器 |
(Ea) |
M[R[Ea]] |
间接寻址 |
movq (%ebp),%esp |
存储器 |
Imm(Eb) |
M[Imm+R[Eb]] |
(基址+偏移量)寻址 |
movq 0x8(%rdi),%rax |
存储器 |
(Eb,Ei) |
M[R[Eb]+R[Ei]] |
变址寻址 |
movq (%rdi,%rax),%rcx |
存储器 |
Imm(Eb,Ei) |
M[Imm+R[Eb]+R[Ei]] |
变址寻址 |
movq 0x8(%rdi,%rax),%rcx |
存储器 |
(,Ei,s) |
M[R[Ei]×s] |
比例变址寻址 |
movq (,%rdi,0x2),%rcx |
存储器 |
Imm(,Ei,s) |
M[Imm+R[Ei]×s] |
比例变址寻址 |
movq 0x8(,%rdi,0x2),%rcx |
存储器 |
(Eb,Ei,s) |
M[R[Eb]+R[Ei]×s] |
比例变址寻址 |
movq (%rbx,%rdi,0x2),%rcx |
存储器 |
Imm(Eb,Ei,s) |
M[R[Eb]+R[Ei]×s] |
比例变址寻址 |
movq 0x8(%rbx,%rdi,0x2),%rcx |
GCC的开发者坚定地保持与i386的二进制兼容性,即使是IA32指令集中添加了有用的特性,包括条件传送和更现代的浮点指令集。只有以特殊的命令行选项设置编译时,才会使用这些特性。在x86-64作为目标时,这为GCC提供了一个放弃后向兼容性的机会,只用标准的命令行选项就能利用这些新特性。
对于x86-64位平台与IA32的主要特性区别是:
- 指针和长整型是64位长。整数算术运算支持8、16、32和64位数据类型;
- 通用目的寄存器组从8个扩展到16个,分别为%r[a-d]x,%r[sd]i,%r[bs]p,%r[8-15]。其中,%rbp不再专用为frame pointer,而是通用寄存器;
- 许多程序状态都保存在寄存器中,而不是栈上。整形和指针类型的过程参数(最多6个)通过寄存器传递。有些程序根本不需要访问栈;
- 如果可能,条件操作用条件传送指令实现,会得到比传统分支代码更好的性能;
- 浮点操作用面向寄存器的指令集(SSE2 or later)来实现,而不是x87。