3.3 内存引用
x86-64 提供灵活的内存寻址模式,可以高效地计算地址并访问内存。最通用的形式是 Imm(Reg, Reg, Scale) 格式。
通用寻址格式
地址 = Imm + Reg1 + Reg2 × Scale
| 组成部分 | 含义 | 可取值 |
|---|---|---|
Imm | 立即数偏移 | 1, 2 或 4 字节的常数 |
Reg1 | 基址寄存器 | 任意通用寄存器 |
Reg2 | 变址寄存器 | 任意通用寄存器(除 %rsp) |
Scale | 比例因子 | 1, 2, 4, 8 |
寻址模式分类
1. 立即数寻址
仅包含立即数偏移,用于访问静态全局变量。
movq 0x1234, %rax # 从地址 0x1234 读取
movq global_var, %rax # 从符号 global_var 的地址读取2. 寄存器间接寻址
最常用的形式,按寄存器中的地址访问内存。
movq (%rax), %rbx # rbx = *(uint64_t *)rax
movq %rbx, (%rax) # *(uint64_t *)rax = rbx对应 C 语言的指针解引用:
long val = *ptr; // movq (%rax), %rbx
*ptr = val; // movq %rbx, (%rax)3. 基址+偏移量寻址
常用于访问结构体成员或栈上局部变量。
movq 8(%rbp), %rax # 从 rbp+8 地址读取
movl -4(%rbp), %eax # 从 rbp-4 地址读取(局部变量)对应 C 语言的结构体访问:
struct S { long a; long b; };
struct S s;
s.b = 10; // movq $10, 8(%rdi) 其中 %rdi 指向 s4. 变址寻址
常用于数组访问。
movq (%rdi, %rsi, 8), %rax # rax = *(rdi + rsi*8)对应 C 语言的数组访问:
long arr[N];
long val = arr[i]; // movq (%rdi, %rsi, 8), %rax
// %rdi = &arr[0], %rsi = i5. 比例变址寻址
结合所有组件。
movq 8(%rdi, %rsi, 4), %rax # rax = *(rdi + rsi*4 + 8)所有寻址模式总表
| 类型 | AT&T 格式 | 地址计算 | 使用场景 |
|---|---|---|---|
| 立即数 | Imm | Imm | 全局变量 |
| 寄存器 | (Reg) | Reg | 指针解引用 |
| 基址+偏移 | Imm(Reg) | Reg + Imm | 结构体/栈访问 |
| 变址 | (Reg, Reg) | R1 + R2 | 数组(元素大小为 1) |
| 比例变址 | (Reg, Reg, S) | R1 + R2×S | 数组 access (S=元素大小) |
| 基址+比例变址+偏移 | Imm(Reg, Reg, S) | Imm + R1 + R2×S | 复合场景 |
常见应用模式
数组遍历
# int arr[N]; 元素大小 4 字节
# 假设 %rdi = &arr[0], %rsi = i
movl (%rdi, %rsi, 4), %eax # arr[i]二维数组
# long A[M][N]; 元素大小 8 字节,每行 N 个元素
# 访问 A[i][j]:地址 = A + i*N*8 + j*8
# %rdi = A, %rsi = i, %rdx = j
imulq $N, %rsi, %rsi # rsi = i * N
addq %rsi, %rdi # rdi = A + i*N*8 (隐式×8)
movq (%rdi, %rdx, 8), %rax # rax = A[i][j]详见 。
结构体访问
# struct S { int x; long y; int z; };
# %rdi 指向 struct S
movl (%rdi), %eax # s.x (偏移 0)
movq 8(%rdi), %rdx # s.y (偏移 8, 因对齐)
movl 16(%rdi), %ecx # s.z (偏移 16)地址计算与 lea 指令
利用寻址模式的计算能力,在不访问内存的情况下完成算术运算:
leaq (%rdi, %rsi, 4), %rax # rax = rdi + rsi*4 (不访问内存)相关笔记
-
- 内存引用作为操作数
-
- 地址计算与算术运算
-
- 数组的内存布局与访问
-
- 结构体成员的内存偏移
链接到
- 上一个知识点:3.2 寄存器
- 下一个知识点:3.4 数据传送指令