# 3.4.1 操作数指示符

大多数指令有一个或多个操作数(operand),指示出执行一个操作中要使用的源数据值,以及放置结果的目的位置。x86-64 支持多种操作数格式(参见图 3-3)。源数据值可以以常数形式给出,或是从寄存器或内存中读出。结果可以存放在寄存器或内存中。因此,各种不同的操作数的可能性被分为三种类型。

第一种类型是立即数(immediate),用来表示常数值。在 ATT 格式的汇编代码中,立即数的书写方式是 $ 后面跟一个用标准 C 表示法表示的整数,比如,$-577$0x1F。不同的指令允许的立即数值范围不同,汇编器会自动选择最紧凑的方式进行数值编码。

第二种类型是寄存器(register),它表示某个寄存器的内容,16 个寄存器的低位 1 字节、2 字节、4 字节或 8 字节中的一个作为操作数,这些字节数分别对应于 8 位、16 位、32 位或 64 位。在图 3-3 中,我们用符号 ra 来表示任意寄存器 a,用引用 R[ra] 来表示它的值,这是将寄存器集合看成一个数组 R,用寄存器标识符作为索引。

第三类操作数是内存引用,它会根据计算出来的地址(通常称为有效地址)访问某个内存位置。因为将内存看成一个很大的字节数组,我们用符号 Mb[Addr] 表示对存储在内存中从地址 Addr 开始的 b 个字节值的引用。为了简便,我们通常省去下标 b。

如图 3-3 所示,有多种不同的寻址模式,允许不同形式的内存引用。表中底部用语法 Imm(rb, ri, s) 表示的是最常用的形式。这样的引用有四个组成部分:一个立即数偏移 Imm,一个基址寄存器 rb,一个变址寄存器 ri 和一个比例因子 s,这里 s 必须是 1、2、4 或者 8。基址和变址寄存器都必须是 64 位寄存器。有效地址被计算为 Imm + R[rb] + R[ri] · s。引用数组元素时,会用到这种通用形式。其他形式都是这种通用形式的特殊情况,只是省略了某些部分。正如我们将看到的,当引用数组和结构元素时,比较复杂的寻址模式是很有用的。

类型 格式 操作数值 名称
立即数 $Imm Imm 立即数寻址
寄存器 ra R[ra] 寄存器寻址
存储器 Imm M[Imm] 绝对寻址
存储器 (ra) M[R[ra]] 间接寻址
存储器 Imm(rb) M[Imm + R[rb]] (基址 + 偏移量)寻址
存储器 (rb, ri) M[R[rb] + R[ri]] 变址寻址
存储器 Imm(rb, ri) M[Imm + R[rb] + R[ri]] 变址寻址
存储器 (, ri, s) M[R[ri] · s] 比例变址寻址
存储器 Imm(, ri, s) M[Imm + R[ri] · s] 比例变址寻址
存储器 (rb, ri, s) M[R[rb] + R[ri] · s] 比例变址寻址
存储器 Imm(rb, ri, s) M[Imm + R[rb] + R[ri] · s] 比例变址寻址

图 3-3 操作数格式。操作数可以表示立即数(常数)值、寄存器值或是来自内存的值。比例因子 s 必须是 1、2、4 或者 8

练习题 3.1 假设下面的值存放在指明的内存地址和寄存器中:

地址
0x100 0xFF
0x104 0xAB
0x108 0x13
0x10C 0x11
寄存器
%rax 0x100
%rcx 0x1
%rdx 0x3

填写下表,给出所示操作数的值:

操作数
%rax
0x104
$0x108
(%rax)
4(%rax)
9(%rax,%rdx)
260(%rcx,%rdx)
0xFC(,%rcx,4)
(%rax,%rdx,4)