栈帧 stack frame
每一次函数调用都会维护一个栈帧(stack frame),栈帧主要用于传递参数、保存返回地址、保存局部变量等。先直接上一个《深入理解计算机系统》上的原图。
其中,%rsp 指向栈顶位置,%rbp 指向栈底位置。并且栈是由高地址向地址方向增长。
局部变量的布局是由编译器决定的,可能是由个高地址到低地址,也可能由低地址到高地址。
被调函数的前6个参数将由寄存器传入,超过6个的部分将通过栈传入。这里需要注意的是,在被调函数中为了能够对入参进行取地址,被调函数将会将前6个参数压入被调函数的栈中。
函数调用过程:
- 参数入栈。将参数按照一定的顺序将超过6个后的参数入栈。
- 返回地址入栈。将当前代码的一条指令地址压入栈中,函数返回时继续执行。
- 跳入被调函数地址。
- EBP入栈,保存当前栈帧状态值。
- ESP值赋给EBP。
- 分配当前栈帧。
函数返回过程:
- 保存被调用函数的返回值到 EAX 寄存器中。
- 恢复 ESP。
- 将被调函数底部保存的调用函数栈帧EBP值弹入EBP寄存器,恢复调用函数栈帧。
- 弹出当前栈顶元素,从栈中取到返回地址。
下面以一个例子来验证下栈帧布局:
先进入 main 函数的 func 函数调用点:
%rbp 值为 0x7fffffffe110,%rsp 的值为 0x7fffffffe0f0。在根据反汇编可以得到下一条指令的地址为 0x4008f4。根据这些信息我们可以推出 main 函数和 func 函数的栈帧如下:
以上栈帧信息可以dgb调试时候打印验证:
参考:
- 深入理解计算机系统