我们知道C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。栈帧也叫过程活动记录,是编译器用来实现函数调用的一种数据结构那么在Linux下gcc编译器栈帧是怎么实现的呢?

首先来看下面这段代码:

wKiom1ddGMDwiT8YAAKcnHRhemA515.png

      这段代码的运行结果是会导致虚拟机重启。通过代码可以看到我们在fun函数中写了让系统重启的代码然而我们在main函数中并没有调用fun函数,却仍旧导致了系统重启。

      首先要我们知道栈是从高地址向低地址生长的,每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。由此我们来用图的方式说明这个问题。

wKiom1ddJWyRkWpNAAFKwI1WrA8083.png-wh_50

fun1中p是形参a的地址,p--之后p则成了fun1运行后的下一条指令的地址,但是fun1中将*p=fun这句代码使得下一条指令的地址变成了fun的地址因此在main函数没有调用fun的的情况下执行了fun函数。

再来看下这个代码:

wKioL1ddKyOjQO0eAACIiaFW8uc165.png

 容易知道a先压栈,b后压栈。 压栈时,栈顶由高地址向低地址方向前进,因此,结果为:

变量a的地址 0xbfa92d88

变量b的地址 0xbfa92d84