c语言深度理解(函数栈帧与可变参数列表)
作者:互联网
文章目录
函数栈帧
(来自比特蛋哥的c语言深度解析的课堂板出)
ebp:栈底寄存器
esp:栈顶寄存器
eip:指令寄存器,用来存储下一条要执行的语句
ebp指向的是一个函数栈帧的栈底,栈区使用空间是从高地址向低地址使用。刚开始时,在ebp-8的地址处放入A值,ebp-14的位置放入B值,这是初始化x,y变量。
之后把ebp-14地址处的变量放进eax寄存器中,eax寄存器再压栈,此时esp作为栈顶寄存器,它的值变小。再把y的数据压栈。call指令有两个作用,1是压入返回值地址,2是跳转到目标函数。Add函数的下一条指令的地址会压入栈帧中。
eip存储要跳转的地址,跳转到指定地址处。
该地址处的指令也是跳转到一个地址处。
最终跳转到了存储Add函数的代码处。
先将ebp压栈,将ebp的地址存储。mov将esp的地址存储到ebp中,说明ebp这时指向原来的栈顶。sub将esp的地址减少CC,esp就向低地址处移动CC个字节。(具体移动的字节数,编译器会根据函数的大小移动,sizeof在编译期间就能算出变量的字节数,编译器通过统计一个函数内有多少变量,将esp移动)
ebp+8拿到形参a的数据,ebp+c拿到b的数据,将它们相加得到的值存储到c中。最后返回时是将c的值存储到一个寄存器中,所以当函数栈帧销毁时,局部变量虽然销毁但它的值保存在了寄存器中,最后能成功返回。
mov将ebp的地址传给esp,这时的esp指向的是Add函数的栈底,pop是将之前压入main函数栈底地址传给ebp。ret类似pop eip的指令,这时的esp是之前main函数的栈顶,接着存储的是call指令压入的下一条指令的地址,将该地址传入eip,完成函数的返回。
将esp+8释放之前压入的形参
总结
1.调用函数形成临时变量的参数是从右向左形成的
2.每个函数对应开辟一块临时空间
3.函数调用完成,该临时空间释放
4.反应了局部变量具有临时性的本质(栈帧具有临时性)
5.函数的调用是有成本的(形成释放栈帧有时间)
标签:函数,esp,寄存器,列表,地址,ebp,可变,栈帧 来源: https://blog.csdn.net/weixin_61432764/article/details/123022088