栈帧构建与平衡堆栈
一. 什么是栈帧
在汇编语言当中每调用一个函数后为其构建一个对应的栈帧,用于存储改函数当中的局部变量以及参数,栈帧是一个栈的结构,ebp指针指向该栈帧的底部即栈底,esp指针指向该栈帧顶部即栈顶,在上而下地址数值不断增加。由于栈空间是有限的,倘若不断增加栈中元素,会导致栈溢出等错误,所以需要在每一次结束函数调用后将堆栈平衡。
二. 栈帧构建
在理解栈帧构建的过程前,我们需要先理解一下在汇编语言当中函数调用的过程。
- 传递参数,不同的函数调用规范下函数传参的方式不同。在这里我们以cdecl调用规范为例:函数自右向左传递参数,通过栈传递并且由调用者负责清理堆栈。
- 通过call指令调用函数跳转到对应函数地址。
- 保留调用函数信息,构建被调用函数栈帧。
- 函数执行。
- 寄存器信息恢复,使用retn跳转到调用函数区域。
- 平衡堆栈。
清楚了这个过程后,我们可以看到其实栈帧的关键就在于栈中元素的位置以及对元素的操作。
按照整个函数调用过程,我们分析一下栈的变化。
push eax;//传入参数二
push edx;//传入参数一
call sub_401045;//函数调用
add esp 8h;//调用函数平衡堆栈
sub_401045:
push ebp;//保留调用函数ebp
mov ebp,esp;//创建被调用函数堆栈
sub esp,8h;//为局部变量开辟空间
...
...
...
pop ebp;//恢复调用函数ebp
retn;//返回调用函数
这里是cdecl调用规范所以是通过调用函数平衡堆栈。
整个栈的变化流程如图。