当前位置: 首页 > news >正文

函数栈帧的创建和销毁

1、总述:

大家在前期学习函数的时候,肯定会有诸多疑惑:

1、局部变量怎么创建的?

2、为什么有时候局部变量是随机值?

3、函数是怎么传参的?传参的顺序如何?

4、形参和实参是什么样的关系?

5、函数的调用怎么做的?

6、函数调用结束后怎么返回的?

今天,我将跟大家深入探讨,带大家了解函数背后的深层逻辑。当然我们也会一一解决以上问题。

2、寄存器

寄存器(Register)是计算机硬件中的一个关键组成部分,用于存储数据和指令。它们是CPU(中央处理单元)内部的小型存储区域,与主内存(RAM)相比,寄存器的访问速度要快得多。寄存器在计算机体系结构中扮演着至关重要的角色。

我们今天了解的主要是:eax,ebx,ecx,edx,还有两个最主要的的ebp,esp。

ebp,esp这两个寄存器中存放的是地址,这两个地址用来维护函数栈帧。

我们学函数部分时知道每一个函数调用,都要在栈区创建空间。

就如图中所示,当我们去调试代码时发现,main函数也是被调用的,打开VS的调试下的窗口的调用堆栈我们就可以知道,main函数被__tmainCRTStartup调用而 __tmainCRTStartup函数类似的被mainCRTStartup调用。

这里要注意:当哪个函数被调用,ebp,esp这两个寄存器中就维护这个函数的栈帧。

每调用一个函数就建立相对应的函数栈帧,从高地址到低地址依次建立,最先被调用的函数先建立函数栈帧。 

下面是重点,大家要认真听:

我们在前面说过main函数被_tmainCRTStartup调用,所以在建立main函数栈帧之前先建立_tmainCRTStartup函数栈帧

如下图:

这里要注意是从高地址向低地址,也就是向上蔓延。 

3、函数栈帧的建立

现在我们要深入底层,看看汇编语言。

第一步叫push(压栈)将ebp的值放到栈顶,同时esp指向栈顶 如图:

第二步mov(将esp的地址赋给ebp) 所以ebp将指向esp的位置

第三步sub(esp指向esp减去0E4h的地址) 这里0E4h是十六进制数字转换为十进制是228,这时esp指向一块未知空间,我们会发现ebp,esp又维护了一块新的空间,这块空间就是为main函数预先开辟好的空间。

后面三步都是一样将ebx,esi,edi压栈得到

第七步lea(将ebp减024h的地址放到edi) 后面两步也是同理,到rep stos的意思是将从edi这个位置开始向下的9次也就是ecx里的值这么多个doule word的值全部改成eax里的cccccccc。

当我们走完上面这些步骤时,main函数栈帧的建立就结束了,

我们假设CCCCCCCC是4个字节,就要把14h的值放到ebp-8的位置 ,ebp-8的位置放的就是a的值20.下面两步同理,要注意的是:ebp-14h在内存中与ebp-8相距两个double的位置,所以得下图:

做完上面这些,就创建好了局部变量,接下来就该调用Add函数了。

第一步就是将ebp-14h的值也就是b的值放入eax这个寄存器中,接着把eax的值压栈,后面两步同理得到如图:

第五步,call(调用)后内存中存入00B518E7(也就是call的下一条指令add),等我们调用完A    dd的函数后,要返回就会使用到,刚好又存入call的下一条指令,可以完美衔接。

接下来就要建立Add的函数栈帧, 

因为和上面的类似,所以我们下面节奏快一点,前三步,push(将ebp压栈),mov(将esp的地址赋给ebp),sub(将esp-0CCh的地址赋给esp),这三步就是给Add函数建立栈帧分配空间,后三步,将ebx,esi,edi压栈。得到下图:

       

后面四步,将从edi的这个位置向下的3次的double word的值全部改成CCCCCCC。接下来,创建局部变量z,mov(将z的值0放到ebp-8的位置),其次就要进行运算了z=x+y。将ebp+8的值20放入eax寄存器中,然后将ebp+0Ch的值10与eax中的20相加放入eax中,最后将eax的值赋值给z。

最后就是返回z,那么z是如何返回的呢?

其实,是将z相加之后的值30放到eax中,即使出了函数后,z被销毁,但eax是在CPU中的。

整个流程弄下来得到下图:

4、函数栈帧的销毁 

z返回完后就要开始栈帧的销毁了。 

我们来看是如何回收空间的:

先是三个pop,pop的意思是弹出(也可以理解为出栈) , 后面三步省略,直接看mov(将ebp的地址赋给esp),然后在pop(这里ebp存的是main函数开始的ebp),弹出后ebp指向原来main函数位置,完成对Add函数栈帧的回收,当然这里要注意一下ret这一条指令,当我们执行完上面这些步骤

esp指向的刚好是call的下一条指令,这样函数可以返回,这也是为啥这里存call指令下一条指令的原因,main函数回收也是同理,这里就略过了。

最后最后回答一下前面的六个问题:

1、局部变量怎么创建的?

为函数分配好栈帧空间后,初始化一部分空间,为局部变量分配栈帧空间。

2、为什么有时候局部变量是随机值?

我们没有进行初始化 ,局部变量由我们决定的。

3、函数是怎么传参的?传参的顺序如何?

在我们调用函数时,在还没调用函数之前,先将变量压栈,在Add函数中通过指针的偏移量找到形参,传参的顺序是从右往左(可以从压栈的顺序看出,b先被压栈)

4、形参和实参是什么样的关系?

形参和实参值相同,空间是独立的,形参是实参的一份临时拷贝,改变形参不会影响实参。

5、函数的调用怎么做的?

以上讲的都是

6、函数调用结束后怎么返回的?

将call指令的下一条指令压栈,当栈帧销毁,返回时可以直接跳转到call的下一条指令,让函数可以返回,返回值是通过寄存器带回来的。

今天的分享就到这,谢谢大家!

相关文章:

函数栈帧的创建和销毁

1、总述: 大家在前期学习函数的时候,肯定会有诸多疑惑: 1、局部变量怎么创建的? 2、为什么有时候局部变量是随机值? 3、函数是怎么传参的?传参的顺序如何? 4、形参和实参是什么样的关系&am…...

【MQ】探索 Kafka

高性能 消息的顺序性、顺序写磁盘 零拷贝 RocketMQ内部主要是使用基于mmap实现的零拷贝,用来读写文件 减少cpu的拷贝次数和上下文切换次数,实现文件的高效读写操作 Kafka 零拷贝 Kafka 使用到了 mmap 和 sendfile 的方式来实现零拷贝。分别对应 Jav…...

c++ set/multiset 容器

1. set 基本概念 简介: 所有元素都会在插入时自动排序本质: set/multiset属于关联式容器,底层结构是用二叉树实现。set 和 multiset 区别: set容器不允许有重复的元素。 multiset允许有重复的元素。2. set 构造和赋值 构造&a…...

react-bn-面试

1.主要内容 工作台待办 实现思路: 1,待办list由后端返回,固定需要的字段有id(查详细)、type(本条待办的类型),还可能需要时间,状态等 2,一个集中处理待办中转路由页,所有待办都跳转到这个页面…...

【C++数论】880. 索引处的解码字符串|2010

本文涉及知识点 数论:质数、最大公约数、菲蜀定理 LeetCode880. 索引处的解码字符串 给定一个编码字符串 s 。请你找出 解码字符串 并将其写入磁带。解码时,从编码字符串中 每次读取一个字符 ,并采取以下步骤: 如果所读的字符是…...

shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。

文章目录 前言1. 直接上代码最后在讲解1.1 新增的pom依赖1.2 RedisCache.java1.3 RedisCacheManager.java1.4 jwt的三个类1.5 ShiroConfig.java新增Bean 2. 源码讲解。2.1 shiro 缓存的代码流程。2.2 缓存流程2.2.1 认证和授权简述2.2.2 AuthenticatingRealm.getAuthentication…...

Python案例--养兔子

兔子繁殖问题是一个经典的数学问题,最早由意大利数学家斐波那契在13世纪提出。这个问题不仅在数学领域具有重要意义,还广泛应用于计算机科学、生物学和经济学等领域。本文将通过一个具体的Python程序,深入探讨兔子繁殖问题的建模和实现&#…...

【搜索回溯算法】:BFS的魔力--如何使用广度优先搜索找到最短路径

✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:搜索回溯算法篇–CSDN博客 文章目录 一.广度优先搜索(BFS)解决最短路…...

JavaSE第十一天——集合框架Collection

一、List接口 List接口是一个有序的集合,允许元素有重复,它继承了Collection接口,提供了许多额外的功能,比如基于索引的插入、删除和访问元素等。 常见的List接口的实现类有ArrayList、LinkedList和Vector。 List接口的实现类 …...

Three城市引擎地图插件Geo-3d

一、简介 基于Three开发,为Three 3D场景提供GIS能力和城市底座渲染能力。支持Web墨卡托、WGS84、GCJ02等坐标系,支持坐标转换,支持影像、地形、geojson建筑、道路,植被等渲染。支持自定义主题。 二、效果 三、代码 //插件初始化…...

深度学习|表示学习|卷积神经网络|详细推导每一层的维度变化|14

如是我闻: 一个经典的卷积神经网络(CNN)架构,呈现的是输入图像通过多个卷积层、池化层以及全连接层,最终输出分类结果的过程。整个过程的核心是理解输入特征图的尺寸如何在每一层发生变化,我们可以通过卷积…...

多级缓存(亿级并发解决方案)

多级缓存(亿级流量(并发)的缓存方案) 传统缓存的问题 传统缓存是请求到达tomcat后,先查询redis,如果未命中则查询数据库,问题如下: (1)请求要经过tomcat处…...

BOM对象location与数组操作结合——查询串提取案例

BOM对象location与数组操作结合——查询串提取案例 前置知识 1. Location 对象 Location 对象是 JavaScript 提供的内置对象之一,它表示当前窗口或框架的 URL,并允许你通过它操作或获取 URL 的信息。可以通过 window.location 访问。 主要属性&#…...

读书笔记--分布式服务架构对比及优势

本篇是在上一篇的基础上,主要对共享服务平台建设所依赖的分布式服务架构进行学习,主要记录和思考如下,供大家学习参考。随着企业各业务数字化转型工作的推进,之前在传统的单一系统(或单体应用)模式中&#…...

GOGOGO 枚举

含义:一种类似于类的一种结构 作用:是Java提供的一个数据类型,可以设置值是固定的 【当某一个数据类型受自身限制的时候,使用枚举】 语法格式: public enum 枚举名{…… }有哪些成员? A、对象 public …...

【Linux】Linux基础开发工具

1 Linux 软件包管理器 yum 1.1软件包 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上,通过包管理器可以很方便的…...

嵌入式C语言:结构体的多态性之结构体中的void*万能指针

目录 一、void*指针在结构体中的应用 二、实现方式 2.1. 定义通用结构体 2.2. 定义具体结构体 2.3. 初始化和使用 三、应用场景 3.1. 内存管理函数 3.2. 泛型数据结构(链表) 3.3. 回调函数和函数指针 3.4. 跨语言调用或API接口(模拟…...

重构进行时:一秒告别 !=null 判空

重构进行时:一秒告别 !null 判空 空指针异常(NullPointerException)是Java开发中常见的错误之一。 许多开发者在遇到空指针问题时,往往会习惯性地使用! null来进行判断。 然而,当代码中频繁出现这种判断时&#xff…...

React 中hooks之useSyncExternalStore使用总结

1. 基本概念 useSyncExternalStore 是 React 18 引入的一个 Hook,用于订阅外部数据源,确保在并发渲染下数据的一致性。它主要用于: 订阅浏览器 API(如 window.width)订阅第三方状态管理库订阅任何外部数据源 1.1 基…...

Semaphore 与 线程池 Executor 有什么区别?

前言:笔者在看Semaphone时 突然脑子宕机,啥啥分不清 Semaphore 和 Executor 的作用,故再次记录。 一、什么是Semaphore? Semaphore 是 Java 并发编程(JUC)中一个重要的同步工具,它的作用是 控…...

Rust:高性能与安全并行的编程语言

引言 在现代编程世界里,开发者面临的最大挑战之一就是如何平衡性能与安全性。在许多情况下,C/C这样的系统级编程语言虽然性能强大,但其内存管理的复杂性导致了各种安全漏洞。为了解决这些问题,Rust 作为一种新的系统级编程语言进入…...

论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(六)(完结)

Understanding Diffusion Models: A Unified Perspective(六)(完结) 文章概括指导(Guidance)分类器指导无分类器引导(Classifier-Free Guidance) 总结 文章概括 引用: …...

Redis --- 分布式锁的使用

我们在上篇博客高并发处理 --- 超卖问题一人一单解决方案讲述了两种锁解决业务的使用方法,但是这样不能让锁跨JVM也就是跨进程去使用,只能适用在单体项目中如下图: 为了解决这种场景,我们就需要用一个锁监视器对全部集群进行监视…...

电脑怎么格式化?格式化详细步骤

格式化是我们在日常使用电脑时可能会用到的一种操作,无论是清理磁盘空间、安装新系统,还是解决磁盘读写错误,都可能需要格式化。不过,对于一些不熟悉电脑操作的用户来说,格式化听起来可能有些复杂。其实,只…...

TikTok广告投放优化策略:提升ROI的核心技巧

在短许多品牌和商家纷纷投入广告营销,争夺这片潜力巨大的市场。然而,在激烈的竞争环境中,如何精准有效地投放广告,优化广告效果,实现更高的投资回报率(ROI)成为了广告主关注的核心。 一. 精准受…...

视觉语言模型 (VLMs):跨模态智能的探索

文章目录 一. VLMs 的重要性与挑战:连接视觉与语言的桥梁 🌉二. VLMs 的核心训练范式:四种主流策略 🗺️1. 对比训练 (Contrastive Training):拉近正例,推远负例 ⚖️2. 掩码方法 (Masking):重构…...

第05章 08 绘制脑部体绘制图的阈值等值面

绘制脑部体绘制图的阈值等值面,例如肌肉和头骨骼,需要对医学图像数据进行阈值处理,并使用体绘制技术来可视化这些结构。以下是一个基于VTK/C的示例代码,展示如何读取DICOM图像数据,应用阈值过滤器来提取特定组织&#…...

类和对象(4)——多态:方法重写与动态绑定、向上转型和向下转型、多态的实现条件

目录 1. 向上转型和向下转型 1.1 向上转型 1.2 向下转型 1.3 instanceof关键字 2. 重写(overidde) 2.1 方法重写的规则 2.1.1 基础规则 2.1.2 深层规则 2.2 三种不能重写的方法 final修饰 private修饰 static修饰 3. 动态绑定 3.1 动态绑…...

动态规划<九>两个数组的dp

目录 引例 LeetCode经典OJ题 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 7.第七题 引例 OJ传送门LeetCode<1143>最长公共子序列 画图分析&#xff1a; 使用动态规划解决 1.状态表示 ------经验题目要求 经验为选取第一个字符串的[0,i]区间以及第二个字…...

Go:基于Go实现一个压测工具

文章目录 写在前面整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理 客户端模块Http客户端处理Grpc客户端处理Websocket客户端处理 连接处理模块GrpcHttp 统计数据模块统计原理实现过程 写在前面 本篇主要是基于Go来实现一个压测的工具&#xff0c;关于压测的内…...

2025年数学建模美赛 A题分析(2)楼梯使用频率数学模型

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…...

在Ubuntu上用Llama Factory命令行微调Qwen2.5的简单过程

半年多之前写过一个教程&#xff1a;在Windows上用Llama Factory微调Llama 3的基本操作_llama-factory windows-CSDN博客 如果用命令行做的话&#xff0c;前面的步骤可以参考上面这个博客。安装好环境后&#xff0c; 用自我认知数据集微调Lora模块&#xff1a;data/identity.j…...

虹科分享 | 汽车NVH小课堂之听音辨故障

随着车主开始关注汽车抖动异响问题&#xff0c;如何根据故障现象快速诊断异响来源&#xff0c;成了汽修人的必修课。 一个比较常用的方法就是靠“听”——“听音辨故障”。那今天&#xff0c;虹科Pico也整理了几个不同类型的异响声音&#xff0c;一起来听听看你能答对几个吧 汽…...

RoboVLM——通用机器人策略的VLA设计哲学:如何选择骨干网络、如何构建VLA架构、何时添加跨本体数据

前言 本博客内解读不少VLA模型了&#xff0c;包括π0等&#xff0c;且如此文的开头所说 前两天又重点看了下openvla&#xff0c;和cogact&#xff0c;发现 目前cogACT把openvla的动作预测换成了dit&#xff0c;在模型架构层面上&#xff0c;逼近了π0​那为了进一步逼近&#…...

【SpringBoot教程】Spring Boot + MySQL + HikariCP 连接池整合教程

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 在前面一篇文章中毛毛张介绍了SpringBoot中数据源与数据库连接池相关概念&#xff0c;今天毛毛张要分享的是关于SpringBoot整合HicariCP连接池相关知识点以及底层源码…...

0.91英寸OLED显示屏一种具有小尺寸、高分辨率、低功耗特性的显示器件

0.91英寸OLED显示屏是一种具有小尺寸、高分辨率、低功耗特性的显示器件。以下是对0.91英寸OLED显示屏的详细介绍&#xff1a; 一、基本参数 尺寸&#xff1a;0.91英寸分辨率&#xff1a;通常为128x32像素&#xff0c;意味着显示屏上有128列和32行的像素点&#xff0c;总共409…...

【insert函数】

在 C 中&#xff0c;std::string::insert 是一个功能强大的成员函数&#xff0c;用于在字符串的指定位置插入内容。它有多个重载版本&#xff0c;支持插入 字符、字符串、子字符串 等。以下是 insert 所有相关函数的详细介绍&#xff1a; 1. 插入字符串 函数签名&#xff1a; …...

Python 如何进行文本匹配:difflib| python 小知识

Python 如何进行文本匹配&#xff1a;difflib| python 小知识 difflib是Python标准库中的一个工具&#xff0c;用于比较和处理文本差异。它提供了一组用于比较和处理文本差异的功能&#xff0c;可以用于比较字符串、文件等。本文将详细介绍difflib模块的用法和实现细节&#x…...

MySQL误删数据怎么办?

文章目录 1. 从备份恢复数据2. 通过二进制日志恢复数据3. 使用数据恢复工具4. 利用事务回滚恢复数据5. 预防误删数据的策略总结 在使用MySQL进行数据管理时&#xff0c;误删数据是一个常见且具有高风险的操作。无论是因为操作失误、系统故障&#xff0c;还是不小心执行了删除命…...

可以称之为“yyds”的物联网开源框架有哪几个?

有了物联网的发展&#xff0c;我们的生活似乎也变得更加“鲜活”、有趣、便捷&#xff0c;包具有科技感的。在物联网&#xff08;IoT&#xff09;领域中&#xff0c;也有许多优秀的开源框架支持设备连接、数据处理、云服务等&#xff0c;成为被用户们广泛认可的存在。以下给大家…...

为AI聊天工具添加一个知识系统 之74 详细设计之15 正则表达式 之2

本文要点 要点 本项目&#xff08;为AI聊天工具添加一个知识系统&#xff09;中的正则表达式。 正则表达式的三“比”。正则表达式被 一、排比为三种符号&#xff08;元符号-圈号&#xff0c;特殊符号-引号&#xff0c;普通符号-括号&#xff09; 引号<<a线性回归bo…...

Java 注解与元数据

Java学习资料 Java学习资料 Java学习资料 一、引言 在 Java 编程中&#xff0c;注解&#xff08;Annotation&#xff09;和元数据&#xff08;Metadata&#xff09;是两个重要的概念。注解为程序提供了一种在代码中嵌入额外信息的方式&#xff0c;这些额外信息就是元数据。元…...

【橘子Kibana】Kibana的分析能力Analytics简易分析

一、kibana是啥&#xff0c;能干嘛 我们经常会用es来实现一些关于检索&#xff0c;关于分析的业务。但是es本身并没有UI,我们只能通过调用api来完成一些能力。而kibana就是他的一个外置UI&#xff0c;你完全可以这么理解。 当我们进入kibana的主页的时候你可以看到这样的布局。…...

度小满前端面试题及参考答案

<form>标签使用过哪些 tag? <form>标签中常使用的标签有很多。 <input>:这是最常用的标签之一,用于创建各种类型的输入字段,如文本框、密码框、单选按钮、复选框、文件上传框等。通过设置type属性来指定输入类型,例如type="text"创建文本输入…...

Padas进行MongoDB数据库CRUD

在数据处理的领域,MongoDB作为一款NoSQL数据库,以其灵活的文档存储结构和高扩展性广泛应用于大规模数据处理场景。Pandas作为Python的核心数据处理库,能够高效处理结构化数据。在MongoDB中,数据以JSON格式存储,这与Pandas的DataFrame结构可以很方便地互相转换。通过这篇教…...

LQ1052 Fibonacci斐波那契数列

题目描述 Fibonacci斐波那契数列也称为兔子数列&#xff0c;它的递推公式为&#xff1a;FnFn-1Fn-2&#xff0c;其中F1F21。 当n比较大时&#xff0c;Fn也非常大&#xff0c;现在小蓝想知道&#xff0c;Fn除以10007的余数是多少&#xff0c;请你编程告诉她。 输入 输入包含一…...

华硕笔记本装win10哪个版本好用分析_华硕笔记本装win10专业版图文教程

华硕笔记本装win10哪个版本好用&#xff1f;华硕笔记本还是建议安装win10专业版。Win分为多个版本&#xff0c;其中家庭版&#xff08;Home&#xff09;和专业版&#xff08;Pro&#xff09;是用户选择最多的两个版本。win10专业版在功能以及安全性方面有着明显的优势&#xff…...

编译器gcc/g++ --【Linux基础开发工具】

文章目录 一、背景知识二、gcc编译选项1、预处理(进行宏替换)2、编译&#xff08;生成汇编&#xff09;3、汇编&#xff08;生成机器可识别代码&#xff09;4、链接&#xff08;生成可执行文件或库文件&#xff09; 三、动态链接和静态链接四、静态库和动态库1、动静态库2、编译…...

八股文 (一)

文章目录 项目地址一、前端1.1 大文件上传,预览1.2 首页性能优化1.2 流量染色,灰度发布1.3 Websock心跳机制,大数据实时数据优化1.4 Gpu 加速 fps优化1.5 echarts包大小优化和组件封装1.6 前端监控系统1.7 超大虚拟列表卡顿1. 实现2. 相关问题(1) 什么是虚拟化列表,为什么要…...

c语言无符号的变量不能和有符号的直接比较,或者使用移项解决符号问题

使用移项解决问题&#xff0c;简单来说就是无符号运行不要有减号&#xff0c;使用移项后的加号代替 if(uEventDirLimitSize > uEventAndNormalDirSize) {if((uEventDirLimitSize - uEventAndNormalDirSize) > pStConfig->stParam.stUserParam.uEventRemain){return O…...