add README.md and update L07 note

This commit is contained in:
2026-04-09 15:52:30 +08:00
parent e81f36b247
commit 6b2fc2c7f0
2 changed files with 18 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
# Lecture 07 Procedures 函数的调用
# Lecture 07 Procedures 过程 \(函数的调用\)
## Mechanisms 机制 / 目录
@@ -8,7 +8,7 @@
- [Passing Data 传递数据](#passing-data-传递数据)
- [传入参数](#传入参数)
- [返回值](#返回值)
- [Managing Local Data 管理其他变量](#managing-local-data-管理其他变量)
- [Managing Local Data 管理其他变量与内存](#managing-local-data-管理其他变量与内存)
- [Stack Frame 栈帧](#stack-frame-栈帧)
- [Recursion 递归](#recursion-递归)
- [`ret` 指令](#ret-指令)
@@ -97,20 +97,29 @@
返回值一般使用```%rax```进行传递。
## Managing Local Data 管理其他变量
## Managing Local Data 管理其他变量与内存
### Stack Frame 栈帧
一般情况下,由于诸多与函数相关的特点,我们会在栈上分配一些内存给局部变量。加上其他要分配的内存[^extra-mmr-allocate],这部分被称作“栈帧”。
有时,我们会在栈上分配一些内存给局部变量。常见情况比如:
- 寄存器不够存放所有的局部变量
- 某些局部变量是个Array或者Struct
- 对一个局部变量取地址(&),需要它在内存中有一个固定的地址
加上其他要分配的内存[^extra-mmr-allocate],这部分被称作“栈帧”。
| 函数特点 | 栈特点 |
| ---------- | ---------- |
| 返回后,函数内分配的局部变量被丢弃 | 更改```rsp```指针即可丢弃数据 |
| 函数内可能会调用其他函数 | 直接将返回地址压栈 |
| 单线程调用其他函数时,原函数停止继续运行 | 保存原函数 的帧指针,在其之上可直接建立新栈帧 |
| 原函数的数据保持不变 | 新分配一个栈即可避免数据被覆盖 |
[^extra-mmr-allocate]: 上一个函数的寄存器内容、Windows下的影子空间、返回地址等等内容。
需要注意的是在C语言中struct、union这种“庞大”的数据类型也会被留在栈上。如果处理不当很可能Stack Overflow。因此在处理大型数据结构时通常建议使用动态内存分配如malloc来避免栈空间的过度使用并使用free来手动释放。
### Recursion 递归
由于“栈帧”的特性,它很适合用来做递归。系统会为每一层递归单独分配内存空间,彼此之间不会因为相同的代码导致变量的地址也相同(使用```%rbp + 数```管理)。