本文为纯手打原创硬核干货,适合学习计算机组成、汇编、CSAPP 的同学,欢迎真实阅读、交流。
基于 x86-64 架构,本文将从主存(Main Memory)的矩阵式物理实现切入,系统拆解内存寻址机制、数据传送指令族与栈操作逻辑,带你吃透 CPU 与内存交互的底层原理,彻底搞懂 mov 指令的本质。
一、主存的物理实现与寻址
1.1 矩阵式存储结构
现代主存的实现采用矩阵(Matrix)结构,而非简单的线性排列。这种设计的核心动机是避免"极长的内存地址线"带来的物理布线难题。
核心思想:通过行列译码将一维地址映射到二维物理空间,大幅降低地址译码电路的复杂度。
1.2 x86-64 的内存模型
在 x86-64 架构中,内存系统具有以下关键特性:
| 地址空间 | 理论上支持
2 64 2^{64} 264 个不同的内存地址 |
| 地址长度 | 每个内存地址需要 64 位二进制表示 |
| 寻址粒度 | 每个地址指向单个字节(1 byte = 8 bits) |
| 字节序 | 小端序(Little-Endian) |
虽然架构支持
2
64
2^{64}
264 地址空间,但实际实现通常只使用 48 位(256 TB)以避免页表过于庞大。
二、数据格式与 mov 指令规则
x86-64 汇编指令使用单字符后缀明确表示操作数的大小,这是理解指令行为的基础:
| b | byte | 1 byte (8 bits) | movb |
| w | word | 2 bytes (16 bits) | movw |
| l | long/double word | 4 bytes (32 bits) | movl |
| q | quad word | 8 bytes (64 bits) | movq |
2.1 数据移动指令(mov)
| movb | move byte |
| movw | move word |
| movl | move double word |
| movq | move quad word |
| movb | move byte |
| movw | move word |
2.2 特殊传送指令:movabsq
当需要处理 64 位立即数时,标准 movq 可能会发生截断(符号扩展),此时需要使用 movabsq:
; 错误:立即数被截断为 32 位再符号扩展
movq $0x0011223344556677, %rax ; %rax = 0x0000000044556677 ❌
; 正确:完整 64 位立即数传送
movabsq $0x0011223344556677, %rax ; %rax = 0x0011223344556677 ✓
三、x86-64 寄存器体系
3.1 通用寄存器的层级结构
x86-64 寄存器支持部分访问,这是向下兼容 32/16/8 位代码的关键设计: 
3.2 常用寄存器一览
| %rax | %eax | %ax | %al | 累加器,返回值 |
| %rbx | %ebx | %bx | %bl | 基址寄存器 |
| %rcx | %ecx | %cx | %cl | 计数器,循环变量 |
| %rdx | %edx | %dx | %dl | 数据寄存器 |
| %rsi` | %esi` | %si` | %sil | 源变址 |
| %rdi` | %edi` | %di` | %dil | 目的变址 |
| %r8-%r15` | %r8d-%r15d` | %r8w-%r15w | %r8b-%r15b` | 扩展寄存器 |
四、操作数寻址模式(Operand Forms)
x86-64 提供了丰富灵活的寻址方式,可分为三类:立即数(Immediate)、寄存器(Register) 和 内存(Memory)。 内存指寄存器地址里存的数,可能是一个数值,也可能是一个新的地址。
4.1 寻址模式速查表
| 立即数 | $Imm |
I m m Imm Imm |
Immediate |
| 寄存器 | ra |
R [ r a ] R[ra] R[ra] |
Register |
| 绝对寻址 | Imm |
M [ I m m ] M[Imm] M[Imm] |
Absolute |
| 间接寻址 | (ra) |
M [ R [ r a ] ] M[R[ra]] M[R[ra]] |
Indirect |
| 基址+偏移 | Imm(rb) |
M [ I m m + R [ r b ] ] M[Imm + R[rb]] M[Imm+R[rb]] |
Base + displacement |
| 变址寻址 | (rb, ri) |
M [ R [ r b ] + R [ r i ] ] M[R[rb] + R[ri]] M[R[rb]+R[ri]] |
Indexed |
| 比例变址 | (rb, ri, s) |
M [ R [ r b ] + R [ r i ] ⋅ s ] M[R[rb] + R[ri] \\cdot s] M[R[rb]+R[ri]⋅s] |
Scaled indexed |
📝 比例因子 s 的取值:只能是 1, 2, 4, 8(方便数组元素访问)
4.2 寻址计算实例
假设寄存器与内存状态如下:
| 0x100 | 0xFF | %rax | 0x100 |
| 0x104 | 0xAB | %rcx | 0x1 |
| 0x108 | 0x13 | %rdx | 0x3 |
| 0x10C | 0x11 | – | – |
则各操作数值为:
| %rax | R[%rax] | 0x100 |
| 0x104 | M[0x104$] | 0xAB |
| $0x108 | 0x108$ | 0x108 |
| (%rax) | M[0x100] | 0xFF |
| 4(%rax) | M[0x100 + 4] | 0xAB |
| 9(%rax, %rdx) | M[0x100 + 0x3 + 9] | 0x11 |
| 260(%rcx, %rdx) | M[0x1 + 0x3 + 0x104] | 0x13 |
| (%rax, %rdx, 4) | M[0x100 + 0x3 * 4] | 0x11 |
-
常见场景:%rdi是参数中的数组A,%rcx表示偏移量设为i
-
寄存器与寻址逻辑 %rdi = A (数组首地址/指针) %rcx = i (索引/偏移量)
-
不同数据类型的寻址映射 int *A: (%rdi, %rcx, 4) -> A[i] char *A: (%rdi, %rcx, 1) -> A[i] long *A: (%rdi, %rcx, 8) -> A[i]
-
五、数据扩展传送指令
5.1 零扩展(Zero-Extending)
将较小数据扩展为较大数据,高位补零:
| movzbw | 8-bit | 16-bit | 零扩展到字 |
| movzbl | 8-bit | 32-bit | 零扩展到双字 |
| movzbq | 8-bit | 64-bit | 零扩展到四字 |
| movzwl | 16-bit | 32-bit | 零扩展到双字 |
| movzwq | 16-bit | 64-bit | 零扩展到四字 |
- 特殊等价:movzlq %ecx, %rax 等价于 movl %ecx, %eax,因为 32 位移动会自动零扩展到 64 位。
5.2 符号扩展(Sign-Extending)
将较小数据扩展为较大数据,高位复制符号位:
| movsbw | 8-bit | 16-bit |
| movsbl | 8-bit | 32-bit |
| movsbq | 8-bit | 64-bit |
| movswl | 16-bit | 32-bit |
| movswq | 16-bit | 64-bit |
| movslq | 32-bit | 64-bit |
| cltq | %eax | %rax |
- cltq = movslq %eax, %rax => %rax = sign-extend(%eax)
5.3 扩展指令对比实验
movq $0x0011223344556677, %rax ; %rax = $0x0000000044556677 (仅改低8位)
movabsq $0x0011223344556677, %rax ; %rax = 0x0011223344556677
movb $0xAA, %dl ; %dl = 0xAA (10101010)
movb %dl, %al ; %rax = 0x00112233445566AA (仅改低8位)
movsbq %dl, %rax ; %rax = 0xFFFFFFFFFFFFFFAA (符号扩展,1填充)
movzbq %dl, %rax ; %rax = 0x00000000000000AA (零扩展,0填充)
六、栈操作:Push 与 Pop
在 x86-64 架构中,堆栈不仅仅是一个数据结构,它是通过寄存器 %rsp 维护的硬编码内存区域。其核心逻辑在于地址的逆向增长与指针的解引用同步。
6.1 核心概念:反直觉的“向下生长”
栈是内存中一块特殊的区域,专门用来临时存储数据(如局部变量、保存的寄存器状态等)。
- 栈顶指针:寄存器 %rsp 始终存储当前栈顶元素的起始地址。
- 向下生长:压栈操作会导致 %rsp 向低地址方向位移。也就是说,压入的数据越多,%rsp 里的地址数值反而越小。
- 操作单位:在 x86-64 系统中,栈操作的标准单位是 Quadword(8 字节 / 64 位)。
6.2 指令拆解:微操作等价性
push 和 pop 是高度封装的指令。在理解其执行流时,可以将其拆解为指针算术与内存访问的组合:
- 入栈 (Push) 执行 pushq %rax 时,CPU 执行以下复合动作:
pushq %rax 完全等价于:
subq $8, %rsp ; 1. 栈顶指针下移(地址减小)
movq %rax, (%rsp) ; 2. 将数据写入新的栈顶地址
- 出栈 (Pop) 执行 popq %rax 时,CPU 的操作顺序正好相反:
popq %rax 完全等价于:
movq (%rsp), %rax
addq $8, %rsp
6.3 状态追踪:寄存器与内存瞬时态
以下是在 %rsp 初始值为 0x8000 时,执行连续操作的 Trace 分析。
| movq $0x123, %rax | 0x123 | 0x8000 | M[0x8000] = ? | 寄存器预设值 |
| pushq %rax | 0x123 | 0x7FF8 | M[0x7FF8] = 0x123 | 指针下移 8 字节并写入 |
| movq $0x22, %rax | 0x22 | 0x7FF8 | M[0x7FF8] = 0x123 | 寄存器改写,内存维持现状 |
| pushq %rax | 0x22 | 0x7FF0 | M[0x7FF0] = 0x22 | 指针再次下移并写入 |
| popq %rax | 0x22 | 0x7FF8 | M[0x7FF8] = 0x123、M[0x7FF0] = 0x22 | 数据载入寄存器,指针回退 |
观察上面表格的最后一行 popq %rax: 出栈操作仅仅是改变了 %rsp 的指向,不会清空或擦除内存里的旧数据! 地址 0x7FF0 里的 0x22 虽然物理上未被擦除,但在下一次 push 覆盖它之前,它被视为垃圾数据。
七、常见错误与注意事项
7.1 非法操作数组合
| movb $0xF, (%ebx) | 不能使用 %ebx 作为地址寄存器(32位) | movb $0xF, (%rbx) |
| movl %rax, (%rsp) | 指令后缀 l 与寄存器 rax(64位)不匹配 | movq %rax, (%rsp) |
| movw (%rax), 4(%rsp) | 源和目的不能同时为内存引用 | 使用寄存器中转 |
| movb %al, %sl | 不存在 %sl 寄存器 | movb %al, %sil |
| movq %rax, $0x123` | 立即数不能作为目的操作数 | movq $0x123, %rax |
| movl %eax, %dx | 目的操作数大小不正确 | movl %eax, %edx |
| movb %si, 8(%rbp) | 指令后缀 b 与寄存器 si(16位)不匹配 | movw %si, 8(%rbp) |
7.2 关键原则
八、实战:C 代码与汇编对照
8.1 交换函数(Swap)
void swap(long *xp, long *yp) {
long t0 = *xp;
long t1 = *yp;
*xp = t1;
*yp = t0;
}
对应 x86-64 汇编:
swap:
movq (%rdi), %rax ; t0 = *xp (xp 在 %rdi)
movq (%rsi), %rdx ; t1 = *yp (yp 在 %rsi)
movq %rdx, (%rdi) ; *xp = t1
movq %rax, (%rsi) ; *yp = t0
ret
执行轨迹:
- 初始:%rdi=0x120 (存 123), %rsi=0x100 (存 456)
- 执行后:0x120 变为 456,0x100 变为 123
8.2 数组寻址
假设 long long array[8] 地址在 %rdx 中,索引 4 在 %rcx 中。 目标:把array[4]的值存入 %rax
movq (%rdx, %rcx, 8), %rax
# 1. 计算地址 %rdx + 4*8
# 2. 从该内存地址搬运 8 字节到 %rax
九、总结与展望
本文从主存的矩阵实现出发,系统梳理了 x86-64 架构下的:
2
64
2^{64}
264 字节地址空间,字节级寻址
理解这些底层机制,是后续学习算术逻辑指令、控制流、过程调用以及存储器层次结构的坚实基础。主存不仅是数据的容器,更是 CPU 与软件交互的核心界面,掌握其工作原理,才能真正理解计算机系统的全貌。
参考资源
- 《Computer Organization》课程笔记
- 《深入理解计算机系统》(CS:APP)第 3 章
- Intel 64 and IA-32 Architectures Software Developer’s Manual
延伸阅读与互动
本文内容已同步收录至我的个人技术站及 GitHub 开源项目。相比于 CSDN,个人站点拥有更完美的 LaTeX 公式和表格渲染与交互式代码体验,欢迎访问:
-
🚀 本文高清版:https://www.chenxu.online/blog/computer_organization1/(体验最佳)
-
🏠 个人站点:https://www.chenxu.online/(查看更多 CS:APP 学习笔记)
-
📂 GitHub 项目:my-blog (欢迎 Star 关注)
本文最后更新于:2026-02-27



