学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程

马肤

温馨提示:这篇文章已超过474天没有更新,请注意相关的内容是否还可用!

学习C语言的第十一天,我通过查看汇编代码,逐步了解了函数栈帧(栈区局部变量)的创建和销毁过程。这一过程涉及到函数调用时如何在栈上分配和释放内存,以及局部变量如何在栈帧中存储。通过深入理解栈帧的结构和操作,我对C语言的运行时有更深的认识。

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

相关代码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 
            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;
            }
            
            函数栈帧图示:

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第1张

                                  


                                

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

                           

            mainCRTStartup        -->        __tmainCRTStartup        -->        main函数 

                        (调用)                                            (调用)

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第2张

                                

             实际开辟的空间为:

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第3张

                          

             (查看汇编代码:)

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第4张

                              


                                

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

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

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

            (压栈前:)

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第5张

                              

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第6张

                        

                        

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

                        

                        

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第7张

                        

                        

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

                        

                        

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第8张

                        

                        

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

                        

                        

            (4).连续push三次:

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第9张

                        

                        

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

                        

                        

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第10张

                        

                        

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

                        

                        

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第11张

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

                          

            变量未初始化,变量里面的数据就是“cc cc cc cc”,

            这些“cc cc cc cc”在使用后会产生随机值,

            即"烫烫烫",而初始化就会将这些随机值覆盖。

                        

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

                        

                        

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第12张

                        

                        

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

                        

                        

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第13张

                        

                        

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

                        

                        

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

            学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第14张

                          

                         

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

                            

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

                             

            • 为这次函数调用创建函数栈帧   -- (1)~(6)

                               

            • 在函数栈帧中找到空间把局部变量放进去   --(7)~(9)

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

                                

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第15张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第16张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第17张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第18张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第19张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第20张

                            

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第21张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第22张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第23张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第24张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第25张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第26张

                          

                          

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

                          

                          

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

              学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第27张

                          

                          

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

                          

                          

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

                              

               形参的产生和使用:
              • 形参是对实参的临时拷贝:形参是调用的main函数中对变量的拷贝,

                即下图 ecx 和 eax所以改变形参,改变的也只是 ecx 和 eax ,

                并不会改变main函数中的实参

                                    

              • 压栈时:先压的b’,所以在a‘下面,所以传参是先传的形参y,再传的形参x

                                

              • 形参的使用:通过指针的偏移量找到形参

                                 

                学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第28张

                                

                学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第29张

                            

                            

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

                            

                            

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

                学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第30张

                            

                            

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

                            

                            

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

                学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第31张

                            

                            

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

                            

                            

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

                学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第32张

                            

                            

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

                            

                            

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

                学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第33张

                            

                            

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

                            

                            

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

                学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】,C语言学习第11天,解析汇编代码,深入理解函数栈帧(栈区局部变量)的创建与销毁过程 第34张

                            

                            

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

                            

                            

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


0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码