详解函数栈帧的销毁

6 篇文章 0 订阅
2 篇文章 0 订阅

大家好,我是情谊,在新的一年里,我祝大家龙年大吉,幸福安康。

回顾上一周,我们讨论到了函数栈帧的创建,知道了创建变量时函数栈帧的变化,那么今天,我们来介绍一下函数栈帧的销毁。

上周我们使用是一个简单的代码,我们知道函数栈帧的创建是由esp和ebp进行维护的,当这两个指针指向哪里,那我们就正在维护哪一个函数,我们也知道函数栈帧的创建都是差不多的,那么我们今天讨论在Add函数和main函数的栈帧都创建好的情况下如何销毁栈帧。

首先,我们先看看Add函数的反汇编语言,由于前面我在上一篇文章中已经讲到过函数栈帧的创建,今天我们从int z = 0开始。

  004EBF6E  mov     eax,dword ptr [ebp + 8]  这一句是将ptr [ebp + 8]位置的值传给eax,4EBF71  add         eax,dword ptr [ebp + 0ch] 则是将eax和ptr [ebp + 0ch]的值进行相加,第三句则是将计算出来的结果eax放到[ebp - 8]里面,接下来我们将[ebp - 8]的值放进eax里面,以上的代码完成的是两个参数的计算,借助我们之前创建的函数栈帧图我们可以看出,[ebp+8]这个位置指向的数值其实就是我们在main函数外创建的实参的临时拷贝ecx(ebp + 8)和eax(ebp+0ch),其实在这里,我们也看出了函数传参的调用是从最右边的参数进行拷贝的。

接下来我们就开始进行结果的返回,我们最后的结果是放在ebp-8里面的,return z上面的代码是将ebp-8 的值放在eax里面,下面的代码就是正式的返回开始。

pop表示弹出空间,执行一次pop,就弹出一次空间,esp就增加一格,所以连续三次pop后,Add函数栈帧中创建的edi和esi和ebx就被销毁了,esp就指向Add函数栈帧主体了。

这里其实还是可以延展一下,都说函数创建后就被销毁了,那么计算出来的结果z是怎么被返回的呢?其实上面的讲解已经解决了这个问题,004EBF77  mov   eax,dword ptr [ebp-8]这一句代码中将ebp-8的值(即z的值)传给了eax这个寄存器,函数栈帧会被销毁,但是寄存器是不会被销毁的,所以这也就很好的回答了该问题。

然后,函数栈帧的主体结构也需要进行销毁,这里销毁的就很巧妙,004EBF7D  mov     esp,ebp  这一条代码就完成其工作内容,直接将ebp的值传给esp,那么esp就直接指向ebp的位置了,而上面的代码就被销毁了,我们看下图。

使esp指向ebp后,下一条指令004EBF7F  pop   ebp就是将ebp给弹出,使其回到上一个ebp的地方,而ebp被弹出后,esp也会向下增加一格,既是下图所圈出的两个位置。

然后下一条指令004EBF80  ret 则是让代码跳到esp指向的地址去(即是函数栈帧创建的时候的call指令的下一个指令的代码),可以参考我的上一篇文章《函数栈帧的创建》,如图。

所以,接下来进行的汇编代码如图。

下一条代码,让esp加上8,即释放了ecx和eax这两个实参的临时拷贝的空间,再下一条代码将eax的值放入[ebp-20h]这个地址里面,而在上面的函数栈帧图里面得知,[ebp-20h]这个地址就是c的地址,而eax就是上面我们介绍的eax寄存器,存储了计算结果,以上便是Add函数栈帧的销毁方法以及计算结果的返回。

main函数栈帧的销毁也是一样的方法,只是main函数返回值的是0。那我们便不在过多的赘述啦。

自此,函数栈帧的创建和销毁我们都讨论了一下啦,如果看到这里,能否给一个小小的赞鼓励一下我的,同时文中出现错误还请大家多多担待啦,我会继续努力的,谢谢大家,再次祝贺大家龙年大吉,合家欢乐!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值