CMU 15-213 Intro to Computer Systems Lecture 7
课程主页:http://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/schedule.html
课程资料:https://github.com/EugeneLiu/translationCSAPP
课程视频:https://www.bilibili.com/video/av31289365/
这一讲介绍了机器级编程3:过程。
栈结构
x86-64栈
- 通过栈规范管理内存区域
- 栈顶在低地址
- 寄存器%rsp为最小的堆栈地址
- 即“顶部”元素的地址
Push
- pushq Src
- 将%rsp减少8
- 在给定的地址%rsp处写入操作数
Pop
- popq Dest
- 在%rsp指定的地址处读取值
- 将%rsp增加8
- 将值存储在Dest(必须是寄存器)
调用约定
传递控制
例子
考虑如下代码
void multstore
(long x, long y, long *dest) {
long t = mult2(x, y);
*dest = t;
}
0000000000400540 <multstore>:
# x in %rdi, y in %rsi, dest in %rdx
400540: push %rbx # Save %rbx
400541: mov %rdx,%rbx # Save dest
400544: callq 400550 <mult2> # mult2(x,y)
# t in %rax
400549: mov %rax,(%rbx) # Save at dest
40054c: pop %rbx # Restore %rbx
40054d: retq # Return
long mult2
(long a, long b)
{
long s = a * b;
return s;
}
0000000000400550 <mult2>:
# a in %rdi, b in %rsi
400550: mov %rdi,%rax # a
400553: imul %rsi,%rax # a * b
# s in %rax
400557: retq # Return
过程控制流
- 使用栈来支持过程调用和返回
- 程序调用:call label
- 将返回地址推入堆栈
- 跳转到标签
- 返回地址:
- call之后下一条指令的地址
- 程序返回:ret
- 从栈中的弹出地址
- 跳转到地址
传递数据
过程数据流
6个以内的参数通过寄存器传递,6个以上的部分存储在栈中,返回值在%rax中。
管理局部数据
- 支持递归的语言
- 例如C,Pascal,Java
- 代码必须为“Reentrant”
- 单个过程的多个同时实例化
- 需要一些地方来存储每个实例的状态
- 参数
- 局部变量
- 返回指针
- 栈规则
- 在有限的时间内说明给定程序所需的状态
- 从call到return的时间
- callee先于回caller返回
- 在有限的时间内说明给定程序所需的状态
- 栈被分配在栈帧(Stack Frames)
- 单过程实例化的状态
栈帧
- 内容
- 返回信息
- 本地存储(如果需要)
- 临时空间(如果需要)
- 管理
- 进入过程时分配空间
- “Set-up”代码
- 包括call指令
- 返回时取消分配
- “Finish”代码
- 包括ret指令
- 进入过程时分配空间
x86-64/Linux栈帧
- 当前栈帧(“顶部”至底部)
- Argument build:要调用的函数的参数
- Local Variables(如果没法存储在寄存器中)
- Saved Registers
- Old frame pointer(可选)
- Caller栈帧
- Return address
- 由call指令推送
- 此次call的参数
- Return address
寄存器保存约定
- 当过程yoo call who:
- yoo是caller
- who是callee
- 可以将寄存器用于临时存储吗?
- 约定
- “Caller Saved”
- caller在call之前将临时值保存在其帧中
- “Callee Saved”
- callee在使用前将临时值保存在其帧中
- callee在返回到caller前将这些值恢复
- “Caller Saved”
x86-64/Linux寄存器用处
- %rax
- 返回值
- 也是caller-saved
- 可以通过过程修改
- %rdi,…,%r9
- 参数
- caller-saved
- 可以通过过程修改
- %r10,%r11
- caller-saved
- 可以通过过程修改
- %rbx,%r12,%r13,%r14
- callee-saved
- callee必须保存并还原
- %rbp
- callee-saved
- callee必须保存并还原
- 可用作帧指针
- 可以混合搭配
- %rsp
- 特殊形式的callee-saved
- 退出程序后恢复到原始值
递归过程
- 无需特殊考虑即可处理
- 栈帧意味着每个函数调用都有专用存储
- 保存的寄存器和局部变量
- 保存的返回指针
- 寄存器保存约定可防止一个函数调用破坏另一个数据
- 除非C代码明确这样做(例如,第9课中的缓冲区溢出)
- 堆栈规则遵循调用/返回模式
- 如果P呼叫Q,则Q在P之前返回
- 后进先出
- 栈帧意味着每个函数调用都有专用存储
- 也适用于相互递归
- P call Q; Qcall P
x86-64过程总结
- 重要事项
- 栈是使得过程调用/返回正确的数据结构
- 如果P call Q,则Q在P之前返回
- 递归(和相互递归)由正常调用机制处理
- 可以安全地将值存储在本地栈帧和被调用者保存的寄存器中
- 将函数参数放在栈顶
- 结果返回%rax
- 指针是值的地址
- 在栈上或全局
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere