函数调用过程解析——函数栈帧的创建和销毁

本文探讨了在VS2013环境下,函数调用时栈帧的创建、销毁以及参数传递的过程。讲解了局部变量的创建(在栈帧中分配空间)、初始值可能为随机的原因。阐述了函数传参是从右向左压栈,形参是实参的副本,改变形参不影响实参。同时,介绍了函数调用时的返回机制,包括如何保存返回地址和如何通过寄存器带回返回值。强调了ebp和esp寄存器在维护栈帧中的作用,以及静态变量的存储位置。
摘要由CSDN通过智能技术生成

提示:

1、这里使用的环境是VS2013,不高级的编译器容易学习和观察。

2、在不同的编译器下函数调用过程中栈帧的创建和销毁时略有差异的,具体细节取决于编译器的实现。


讲栈帧——先看寄存器

寄存器有eax,ebx,ecx,edx,ebp,esp。

其中ebp,esp这两个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的。这两个寄存器看成指针。

每一个函数调用都要在栈区创建一个空间。

压栈:给栈低放一个元素——push 

出栈:从栈顶删除一个元素——pop

在还没有调用Add函数的时候就已经把参数a、b传过去了,先传的是b,后传的是a。(从左向右传参),所以参数先进入栈区压栈,等真正进入函数内部后,用x和y相加的时候是找回了之前压栈的这两个参数,计算和后放到z中。

①局部变量是怎么创建的?

答:首先为函数分配好栈帧空间,栈帧空间里初始化一部分函数之后然后给局部变量栈帧里面分配空间。

②为什么局部变量的值是随机值?

答:因为随机值是随机放进去的。如果给局部变量初始化就把随机值覆盖了。

③函数是怎么传参的?传参的顺序是怎样的?

答:当调用函数的时候,在还没调用的时候就已经push把参数从右向左开始压栈压进去,当真正进入函数的形参时,其实在Add函数栈帧里通过指针的偏移量找回形参。

④形参和实参是什么关系?

答:形参是函数压栈开辟的空间,它和形参在值上是相同的,空间是独立的,所以形参是实参的临时拷贝,改变形参不会影响实参。

⑤函数调用是怎么做的?函数调用是结束后怎么返回的?

答:在函数调用之前就已经把call指令下一条的地址记住了(存储——压进去),把ebp调用这个函数的上一个函数的栈帧的ebp就存进去了,当函数调用完要返回的时候,弹出ebp就能找到原始上一个函数调用的ebp了,然后指针往下走的时候就能找到esp的地址回到栈帧空间,因为记住了call指令下一条的地址,往回返的时候就可以跳转到call指针的下一条地址让函数调用返回值可以返回。返回值是怎么带回来的呢?是通过寄存器的方式带回来的。

注意函数调用的返回值是放到寄存器中了不会销毁。

函数内部创建的静态变量是在全局开辟的。
ebp不是数据结构里的头指针,与它没什么关系。ebp就是个寄存器,它是用来记录当前调用函数栈帧的栈低的位置的地址。ebp是寄存器,pop ebp的意思是栈顶上的元素弹出来放到ebp中。

在栈区给每个函数开辟的空间是不一样的,不确定。

寄存器不在main()函数里,寄存器不是内存中的,是独立于内存的,是集成到CPU上的。电脑上的存储有硬盘,内存,寄存器,这些都是完全独立的,不同的空间。

ebp和esp是存放地址的,这个地址是用来维护栈帧的,ebo和esp里村的是这个栈空间的维护当前函数调用所使用栈空间的栈低和栈顶的,ebp指向栈低esp指向栈顶,ebp和esp没函数的地址没有关联。
形参的创建的空间在main函数和调用函数之间。函数的形参不在该函数的栈帧里面,可以理解为放在main函数栈帧里,相当于main函数栈帧的拓宽。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值