FP+偏移、局部变量用 FP−偏移 访问。| 项目 | 值 |
|---|---|
| 对应高级语言 | 函数调用 / 过程调用 |
| 核心机制 | 栈帧(Stack Frame)管理 |
| 关键指令 | CALL(调用)和 RET(返回) |
| 调用步骤 | 传参 → 保存返回地址 → 跳转 → 建立栈帧 → 执行 → 恢复 → 返回 |
过程调用(函数调用)在机器级通过栈帧机制实现。每次调用在栈上分配一个栈帧,用于存储局部变量、参数、返回地址和保存的寄存器。
CALL 指令自动将下一条指令地址(返回地址)压栈push ebp),设置新的帧指针(mov ebp, esp),分配局部变量空间(sub esp, N)RET 指令从栈中弹出返回地址到 PC[参数2] ← ebp + 12
[参数1] ← ebp + 8
[返回地址] ← ebp + 4
[旧的ebp] ← ebp (帧指针)
[局部变量1] ← ebp - 4
[局部变量2] ← ebp - 8
[保存的寄存器] ← esp (栈指针)
ebp 为分界线:正偏移取参数、负偏移取局部变量;返回地址永远紧贴在旧 ebp 的高地址侧(ebp+4)。| 组件 | 作用 | 说明 |
|---|---|---|
| PC(程序计数器) | 存储下一条指令地址 | CALL 修改 PC 为被调过程地址 |
| SP(栈指针) | 指向栈顶 | 压栈时 SP 减小,弹栈时 SP 增大 |
| FP/BP(帧指针) | 指向当前栈帧的基址 | 用于访问局部变量和参数 |
| CALL 指令 | 压入返回地址 + 跳转 | 等价于 PUSH 返回地址 + JMP 目标 |
| RET 指令 | 弹出返回地址 + 跳转 | 等价于 POP PC |
| 调用约定 | 参数传递 | 栈清理 |
|---|---|---|
| cdecl(C 默认) | 参数从右到左压栈 | 调用者清理 |
| stdcall(Win API) | 参数从右到左压栈 | 被调者清理 |
| 寄存器传参 | 前几个参数放寄存器 | — |
| 考法 | 解题套路 |
|---|---|
| 分析栈帧布局 | 画出栈帧结构图,标出各部分的地址偏移 |
| CALL/RET 的等价操作 | $CALL = $ push 返回地址 $+$ JMP;$RET = $ pop PC |
| 给定汇编还原函数调用 | 找 CALL 和 RET,识别参数传递和返回值 |
| 栈的增长方向 | x86 中栈向低地址增长(push 使 SP 减小) |
| 调用嵌套的栈状态 | 逐层画出栈帧的压入过程 |
EAX/RAX 寄存器中,不在栈上。ebx, esi, edi, ebp)由被调过程保存;caller-saved 寄存器(如 eax, ecx, edx)由调用者保存。EAX 传递。↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。