
在程序执行过程中函数调用是最基本的控制流转移方式。每一次函数调用都会涉及到栈帧的创建与切换这是计算机组成原理中与体系结构密切相关的重要概念。本文将简要介绍栈帧的结构以及切换过程。一、什么是栈帧栈帧Stack Frame也叫过程活动记录Procedure Activation Record是函数调用时在栈上分配的一块内存区域。每个栈帧保存了该函数执行所需的全部信息包括函数的局部变量函数参数在部分调用约定中返回地址调用结束后应跳转的位置保存的被调用者保存寄存器Callee-saved Registers帧指针Frame Pointer即旧 EBP/RBP典型的栈帧结构如下表所示以 x86 为例地址从高到低栈帧区域内容说明函数参数调用者压入的实参由调用方负责压栈返回地址call 指令自动压入ret 指令弹出并跳转旧帧指针上一个函数的 EBP用于恢复调用者栈帧局部变量函数内部定义的变量按声明顺序分配空间保存寄存器被调用者保存的寄存器函数返回前恢复二、栈帧切换的过程栈帧切换发生在函数调用call和函数返回ret时。整个过程由 CPU 硬件和编译器生成的指令共同完成。2.1 函数调用时创建新栈帧调用者将参数按调用约定压入栈中执行 call 指令CPU 自动将返回地址压栈并跳转到目标函数被调用函数的序言Prologuepush ebp; mov ebp, esp; sub esp, N —— 保存旧帧指针建立新帧指针为局部变量分配空间2.2 函数返回时销毁当前栈帧被调用函数的尾声Epilogue将返回值存入 EAXmov esp, ebp; pop ebp —— 释放局部变量空间恢复调用者的帧指针执行 ret 指令CPU 弹出返回地址并跳转回去调用者清理栈上的参数在 cdecl 等调用约定中由调用者负责栈帧切换中涉及的关键寄存器寄存器作用切换时的变化ESP栈顶指针指向栈最顶端的地址sub esp, N 分配空间mov esp, ebp 释放空间EBP帧指针基址指针指向当前栈帧底部push ebp 保存旧值mov ebp, esp 建立新帧EIP指令指针指向下一条待执行指令call 压入当前 EIPret 弹出并恢复 EIPEAX累加器用于存放函数返回值被调用函数在返回前将结果写入 EAX三、总结栈帧切换的本质是通过 ESP 和 EBP 两个指针的配合在内存栈上为每个函数划分独立的运行空间。call/ret 指令由硬件自动完成返回地址的压栈和弹栈而帧指针的保存与恢复则由编译器生成的序言和尾声代码完成。理解栈帧切换对于调试、逆向工程以及深入理解计算机体系结构都具有重要意义。