函数的调用和返回使栈的增长和收缩成线性。大部分的Unix/Linux中,栈驻留在内存的高端并向下增长(超堆的方向)。专用寄存器------栈指针(stack pointer),用于跟踪当前栈顶。每次调用函数时,会在栈上新分配一帧,每当函数返回时,再从栈上将此帧移去。
- 虽然栈向下增长,但是仍将栈的增长段称为栈顶,因为抽象说来,情况本就如此。栈的实际增长方式是个(属于硬件范围的)实现细节。在 HP PA-RISC 的 Linux 实现中,栈的增长方向就是向上的
- 就虚拟内存而言,分配栈帧后,栈段的大小将会增长。但大多数Linux中,释放这些栈帧后,栈的大小并未减少(在分配新的栈帧时,会对这些内存加以重新利用)。当讨论栈的增长和收缩时,只是从逻辑视觉来看栈帧在栈中的增减情况。
有时,会用用户栈(user stack)来表示此处所讨论的栈,以便与内核栈区分开来。内核栈是每个进程保留在内核内存中的内存区域,在执行系统调用的过程中供(内核)内部函数调用使用。(由于用户栈驻留在不受保护的用户内存中,所以内核无法利用用户栈来达成这一目的。
每个用户栈帧中包括如下信息:
- 函数实参和局部变量:由于这些变量都是在调用函数时自动创建的,因此在C语言中称其为自动变量。函数返回时将自动销毁这些变量(因为栈帧会被释放),这也是自动变量与静态变量、全局变量主要的语义区别:后者与函数执行无关,且长期存在
- (函数)调用的链接信息:每个函数都会用到一些 CPU 寄存器,比如程序计数器,其指向下一条将要执行的机器语言指令。每当一函数调用另一函数时,会在被调用函数的栈帧中保存这些寄存器的副本,以便函数返回时能为函数调用者将寄存器恢复原状。
因为函数能够嵌套调用,所以栈中可能有多个栈帧。(若一函数递归调用自身,则该函数在栈中将有多
个栈帧)