【函数栈帧的创建和销毁】(超详细图解)(下)

简介: 【函数栈帧的创建和销毁】(超详细图解)

7.

002718E2call002710B4002718E7addesp,8

call指令是调用的意思,这里我们需要将call指令的下一条指令的地址进行压栈,这里因为函数调用会返回,而返回的地址正是call指令的下一条地址

357728052e624553aa2c5567c41db22e.png

接下来就正是进入我们的Add函数了

Add函数汇编代码:

intAdd(intx, inty) {
00271770pushebp00271771movebp,esp00271773subesp,0CCh00271779pushebx0027177Apushesi0027177Bpushedi0027177Cleaedi,[ebp-0Ch]  
0027177Fmovecx,300271784moveax,0CCCCCCCCh00271789repstosdwordptres:[edi]  
0027178Bmovecx,27C003h00271790call0027131Bintz=0;
00271795movdwordptr [ebp-8],0z=x+y;
0027179Cmoveax,dwordptr [ebp+8]  
0027179Faddeax,dwordptr [ebp+0Ch]  
002717A2movdwordptr [ebp-8],eaxreturnz;
002717A5moveax,dwordptr [ebp-8]  
}
002717A8popedi002717A9popesi002717AApopebx002717ABaddesp,0CCh002717B1cmpebp,esp002717B3call00271244002717B8movesp,ebp002717BApopebp002717BBret

8.

00271770pushebp00271771movebp,esp00271773subesp,0CCh00271779pushebx0027177Apushesi0027177Bpushedi0027177Cleaedi,[ebp-0Ch]  
0027177Fmovecx,300271784moveax,0CCCCCCCCh00271789repstosdwordptres:[edi]  

这里就进入了我们Add函数的汇编指令了,大家有没有发现这串代码和前面main函数开辟函数栈帧的代码很相似:

push:首先是ebp压栈,

mov:移动,将esp的值赋给edp

sub:将esp的值减去0Ch大小的空间

将edi向下的39这么大的空间里全部赋值为cccccccc

aad8c184b35c4d5a96b84a0e890d22b1.png


9.

intz=0;
00271795movdwordptr [ebp-8],0z=x+y;
0027179Cmoveax,dwordptr [ebp+8]  
0027179Faddeax,dwordptr [ebp+0Ch]  
002717A2movdwordptr [ebp-8],eaxreturnz;
002717A5moveax,dwordptr [ebp-8]  
00271795movdwordptr [ebp-8],0

 首先将[ebp-8]位置赋值为0给变量z

0027179Cmoveax,dwordptr [ebp+8]  
0027179Faddeax,dwordptr [ebp+0Ch]  
002717A2movdwordptr [ebp-8],eax

接下来将[ebp+8]位置的值赋给eax,而此时[ebp+8]正是我们在上面创建好的a变量10,即:eax=10,接着执行add,将[ebp+0ch]的值加给eax,而[ebp+0ch]的值正是我们在上面创建好的b变量20,此时eax=30,接着继续mov,将eax的值赋给[ebp-8],而[ebp-8]是我们上面创建好的z,一切都是那么的吻合!太美妙了!

0279611726394d358f14d3d1925c8795.png

我们在学习函数的时候,有一句话叫形参是实参的一份临时拷贝,现在看过来,这句话完全正确,因为我们在传参的时候,并没有独立去开辟新的空间去接收形参,而是通过寄存器去找到我们之前在主函数里压栈进去的实参!


10.

returnz;
002717A5moveax,dwordptr [ebp-8]  
}
002717A8popedi002717A9popesi002717AApopebx002717B8movesp,ebp002717BApopebp

mov  将[ebp-8]的值由eax保管

pop   意思是弹出,接下来就是函数栈帧的销毁,此时edi,esi,ebx就被销毁了

71b5b489a37348b2824aade392971a5e.png

 mov   将ebp的值赋给esp

00665db011d941468836985e7ff7f261.gif

pop   弹出ebp

ba3d4f0f4b4548eab213234df3073d17.png

到这里,红线以上的Add函数的栈帧就被销毁了

回过头看,我们为什么要将[ebp-8]的值先由eax保管,原因是[ebp-8] (也就是z的值)会销     毁,如果不由eax保管,那么返回值将带不出来!


10.

002717BBret

ret    返回值

此时栈顶上存放的就是call指令的下一条指令的地址,此时按F10,就直接跳到main函数的Add指令了

6adb4add0c0245688cd2a215cad5ee03.png

 这就是我们为什么要存放call指令的下一条指令的地址,就是为了确保函数销毁时我还能回得来!这一套逻辑真的是太严密了!!!


11.

002718E7addesp,8002718EAmovdwordptr [ebp-20h],eax

add    将esp的地址+8,就回到了我们的edi上面了

58da458aa5af48beb08886ec10942221.png

此时红线以上的部分又被销毁了,此时的形参x,y的空间就释放了

mov     将eax的值赋给[ebp-20h],而此时的[ebp-20h]就是我们之前压栈的c的空间,eax使我们上面带回来的30,赋给了变量c,这一切又是那么的巧妙!!!

a30af23cecd5438887695c9bfd4db98d.png


二 . 总结


当我们真正理通函数栈帧创建和销毁的过程,我们会产生一种敬畏之心(小编是有的),对前辈的敬畏,这么严密的底层逻辑思维,每一步汇编指令都是精心设计,回头来你会发现,原来当我们在写代码的时候,底层的一些东西原来是这样实现的,这个世界真的很奇妙!


如果对上文有意见或者有错误,还请大佬们斧正,觉得有帮助的童鞋们,蟹蟹三连!


目录
相关文章
|
JavaScript 前端开发
JS浮点数精度问题及高精度小数运算:BigNumber解决方案
JS浮点数精度问题及高精度小数运算:BigNumber解决方案
1387 0
|
网络安全
应用开发通过nfs来mount失败解决办法mount.nfs: Connection timed out
应用开发通过nfs来mount失败解决办法mount.nfs: Connection timed out
2445 0
|
存储 人工智能 弹性计算
国内首个,阿里云入选Gartner®战略云平台魔力象限挑战者
近日,Gartner发布2024年《战略云平台魔力象限》(Magic Quadrant™ for Strategic Cloud Platform Services)报告,阿里云从利基者象限进入挑战者象限,成为国内首个入选该象限的中国公共云厂商。
|
编解码 开发工具 C#
Windows电脑如何启动RTSP服务实现本地摄像头数据共享
本文介绍如何利用大牛直播SDK中的轻量级RTSP服务,在Windows平台上轻松采集摄像头数据并生成本地RTSP流。通过SDK提供的SmartPublisherDemo工具,用户能简便地选择摄像头、配置分辨率与帧率,并启动RTSP服务。此外,还支持音频采集、多端口服务以及动态水印等功能。生成的RTSP URL可用于其他终端拉流播放,无需额外部署服务器。该服务适配多种应用场景,如安防监控、电子教室等,并兼容Windows 7及以上版本。对于希望集成此功能的开发者,SDK提供了C++及C#接口,并支持多种编译模式。
820 0
|
网络协议 Android开发
Python 游戏开发的基本逻辑
游戏开发是一个复杂而富有挑战性的过程,需要综合运用多种技术和知识。在 Python 游戏开发中,理解基本逻辑是至关重要的。本文将介绍 Python 游戏开发的基本逻辑,并提供一些关键概念和示例,帮助你构建一个简单的游戏。
|
C# Windows
WPF技术之Border控件
WPF(Windows Presentation Foundation)的Border控件用于创建一个可视的边框,可以将其他控件包裹在内。
891 0
WPF技术之Border控件
|
弹性计算 Prometheus 运维
【数据可观测】阿里云的Grafana云监控大盘服务
阿里云发布的grafana托管服务,更是为云上的资产提供了高效的监控数据可观测能力。阿里云grafana弹性、免运维,可以方便的对接云上云下的各种数据源。
2711 1
【数据可观测】阿里云的Grafana云监控大盘服务
|
机器学习/深度学习 资源调度 算法
学习笔记: 机器学习经典算法-线性SVM(LinearSVM)
机器学习经典算法-个人笔记和学习心得分享
416 0