寻址方式(Addressing Modes)
AT&T 内存操作数通用格式:
section:disp(base, index, scale)
等价于地址:section_base + disp + base + index * scale
disp:偏移常量(十进制或十六进制0x...),可以是符号。base:基址寄存器。index:变址寄存器。scale:1、2、4 或 8(index 的乘数,缺省为 1)。- 各部分均可省略,但括号与逗号结构需保留。
常见形式
| 形式 | 示例 | 含义 |
|---|---|---|
| 直接(绝对地址) | movl value, %eax |
地址 value 处的值 |
| 寄存器间接 | movl (%eax), %ebx |
*eax |
| 带偏移 | movl 8(%ebp), %eax |
*(ebp+8) |
| 变址 | movl (%ebx,%ecx), %eax |
*(ebx+ecx) |
| 变址+比例 | movl (%ebx,%ecx,4), %eax |
*(ebx+ecx*4) |
| 偏移+变址+比例 | movl 12(%ebx,%ecx,4), %eax |
*(ebx+ecx*4+12) |
| 无基址变址 | movl arr(,%ecx,4), %eax |
*(arr+ecx*4) |
| RIP 相对(64 位) | leaq msg(%rip), %rdi |
rip + msg 的偏移(PIC 常用) |
注意事项
- 内存到内存操作不被允许:两个操作数不能都是内存,需经寄存器中转。
scale只能是 1/2/4/8,省略时默认为 1:(%ebx,%ecx)是合法的(base+index,scale 默认 1);但(%ebx+%ecx)这种"寄存器相加"写法非法。- 64 位模式下请使用 64 位寄存器寻址。使用 32 位寄存器(如
(%eax,%ebx))虽然能汇编,但会生成地址大小前缀(address-size override),有效地址被截断为 32 位,容易出错。 %rsp不能用作 index 寄存器;%rip只能以disp(%rip)的形式出现,不能作 base/index。- 64 位模式下直接绝对寻址(如
movl 0x8049000, %eax)使用符号扩展的 32 位位移,地址超出低 2GB/高 2GB 范围会出错。要访问任意地址,先把地址装入寄存器:movabsq $0x1122334455667788, %rax再movl (%rax), %eax(非 PIC 场景)。 - 只有
mov接受 64 位立即数:movq $0x1122334455667788, %rax(汇编器实际生成 movabs)。
# 遍历数组(每个元素 4 字节)
movl $0, %ecx
loop:
movl arr(,%rcx,4), %eax # arr[rcx]
addl $1, %ecx
cmpl $4, %ecx
jl loop
段前缀
movl %fs:0, %eax # 从 fs 段偏移 0 处读取(线程局部存储常用)