内存栈区上保存的是什么?
大家好,我是小风哥,今天简单聊聊函数的调用栈保存的内容。
假设有三个函数,函数1调用函数2,函数2调用函数3。
函数在运行时同样有很多与之相关的信息需要记录下来,因此每个函数被执行时都会有属于自己的一块内存,这三块内存被称之为栈帧:
这些栈帧组成了栈区。

这些栈帧会因为函数的调用以及返回形成一个先进后出的结构,也因此这些栈区组成的内存区域被称之为栈区。那么我们怎么知道栈帧的内存范围呢?这通过CPU中esp和ebp这两个寄存器来界定的。

ebp被称之为栈帧寄存器,指向栈底部,esp被称之为栈寄存器,指向栈顶。其中栈寄存器esp是可以上下移动的,esp下移就是分配更多栈空间,esp上移就是释放栈空间。假设此时我们将进行函数调用,函数调用的第一件事就是把返回地址保存在栈上:
这样当被调函数运行完毕后CPU就知道该从哪里继续执行指令了。
红线这里将是上一个栈帧的末尾,此后我们将来到新的栈帧,也就是被调函数的栈帧。此时CPU正式跳转到被调函数,来到被调函数的第一件事就是保存栈帧寄存器ebp,以便被调函数运行完毕后恢复调用函数的栈帧

此时ebp会被保存在被调函数的栈帧中,并把esp的值赋值给ebp,这样esp和ebp就指向了新的栈帧,也就是被调函数的栈帧。
接着,如果有必要则把部分寄存器的值保存在栈上。
为什么会有这一步呢,因为CPU中的寄存器是可以被所有函数共享的,而寄存器数量有限,调用栈上可能有n多函数,这就是10个壶八个盖的游戏:
当函数A调用函数B时我们必须确保函数B不能破坏函数A要用的寄存器,所以函数B在运行时会保存部分寄存器的值,当函数B执行完毕后再根据栈上的信息恢复寄存器。除了寄存器,接下来是局部变量,也就是这里的y和z。

局部变量当然可以放在寄存器中,但由于寄存器数量有限,因此部分局部变量也会被放到栈上。如果被调函数也调用了其它函数,那么会把调用其它函数的参数放到栈上,这部分就会被放到栈上。

最后,同样会把返回地址保存在栈上,方便CPU继续执行被调函数之后的指令。
可以看到,一个函数的栈帧保存的信息大体分为这么几类:寄存器、局部变量、函数参数以及返回地址。好啦,本文就到这里,希望对大家理解函数调用栈有所帮助。





