函数栈帧的创建和销毁 - 局部变量|函数传参|函数调用|函数返回|图文详解

news2025/1/10 21:15:14

目录

1.寄存器EBP和ESP

2.函数栈帧的创建

3.函数的调用

4. 函数栈帧的销毁


函数栈帧(function stack frame)是在函数调用期间在上分配的内存区域,用于存储函数的局部变量、参数、以及用于函数调用和返回的相关信息。每当函数被调用时,都会创建一个新的栈帧,函数执行结束后,该栈帧会被销毁。

1.寄存器EBP和ESP

寄存器是位于CPU内部的一组用于存储和处理数据的小型临时存储器。它们被设计用于执行指令、进行算术和逻辑运算、控制程序流程等任务。寄存器通常比内存访问速度更快,因为它们直接集成在CPU内部,而不需要通过外部总线进行访问。

EBP和ESP是 x86 架构下的寄存器,用于在函数调用过程中维护被调用的函数的栈帧。

EBP是扩展基址寄存器(栈底指针),通常用来指向当前函数的栈帧的基址(高地址处)。ESP是栈指针寄存器(栈顶指针),指向当前栈顶的位置(低地址处)

每当函数调用时时,都要在栈区上创建一个空间,并且将栈区的地址分别交由寄存器EBP和ESP来来维护。正在调用的是哪个函数,这两个寄存器就维护哪个函数的栈帧。

2.函数栈帧的创建

接下来通过一个简单求和函数来了解函数栈帧的创建过程

#include<stdio.h>

int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}

int main()
{
	int a = 2;
	int b = 1;

	int c = Add(a, b);

	return 0;
}

再来看这段反汇编代码:

可以看到,在进入main函数的时候有一系列的反汇编指令,它们是什么意思?干了什么事情?

下面是一个内存演示图 :在进入main函数之前,ebp和esp分别指向调用main函数的函数的栈底和栈顶。


push ebp(压栈):执行这一条语句后,将ebp的值放在esp的位置,esp维护栈顶位置,所以esp向高地址走一步(值减小)


mov ebp,esp:将esp的值给ebp 


sub esp,0E4h:esp向上低地址处移动,现在ebp与esp之间的空间就是为main函数开辟的栈帧空间


push  ebx , push esi, push sdi:把ebx,esi,edi分别压入栈


lea  edi,[ebp-24h]:ebp的值减去24(十六进制)的偏移量,然后将结果储存在edi中。这样做是为了将edi指向要填充的内存区域的起始地址

mov ecx,9:存储到ecx中。这个值表示要填充的内存区域的大小,单位为dword(Double Word 即4字节).

mov eax,0cccccccch:将0xcccccccc 存储到eax中.

rep stos dword ptr es:[edi]  :一个重复(rep)操作,它会将eax中的值(0xcccccccc)存储到edi所指向的内存地址处,存储的长度为ecx中的值(9 dword)


3.函数的调用

到这里为止,调用main函数的准备工作才算结束,接下来才刚开始执行我们写的代码:

 mov  eax,dword ptr [a]:写入数据到a的位置。这里的b其实就是ebp - 8 的位置

后面的mov都是写入数据,只是写入的位置逐渐向低地址处移动。


终于来到调用函数Add的部分,首先我们进行函数的参数传递

mov eax,dword ptr [b]:将ptr[b]放到eax里去

push eaxeax入栈

mov eax,dword ptr [b]:将ptr[a]放到eax里去

push eaxeax入栈

注意,由上面的四条指令可以看出:虽然形参的顺序是先a后b,但是实际压入栈的顺序是先b后a

call  _Add (03410B9h) :调用函数Add,其中03410B9h是函数的地址。并且把call指令的下一条指令压入栈,使Add函数执行完后知道下一条该执行的指令。


现在来到Add函数里面:

可以发现前面部分跟在调用main函数的时候是相似的,即为Add函数创建栈并初始化。

要注意的时,现在的ebp,esp已经由维护main函数的栈帧变为维护Add函数,因为此时我们已经开始创建Add的栈帧了。

mov eax,dword ptr[x]:这里其实就是找到刚刚压入Add函数的值,即ptr[x]位置的eax,值为1

add eax,dword ptr[y]:将ptr[x]位置的eax,值为2,和prt[x]相加,得到3

mov dword ptr[z],eax把3放入eax,即得到z=3

从这里可以看出,当我们真正进入函数调用两个数相加时,形参根本不是在Add中创建的,而是在Add中找到刚刚调用函数时压入的空间所存放的数据,即图中所示的空间:

所以,这样就能很明确的知道:形参是实参的一份临时拷贝 

mov  eax,dword ptr [z]:将z的值放入eax中,因为z会随着函数的结束而被销毁,要想返回一个值需要用eax这样一个寄存器来保留,因为寄存器是不会随着函数的结束而被销毁的。


4. 函数栈帧的销毁

pop edi、pop esi、pop ebx:弹出edi,,esi,,ebx,同时每次弹出时esp也向高地址处移动

mov esp,ebp:将esp指向ebp的位置

pop ebp:弹出ebp,此时ebp回到main函数中ebp原本的位置,esp由于这一次pop也向高地址处移动1偏移量,指向刚刚保存call的下一条指令的位置,准备执行下一条指令。1

add esp,8:将esp向高地址处移动两个偏移量,此时用于保存之前压入Add函数的两个形参的eax就被释放了

mov dword ptr [c],eax:把刚刚保留c的那个eax复制给c


到这里整个过程就介绍的差不多了,从中我们可以的出许多结论比如:

1.释放栈帧所占用的内存空间,是通过移动栈帧指针,从而允许后续操作直接覆盖数据来实现的

2.函数调用后还能找到下一条执行的语句是因为在调用函数之前,当前函数的上下文需要被保存到栈中,以便在函数执行完毕后能够正确返回到调用函数。

3.函数传参时是将函数调用时传递的参数复制到栈帧中的相应位置,以便函数内部能够访问这些参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1531746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis 应用与原理(三)

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 Redis Cluster 解决方案 基础概念 首先&#xff0c;分析一下主从哨兵模式带来的问题&#xff1a; 在主从 哨兵的模式下&#xff0c;仍然只有一个 Master 节点&#xff0c;当并发请求较大时&#xff0c;哨兵…

config.properties的存放位置在Javaweb和Java工程中的区别

Java项目中&#xff1a;一般是与src平行的设置一个config目录&#xff0c;然后把配置文件放到config目录里面 Javaweb中&#xff1a;一般放到src目录下 顺便补习一下Properties的用法 package config;import java.io.FileInputStream; import java.io.FileOutputStream; impor…

JD商品详情原数据 API 返回值说明

一、应用场景 商品详情原数据API的应用场景广泛而多样。具体来说&#xff0c;它可以被用于以下方面&#xff1a; 1、电商平台数据分析&#xff1a;电商平台可以通过商品详情原数据API提取商品销售数据、质量评分、评论和反馈等信息&#xff0c;从而帮助用户更好地理解市场和竞…

QT charts模块画图

QT charts模块画图 在项目中使用Qt Charts模块,必须在项目的配置文件(.pro文件)添加行语句。 QT += core gui charts或者 QT += core gui QT += charts在需要使用QtCharts的类的头文件或源文件中,包含如下语句 #include <QWidget> #include &…

Java基础 学习笔记六

自增运算符 /* 自加1-- 自减11. 可以出现在变量前&#xff0c;也可以出现在变量后i 可以i 也可以像这种欲奴算符&#xff0c;只有一边有操作数&#xff0c;我们把这种运算符称为 一元运算符a b 这里的 两边有两个操作数&#xff0c;所以这种运算符被称为 二元运算符2. 无论出…

基于微信小程序的电影交流平台

技术&#xff1a;springbootmysqlvue 一、背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。所以各行业&#xff0c;尤其是规…

matlab中Signal Editor定义梯形信号输出矩形信号

matlab中Signal Editor定义梯形信号输出矩形信号&#xff0c;可以通过如下勾选差值数据实现梯形信号输出。

nginx学习记录-目录结构及基本配置

1. nginx目录结构 执行tree命令就可以看到nginx的目录结构了&#xff0c;主要有4个&#xff0c;分别是配置目录conf&#xff0c;还有界面目录html&#xff0c;日志目录logs以及程序sbin/nginx。 2. nignx基本配置 nginx的主要配置文件为/usr/local/nginx/conf/nginx.conf&…

网络协议与层次划分:探索计算机网络体系结构

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

关于继承是怎么样的?那当然是很好理解之

本文描述了关于继承的大部分知识&#xff0c;但是并不全&#xff0c;每篇博客之间的知识都有互串&#xff0c;所以需要把几篇文章合起来看&#xff0c;学会融会贯通&#xff01; 温馨提示&#xff1a;使用PC端观看&#xff0c;效果更佳&#xff01; 目录 1.继承是什么 2.什…

FREERTOS任务通知

从 v8.2.0 版本开始&#xff0c;FreeRTOS 新增了任务通知(Task Notifictions)这个功能&#xff0c;可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西。使用任务通知的话效率会更高。 有个疑惑&#xff1a; 队列是两个互通消息的任务之外的一个特性&#xff0c;而…

基于springboot+vue的中山社区医疗综合服务平台

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Vue.js+SpringBoot开发创意工坊双创管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…

【机器学习】科学库使用第2篇:机器学习概述,学习目标【附代码文档】

机器学习&#xff08;科学计算库&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习&#xff08;常用科学计算库的使用&#xff09;基础定位、目标&#xff0c;机器学习概述定位,目标,学习目标,学习目标。机器学习概述&#xff0c;1.3 人…

计算机设计大赛 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

初识HOOK框架frida

hook是什么 hook框架是一种技术&#xff0c;用于在运行时拦截和修改应用程序的行为&#xff0c;通过hook&#xff0c;可以劫持应用程序的方法调用、修改参数、篡改返回值等&#xff0c;以达到对应用程序的修改、增强或调试的目的。 常见的hook框架有哪些 Xposed Framework&am…

算法体系-11 第十一节:二叉树基本算法(上)

一 两链表相交 1.1 题目描述 给定两个可能有环也可能无环的单链表&#xff0c;头节点head1和head2。请实现一个函数&#xff0c;如果两个链表相交&#xff0c;请返回相交的 第一个节点。如果不相交&#xff0c;返回null 【要求】 如果两个链表长度之和为N&#xff0c;时间复杂…

什么是GPU云服务器?2024腾讯云GPU云服务器全解析!

腾讯云GPU服务器是提供GPU算力的弹性计算服务&#xff0c;腾讯云GPU服务器具有超强的并行计算能力&#xff0c;可用于深度学习训练、科学计算、图形图像处理、视频编解码等场景&#xff0c;腾讯云百科txybk.com整理腾讯云GPU服务器租用价格表、GPU实例优势、GPU解决方案、GPU软…

名词【语法笔记】

1.名词分为几大类 2.每一类&#xff0c;又有几个小类&#xff0c;以及所需要注意什么

python中字典相关知识点总结

1.字典的定义 字典&#xff1a;在Python中&#xff0c;字典是一系列键-值对。每个键都与一个值相关联&#xff0c;程序员可以通过键来访问与之相关联的值。 实际举例&#xff1a; student{name:xincun,age:18} 通过实例我们可以发现&#xff0c;键-值对是两个相关联的值。指…