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

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

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

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

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

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

                 

函数栈帧的创建和销毁

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

                    

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

               

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

esp栈顶指针        ;        ebp栈低指针


  • 寄存器集成在CPU上

               

  •  ebpesp 这两个寄存器中存放的是地址

               

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

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).leaload 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函数中对变量的拷贝,
    即下图
     ecxeax所以改变形参,改变的也只是 ecxeax ,
    并不会改变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://www.rhkb.cn/news/202642.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前缀和——238. 除自身以外数组的乘积

文章目录 &#x1f377;1. 题目&#x1f378;2. 算法原理&#x1f365;解法一&#xff1a;暴力求解&#x1f365;解法二&#xff1a;前缀和&#xff08;积&#xff09; &#x1f379;3. 代码实现 &#x1f377;1. 题目 题目链接&#xff1a;238. 除自身以外数组的乘积 - 力扣&a…

我在electron中集成了自己的ai大模型

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、大模型选择二、获取key三、调用api四、调用ai模型api时&#xff0c;解决跨域总结 前言 最近单位把gpt、文心一言、通义千问、星火等等等等你能想到的ai大模型都给禁掉了&#xff0c;简直丧心病狂。 不知道有多少感同…

leetcode 343.整数拆分 198.打家劫舍(动态规划)

OJ链接 &#xff1a;leetcode 343.整数拆分 代码&#xff1a; class Solution {public int integerBreak(int n) {int[] dp new int[n1];//每个n&#xff0c;拆分多个整数乘积的最大值dp [0] 0;dp [1] 1; for(int i 2 ; i<n; i){for(int j 0 ; j < i; j){dp[i] Ma…

【JavaEE初阶】 网络编程基础与Socket套接字

文章目录 &#x1f38b;网络编程基础&#x1f6a9;为什么需要网络编程&#xff1f;&#x1f6a9;什么是网络编程&#xff1f;&#x1f6a9;网络编程中的基本概念&#x1f4cc;发送端和接收端&#x1f4cc;请求和响应&#x1f4cc;客户端和服务端&#x1f4cc;常见的客户端服务端…

03. Python中的语句

1、前言 在《Python基础数据类型》一文中&#xff0c;我们了解了Python中的基础数据类型&#xff0c;今天我们继续了解下Python中的语句和函数。 2、语句 在Python中常用的语句可以大致分为两类&#xff1a;条件语句、循环语句。 2.1、条件语句 条件语句就是我们编码时常见…

基于Haclon的Blob分析

任务要求&#xff1a; 请用BLOB分析的方法计算图中所有灰度值在120和255之间的像素构成的8连通区域的面积与中心点坐标。 Blob基础&#xff1a; 分析过程&#xff1a;首先获取图像&#xff0c;然后根据特征对原始图像进行阈值分割&#xff08;区分背景像素和前景像素&#xf…

openstack(2)

目录 块存储服务 安装并配置控制节点 安装并配置一个存储节点 验证操作 封装镜像 上传镜像 块存储服务 安装并配置控制节点 创建数据库 [rootcontroller ~]# mysql -u root -pshg12345 MariaDB [(none)]> CREATE DATABASE cinder; MariaDB [(none)]> GRANT ALL PR…

Git工作流和Commit规范

Git大家都非常熟悉了&#xff0c;就不做过多介绍&#xff0c;但是如何用好Git、如何进行合理的分支开发、Merge你是否有一个规范流程呢&#xff1f;&#x1f4a4; 不论是一个团队一起开发一个项目&#xff0c;还是自己独立开发一个项目&#xff0c;都少不了要和Git打交道&…

AI赋能数据表设计

数据表设计软件用过多种&#xff0c;用Ai 设计表几年Ai大模型爆发之后提升了新的高度 用navicat 设计表就是在跟团队的人介绍这次功能的表结构时&#xff0c;没办法看备注&#xff0c;只能看英文字段&#xff0c;导致在比较复杂的表中&#xff0c;总是在表结构和图形结构中来回…

网络和Linux网络_4(应用层)序列化和反序列化(网络计算器)

目录 1. 重新理解协议 2. 网络版本计算器 2.1 前期封装 Log.hpp sock.hpp TcpServer.hpp 第一次测试(链接) 2.2 计算器实现 第二次测试(序列化和反序列化) 第三次测试(客户端字节流) CalServer.cc CalClient.cc 3. 守护进程 3.1 守护进程和前后台进程 3.1 变成…

zlmediakit实现rtsp流服务器

本次实现是将内存中的H264数据经过zlmediakit实现为rtsp流。 我是用的是CAPI的方式&#xff0c;将zlmediakit作为一个sdk嵌入到自己的程序中而不是作为一个独立的进进程服务。 1.编译完成zkmedialit后会得到bin include lib三个文件夹如图 其中bin中的MediaServer是作为独立的…

二蛋赠书八期:《Java物联网、人工智能和区块链编程实战》

前言 大家好&#xff01;我是二蛋&#xff0c;一个热爱技术、乐于分享的工程师。在过去的几年里&#xff0c;我一直通过各种渠道与大家分享技术知识和经验。我深知&#xff0c;每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此&#xff0c;我非常感激大家一直…

常见树种(贵州省):015榧树、秋枫、滇合欢、锥栗、红豆树、刺槐、余甘子、黑荆、槐树、黄檀

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、榧树 …

cocos2dx ​​Animate3D(二)

Twirl 扭曲旋转特效 // 持续时间(时间过后不会回到原来的样子) // 整个屏幕被分成几行几列 // 扭曲中心位置 // 扭曲的数量 // 振幅 static Twirl* create(float duration, const Size& gridSize, const Vec2& position, unsigned int twirls, float amplitude)…

​LeetCode解法汇总2304. 网格中的最小路径代价

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给你一个下…

Tars-GO 开发

默认环境是安装好的 创建服务: tarsgo make App Server Servant GoModuleName Tars 实例的名称&#xff0c;有三个层级&#xff0c;分别是 App&#xff08;应用&#xff09;、Server&#xff08;服务&#xff09;、Servant&#xff08;服务者&#xff0c;有时也称 Object&am…

构造命题公式的真值表

构造命题公式的真值表 1&#xff1a;实验类型&#xff1a;验证性2&#xff1a;实验目的&#xff1a;3&#xff1a;逻辑联结词的定义方法4&#xff1a;命题公式的表示方法5&#xff1a;【实验内容】 1&#xff1a;实验类型&#xff1a;验证性 2&#xff1a;实验目的&#xff1a…

Python满天星

系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/article/details/1295031234漂浮爱心https://want…

Linux 家目录和根目录

摘要&#xff1a; 在 Linux 操作系统中&#xff0c;家目录和根目录是两个非常重要的概念。它们是 Linux 文件系统中的两个关键节点&#xff0c;为用户和系统进程提供存储、管理和访问文件和目录的接口。本文旨在深入探讨和理解这两个目录的结构、功能和使用方式&#xff0c;同时…

C#,《小白学程序》第六课:队列(Queue)其二,队列的应用,编写《实时叫号系统》

医院里面常见的《叫号系统》怎么实现的&#xff1f; 1 文本格式 /// <summary> /// 下面定义一个新的队列&#xff0c;用于演示《实时叫号系统》 /// </summary> Queue<Classmate> q2 new Queue<Classmate>(); /// <summary> /// 《小白学程序…