深入理解栈帧:从基础概念到高级应用
1. 栈帧基础
栈通常被简单定义为支持压入(push)和弹出(pop)操作的数据结构。然而,局部变量往往是批量压入(函数进入时)和批量弹出(函数退出时)的,而且创建时不一定立即初始化,并且在大量变量压入后,还需要访问栈深处的变量,因此抽象的压入弹出模型并不适用。
我们将栈视为一个大数组,通过一个特殊的寄存器——栈指针(stack pointer)来指向某个位置。栈指针之后的位置被视为垃圾,之前的位置被视为已分配。栈通常只在函数进入时增长,增长量足以容纳该函数的所有局部变量,函数退出前则收缩相同的量。栈上用于存储函数的局部变量、参数、返回地址和其他临时数据的区域称为函数的激活记录或栈帧。由于历史原因,运行时栈通常从高内存地址开始,向低地址增长,就像冰柱一样,栈向下增长,向上收缩。
栈帧布局的设计需要考虑指令集架构和所编译的编程语言的特定特性。计算机制造商通常会规定一种“标准”的栈帧布局,以便所有编程语言的编译器在该架构上尽可能使用。虽然这种布局可能对某些编程语言或编译器不是最方便的,但使用“标准”布局可以让不同语言编写的函数相互调用。
下面是一个典型的栈帧布局:
↑higher addresses
argument n
.
incoming
.
previous
arguments
.
frame
argument 2
argument 1
frame pointer →
static link
local
variables
return address
temporaries
current
saved
frame
registers