函数调用栈帧
00:00
C语言函数调用栈帧详解:局部变量、返回地址、寄存器保存。
1. 栈帧结构
高地址
┌─────────────────┐
│ 参数 n │
│ ... │
│ 参数 1 │
│ 返回地址 │ ← 调用前的栈顶
├─────────────────┤
│ 保存的 EBP │ ← 当前 EBP
├─────────────────┤
│ 局部变量 1 │
│ 局部变量 2 │
│ ... │
├─────────────────┤
│ 临时空间 │ ← ESP
└─────────────────┘
低地址
2. 调用过程
; 调用前
push arg2 ; 参数从右到左入栈
push arg1
call func ; push 返回地址,jmp func
; func 入口
push ebp ; 保存旧 EBP
mov ebp, esp ; 设置新 EBP
sub esp, N ; 分配局部变量空间
; func 退出
mov esp, ebp ; 释放局部变量
pop ebp ; 恢复 EBP
ret ; pop 返回地址,jmp 回去
3. 调用约定
| 约定 | 参数传递 | 栈清理 | 名称修饰 |
|---|---|---|---|
| cdecl | 从右到左入栈 | 调用者 | _func |
| stdcall | 从右到左入栈 | 被调用者 | _func@N |
| fastcall | ECX, EDX + 栈 | 被调用者 | @func@N |
4. 栈溢出
void recursive() {
char buffer[1024]; // 每次分配 1KB
recursive(); // 无限递归 → 栈溢出
}
栈大小通常为 1-8MB,超出即崩溃。