当前位置:首页 » 《休闲阅读》 » 正文

学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】

28 人参与  2024年03月31日 13:25  分类 : 《休闲阅读》  评论

点击全文阅读


=========================================================================

相关代码gitee自取:C语言学习日记: 加油努力 (gitee.com)

=========================================================================

接上期:
学C的第十天(继续深入学习函数、函数递归、练习)-CSDN博客

=========================================================================

                 

函数栈帧的创建和销毁

越高级的编译器,越不容易学习和观察该过程

                    

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

               

寄存器:ebp 和 esp(和函数栈帧有关)

esp:栈顶指针        ;        ebp:栈低指针


寄存器集成在CPU上的

               

 ebp 和 esp 这两个寄存器中存放的是地址

               

这两个地址是用来维护函数栈帧的
                    

1. 每一次函数调用,都要在栈区创建一个空间

               

2. 正在调用哪个函数,esp 和 ebp 就在维护哪个函数的函数栈帧

               

3. esp 和 ebp 之间的空间就是系统为这次函数所调用的空间,叫这次函数的函数栈帧

               

4. 栈区的使用习惯是先使用高地址,再使用低地址

               

5. 空间消耗时,从高地址向低地址消耗

               

6. 再开辟新空间时,使用的空间是上面的空间(往上使用)

               

7. 像栈一样,放数据是在顶上(栈顶)放数据


               

测试代码:

#include <stdio.h>int Add(int x, int y){int z = 0;z = x + y;return z;}int main(){int a = 10;int b = 20;int c = 0;c = Add(a, b);printf("%d\n", c);return 0;}
函数栈帧图示:

                      


                    

在VS2013中,main函数也是被其它函数调用的

               

mainCRTStartup        -->        __tmainCRTStartup        -->        main函数 

            (调用)                                            (调用)

                    

 实际开辟的空间为:

              

 (查看汇编代码:)

                  


                    

函数栈帧实现过程(重点):

(1).push(压栈):给栈顶放一个元素

        [ 补充:pop(出栈) -->   从栈顶删除一个元素 ]

(压栈前:)

                  

(压栈后:esp会往上移,移到压的元素上方)

            

            

---------------------------------------------------------------------------------------------

            

            

(2).mov(把后面的值赋给前面,把esp的值赋给ebp):

            

            

---------------------------------------------------------------------------------------------

            

            

(3).sub(让esp减去一个十六进制数):

            

            

---------------------------------------------------------------------------------------------

            

            

(4).连续push三次:

            

            

---------------------------------------------------------------------------------------------

            

            

(5).lea(load effective address -- 加载有效地址,
把一个有效地址加载到edi中):

            

            

---------------------------------------------------------------------------------------------

            

            

(6).两次mov后,rep stos:

之前出现过的“烫烫烫”乱码的原因:

              

变量未初始化,变量里面的数据就是“cc cc cc cc”,
这些“cc cc cc cc”在使用后会产生随机值,
即"烫烫烫",而初始化就会将这些随机值覆盖。

            

---------------------------------------------------------------------------------------------

            

            

(7).产生局部变量:int a = 10; (mov)

            

            

---------------------------------------------------------------------------------------------

            

            

(8).产生局部变量:int b = 20; (mov)

            

            

---------------------------------------------------------------------------------------------

            

            

(9).产生局部变量:int c = 0; (mov)

              

             

===================================================================== 

                

(总结上面步骤)局部变量(上面的a、b、c)的创建过程:

                 

为这次函数调用创建函数栈帧   -- (1)~(6)
                 在函数栈帧中找到空间把局部变量放进去   --(7)~(9)

=====================================================================

                  

(10).调用函数:传参(mov)

            

            

---------------------------------------------------------------------------------------------

            

            

(11).调用函数:传参(push)

            

            

---------------------------------------------------------------------------------------------

            

            

(12).调用函数:传参(mov)

            

            

---------------------------------------------------------------------------------------------

            

            

(13).调用函数:传参(push)

            

            

---------------------------------------------------------------------------------------------

            

            

(14).call:调用函数(进入Add()函数)

            

            

---------------------------------------------------------------------------------------------

            

            

(15).进入Add()函数后:

              

(当前开辟的空间情况:)

            

            

---------------------------------------------------------------------------------------------

            

            

(16).Add()函数 的 push:

            

            

---------------------------------------------------------------------------------------------

            

            

(17).Add()函数 的 mov:

            

            

---------------------------------------------------------------------------------------------

            

            

(18).Add()函数 的 sub:

            

            

---------------------------------------------------------------------------------------------

            

            

(19).Add()函数 的 连续三次push:

            

            

---------------------------------------------------------------------------------------------

            

            

(20).Add()函数 的 lea(加载有效地址) --> mov  --> mov --> rep stos:

            

            

---------------------------------------------------------------------------------------------

            

            

(21).Add()函数中产生局部变量:int z = 0; (mov)

            

            

---------------------------------------------------------------------------------------------

            

            

(22).Add()函数中进行计算:z = x + y;

                

 形参的产生和使用:
形参是对实参的临时拷贝:形参是调用的main函数中对变量的拷贝,
即下图 ecx 和 eax所以改变形参,改变的也只是 ecx 和 eax ,
并不会改变main函数中的实参

                    压栈时:先压的b’,所以在a‘下面,所以传参是先传的形参y,再传的形参x
                形参的使用:通过指针的偏移量找到形参
                 

                

            

            

---------------------------------------------------------------------------------------------

            

            

(23).Add()函数计算后进行返回:return z;

            

            

---------------------------------------------------------------------------------------------

            

            

(24).Add()函数调用完后销毁空间返回main函数:
pop -- 出栈(弹出栈顶元素)

            

            

---------------------------------------------------------------------------------------------

            

            

(25).Add()函数调用完后销毁空间返回main函数:ret -- call函数调用完后,
返回main函数call的下一条指令(之前留的地址会出栈)

            

            

---------------------------------------------------------------------------------------------

            

            

(26).main函数:销毁形参

            

            

---------------------------------------------------------------------------------------------

            

            

(27).main函数:使用Add函数的返回值

            

            

---------------------------------------------------------------------------------------------

            

            

(28).最后main函数的销毁是和Add()函数的销毁是类似的


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/88492.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

最新文章

  • 祖母寿宴,侯府冒牌嫡女被打脸了(沈屿安秦秀婉)阅读 -
  • 《雕花锦年,昭都旧梦》(裴辞鹤昭都)完结版小说全文免费阅读_最新热门小说《雕花锦年,昭都旧梦》(裴辞鹤昭都) -
  • 郊区41号(许洛竹王云云)完整版免费阅读_最新全本小说郊区41号(许洛竹王云云) -
  • 负我情深几许(白诗茵陆司宴)完结版小说阅读_最热门小说排行榜负我情深几许白诗茵陆司宴 -
  • 九胞胎孕妇赖上我萱萱蓉蓉免费阅读全文_免费小说在线看九胞胎孕妇赖上我萱萱蓉蓉 -
  • 为保白月光,侯爷拿我抵了债(谢景安花田)小说完结版_完结版小说全文免费阅读为保白月光,侯爷拿我抵了债谢景安花田 -
  • 陆望程映川上官硕《我的阿爹是带攻略系统的替身》最新章节阅读_(我的阿爹是带攻略系统的替身)全章节免费在线阅读陆望程映川上官硕
  • 郑雅琴魏旭明免费阅读_郑雅琴魏旭明小说全文阅读笔趣阁
  • 头条热门小说《乔书意贺宴临(乔书意贺宴临)》乔书意贺宴临(全集完整小说大结局)全文阅读笔趣阁
  • 完结好看小说跨年夜,老婆初恋送儿子故意出车祸_沈月柔林瀚枫完结的小说免费阅读推荐
  • 热推《郑雅琴魏旭明》郑雅琴魏旭明~小说全文阅读~完本【已完结】笔趣阁
  • 《你的遗憾与我无关》宋怀川冯洛洛无弹窗小说免费阅读_免费小说大全《你的遗憾与我无关》宋怀川冯洛洛 -

    关于我们 | 我要投稿 | 免责申明

    Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1