文章目录
- 线索栏
- 笔记栏
-
- 1. exchange函数分析 (图3-7)
-
- 1)C代码
- 2)汇编代码与解读
- 3)揭示的两个关键事实
- 2. 栈的概念与指令
-
- 1)栈
- 2)栈指针 %rsp
- 3)pushq S指令(将四字S压入栈)
- 4)popq D指令(从栈弹出一个四字到D)
- 3. 等效操作与优化
- 3. 栈的访问
- 4.练习题
-
- 练习题3.4
- 练习题3.5
- 总结栏
线索栏
笔记栏
1. exchange函数分析 (图3-7)

1)C代码
long exchange(long *xp, long y) { long x = *xp; *xp = y; return x; }
2)汇编代码与解读
// xp in %rdi, y in %rsi
movq (%rdi), %rax // 1. 从内存(%rdi指向的地址)读取值到%rax。对应: long x = *xp;
movq %rsi, (%rdi) // 2. 将%rsi的值写入内存(%rdi指向的地址)。对应: *xp = y;
ret // 3. 返回,返回值在%rax (即x)
3)揭示的两个关键事实
(1)C指针即地址:指针变量(xp)本身存储在寄存器中(%rdi)。对指针解引用(*xp)在汇编中体现为以该寄存器值为地址的内存访问((%rdi))。 (2)局部变量常驻寄存器:局部变量 x并未存入栈内存,而是直接保留在寄存器 %rax中。这优化了访问速度。
2. 栈的概念与指令
1)栈
一种后进先出(LIFO)的数据结构,在内存中实现,用于支持过程调用。栈顶是最近插入的元素,地址最低。
2)栈指针 %rsp
始终保存栈顶元素的内存地址。
3)pushq S指令(将四字S压入栈)
(1)%rsp ← %rsp – 8(栈指针减8,栈向低地址方向增长) (2)M[%rsp] ← S(将源操作数S的值写入新的栈顶地址)
4)popq D指令(从栈弹出一个四字到D)
(1)D ← M[%rsp](从当前栈顶地址读取值到目的操作数D) (2)%rsp ← %rsp + 8(栈指针加8)
3. 等效操作与优化
(1)pushq %rbp功能上等价于:
subq $8, %rsp // 1. 递减栈指针
movq %rbp, (%rsp) // 2. 存储值
(2)popq %rax功能上等价于
movq (%rsp), %rax // 1. 读取值
addq $8, %rsp // 2. 递增栈指针
(3)为什么用单独指令 pushq和 popq的机器码更短(1字节 vs 多条指令合计8字节),且是通用指令,硬件可能优化其执行。
3. 栈的访问
程序可以用标准内存寻址访问栈内任何位置。例如,movq 8(%rsp), %rdx将栈顶下方(地址更高处)的第二个四字复制到 %rdx。
4.练习题
练习题3.4

练习题3.5

decode1:
movq (%rdi), %r8 // t1 = *xp
movq (%rsi), %rcx // t2 = *yp
movq (%rdx), %rax // t3 = *zp
movq %r8, (%rsi) // *yp = t1
movq %rcx, (%rdx) // *zp = t2
movq %rax, (%rdi) // *xp = t3
ret
void decode1(long *xp, long *yp, long *zp) {
long t1 = *xp;
long t2 = *yp;
long t3 = *zp;
*yp = t1;
*zp = t2;
*xp = t3;
}

总结栏
本节通过具体示例和练习,深化了对数据传送指令的理解,并引入了程序栈这一关键数据结构。
栈的引入为下一节“算术和逻辑操作”以及更重要的“控制”和“过程”章节铺平了道路。理解栈是理解函数调用、局部变量存储和程序控制流管理的关键。

