从汇编代码探究函数栈帧的创建和销毁的底层原理(二)

简介: 从汇编代码探究函数栈帧的创建和销毁的底层原理

2.创建变量

在代码的反汇编部分,右击鼠标,将显示符号名关掉

一直按F10到Add之前的汇编代码处

mov         dword ptr [ebp-8],5       将5存入  ebp-8 的位置


mov         dword ptr [ebp-14h],2   将2存入  ebp-14h(4+1*16=20(ebp-20))的位置


mov         dword ptr [ebp-20h],0   将0存入  ebp-20h(0+2*16=32(ebp-32))的位置


存储之后的内存图这样就创建了变量a,b,c

3.函数传参

mov         eax,dword ptr [ebp-14h]   将ebp-14h(其实就是b的值)的值放入eax(寄存器)里面去


push        eax  eax压栈,将eax放在栈顶


mov         ecx,dword ptr [ebp-8]   将ebp-8(其实就是a的值)的值放入ecx(寄存器)里面去


push        ecx  ecx压栈 ,将ecx放栈顶

传参---先传b,再传a (说明函数传参是从右向左的)

4.函数调用

call--函数调用

执行到此处要按F11进入函数内部

观察内存后,发现执行完call后,call指令的下一条指令的地址被压栈

当后面执行完Add函数后,通过这个地址可以找到调用位置并继续向下执行代码再按F11就进入了Add函数,发现前面的指令与main函数里面一样,说明函数栈帧的创建过程是相同的

与刚开始创建mian函数栈帧的过程相同,唯一不同的就是不同函数栈帧开辟的空间大小有差异,这个空间大小取决于编译器

同样,由于正在调用Add函数,ebp和esp就来维护Add函数的函数栈帧

同样,在Add函数中开始执行代码mov         eax,dword ptr [ebp+8]  ebp+8的值赋给eax


add         eax,dword ptr [ebp+0Ch]   将ebp+0Ch的值与eax的值相加并赋值给eax


mov         dword ptr [ebp-8],eax  将eax的值赋给ebp-8


eax是一个寄存器,可以存储变量/变量的值

说明真进行函数调用的时候,形参并不是在Add函数内部创建的,而是在函数调用刚开始的时候,通过压栈,将参数a,参数b传上去了,且参数b是先传的


在使用形参的时候,回头找到了以前压栈的这块空间,说明形参确实是实参的一份临时拷贝


形参并没有真再创建自己的空间


最后将形参计算的结果存入ebp-8中


但是如果在函数里面创建变量的话,它的内存是单独分配的


四、函数栈帧的销毁

先将计算结果ebp-8(z)里面的值存在寄存器中,方便后面将Add的函数栈帧销毁后返回

三次pop,从栈顶删去三个元素

将ebp赋为esp(说明esp移动到ebp位置,此时栈顶发生变化,到了ebp的位置)

然后从栈顶删去一个元素放在ebp里面,esp继续向下。

因为此时栈顶放的是main函数的栈底地址,所以,ebp通过这个地址找到了main函数的栈底

此时就从Add函数里面顺利的回到了main函数里面

因为00F83420是调用函数的指令call的下一条指令的地址,所以恰好可以让代码继续运行

这就是上面为什么要将call下一条指令的地址存起来

确保‘走出去’,还能‘找回来’ 继续运行add这一条指令

然后ret(return):将栈顶的那个指针pop(出栈)

esp(栈顶指针)再向下移动此时esp+8,即将栈顶 + 8 就相当于将形参x,y销毁,如图

然后mov 将寄存器eax中存的Add函数的计算结果放在ebp-20h中,即c中

此时要进入printf函数,虽然printf已经封装好了,但printf函数的调用还是要经历函数栈帧的创建和销毁这个过程,方法与Add函数相同,这里就不过多赘述

那么return 0就是main函数栈帧的销毁过程

  最后的结果就是main函数的栈帧也被销毁

相关文章
|
3月前
|
网络协议 C++
解决MASM32代码汇编出错: error A2181: initializer must be a string or single item
解决MASM32代码汇编出错: error A2181: initializer must be a string or single item
|
4月前
|
存储 算法 程序员
神秘代码世界惊现高效秘籍!究竟是什么让汇编语言编程如此强大?快来一探究竟!
【8月更文挑战第31天】《代码之美:探索高效汇编语言编程的最佳实践》介绍了汇编语言在系统内核、嵌入式系统及高性能应用中的不可替代作用。书中强调了深入理解处理器架构、提升代码可读性、优化算法与数据结构及有效利用寄存器等最佳实践的重要性。通过具体示例,如在 x86 架构下实现高效的加法函数,展示了如何运用这些技巧编写出既高效又可靠的汇编代码,充分展现了汇编语言的独特魅力及其在现代软件开发中的价值。
52 0
|
3月前
|
Windows
【原创】DOS下TSR程序的汇编演示代码2--黑屏保护程序
【原创】DOS下TSR程序的汇编演示代码2--黑屏保护程序
【原创】DOS下TSR程序的汇编演示代码1--自动按键程序
【原创】DOS下TSR程序的汇编演示代码1--自动按键程序
|
4月前
|
NoSQL 前端开发 程序员
【震撼揭秘!】程序员绝不会告诉你的秘密:掌握汇编语言调试,轻松从软件故障中全身而退——透视代码底层,成为Bug猎人!
【8月更文挑战第31天】《调试的艺术:如何利用汇编语言追踪和解决软件问题》探讨了使用汇编语言进行高效调试的方法。无论是初学者还是资深开发者,面对棘手的 bug 时,高级语言的信息往往不足。文章通过具体示例展示如何通过汇编代码定位问题,如 C 语言中数组求和函数的崩溃问题。借助 `gcc -S` 生成的汇编代码和 GDB 调试器,可以深入理解程序行为,从而更准确地解决问题。掌握这一技能,将使你在复杂问题面前更加从容。
48 2
|
4月前
|
C语言
51单片机汇编语言流水灯代码
51单片机汇编语言流水灯代码
105 1
|
4月前
|
C# 开发者 图形学
Xamarin 竟在游戏开发领域大胆探索,跨平台优势与强大功能结合,开启游戏开发新潮流!
【8月更文挑战第31天】《Xamarin在游戏开发领域的探索》介绍了Xamarin作为跨平台开发框架,在移动游戏开发中的应用。它利用C#语言的优势,提供高效的开发体验,并结合各平台图形库实现高质量画面。本文还展示了Xamarin如何简化游戏逻辑处理、支持多线程编程及与Unity等工具集成,提升游戏质量和开发效率。此外,Xamarin还支持热更新和多平台发布,进一步优化游戏维护流程。
47 0
|
7月前
|
存储 Unix 编译器
汇编语言----X86汇编指令
汇编语言----X86汇编指令
292 2
|
2月前
|
存储 移动开发 C语言
【ARM汇编速成】零基础入门汇编语言之指令集(三)
【ARM汇编速成】零基础入门汇编语言之指令集(三)
|
2月前
|
编译器 C语言 计算机视觉
【ARM汇编速成】零基础入门汇编语言之指令集(二)
【ARM汇编速成】零基础入门汇编语言之指令集(二)
250 0