Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

栈帧

复习

  • 调用约定:函数之间如何传参与返回
  • 栈:后进先出
  • 寄存器着色与溢出:部分值要放到内存

TL;DR

  • 栈帧是函数调用时在栈上开辟的一块空间
  • 它保存局部变量、被保护的寄存器、返回地址等
  • 每次调用压入一个栈帧,返回时弹出
  • 溢出到内存的变量,也放在栈帧里

正文

  函数调用时,需要一块地方来安置“这次调用特有的东西”。这块空间,就是栈帧(stack frame)。它建在栈上,正好契合函数调用的“嵌套”特性。

一帧里装什么

  一个栈帧通常包含:

  • 返回地址:函数执行完,该回到调用处的哪里
  • 保存的寄存器:按调用约定,被调函数要保护的寄存器旧值
  • 局部变量:这个函数自己的局部数据
  • 溢出的值:放不进寄存器、只能暂存内存的那些变量

  所以,栈帧不仅装“数据”,还装“回来的路”和“现场的备份”。

调用压入,返回弹出

  栈帧和函数调用是同步的:

  • 调用一个函数:为它压入一个新的栈帧
  • 函数执行:用的是自己这一帧里的数据
  • 返回:弹出这一帧,控制权交还调用者,调用者继续用它的帧

  因为函数调用是“一层套一层”的,栈帧也一层压一层——这正好是(后进先出)的用武之地。一个函数调用了另一个,新帧就压在旧帧上面;后者返回,就把它弹掉。

和前面的呼应

  栈帧把前面好几个概念串了起来:

  • 它体现调用约定(谁保存哪些寄存器)
  • 它是函数调用运行栈在机器层面的具体样子
  • 它收留溢出的值

  到这里,“值放在哪”这件事就彻底落实了:能放寄存器的放寄存器,放不下的放栈帧。位置都定了,就可以真正动手写汇编了。

思考题 1

  栈帧里通常保存哪些东西?

思考题 2

  栈帧和函数调用的“嵌套”有什么关系?

小结

知识点

  • 栈帧是函数调用时在栈上开辟的空间
  • 内含返回地址、保存的寄存器、局部变量、溢出的值
  • 调用时压入,返回时弹出
  • 栈帧契合函数调用的嵌套结构

参考资料

  1. Wikipedia(zh):调用栈:函数调用信息的栈式存储
  2. Wikipedia(zh):栈帧:一次函数调用占用的栈空间

思考题答案(仅供参考)

思考题 1

  通常包括:返回地址、按约定需要保护的寄存器旧值、函数的局部变量,以及无法放进寄存器、被溢出到内存的那些值。

思考题 2

  函数调用是一层套一层的:调用一个函数会压入一个新栈帧,返回时再弹出。这种“后进先出”的嵌套关系正好对应栈结构,所以栈帧用栈来组织最自然。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪