从汇编指令看函数调用堆栈的详细过程

news2025/4/9 0:50:14

我们以下述代码为例来说明函数调用堆栈的详细过程

#include<iostream>

int sum(int a,int b)
{
	int temp=0;
	temp=a+b;
	return temp;
}

int main()
{
	int a=10;
	int b=20;

	int ret=sum(a,b);
	std::cout<<"ret:"<<ret<<std::endl;
	return 0;
}

接下来,我们逐行分析代码的执行

为局部变量分配空间

首先,当代码执行到main函数后,会为main函数开辟栈帧空间,需要说明的是

  • 栈这个数据结构需要两个指针来维护,分别是栈底指针和栈顶指针
  • 在x86结构里,负责存放栈底指针的寄存器是ebp,负责存放栈顶指针的寄存器是esp
  • 栈空间是向下增长的,故内存地址随着栈帧的开辟会减小 

如下所示,刚开始时,系统在内存中为main开辟的栈帧空间

 

当执行到以下代码时,系统会为变量a和变量b开辟栈帧,同时对其进行初始化

	int a=10;
	int b=20;

汇编指令为

mov dword ptr[ebp-4],0Ah
mov dword ptr[ebp-8],14h

 其中,int a=10;这段代码对应的汇编指令解释如下

  • dword ptr,表示操作一个双字(也就是四个字节)的数据
  • [ebp-4],表示以 ebp 寄存器为基址,偏移 -4 个字节的内存地址。因为栈是向下生长的,所以 -4 表示当前栈帧中的一个局部变量或者其他数据存储位置,通常是相对于栈顶的位置。
  • 0Ah,十进制数字10的十六进制表示
  • mov,移动指令
    故这段代码中表示,将值 10 存储到当前函数栈帧存储位置的前 4 个字节中。

此时,内存空间的栈帧情况如下所示

函数调用

准备工作

接下来,当执行到这段代码时,系统会做以下几件事情

int ret=sum(a,b);
  •  为局部变量ret开辟栈帧空间
  • 为形参变量a和b开辟栈帧空间
  • 调用sum函数

1.为局部变量ret开辟栈帧

 

2.为形参变量开辟栈帧

需要说明的是,在为形参变量开辟栈帧空间时,是从右往左进行开辟的,也就是说是先开辟形参b的空间再开辟形参a的空间

压入形参b的汇编指令为

mov eax,dword ptr[ebp-8];从内存中取出变量b(内存地址为ebp-8)的数据,放到寄存器eax中
push eax;将取出的形参b的数据压入栈中

同理,压入形参a的汇编指令为

mov eax,dword[ebp-4]
push eax

此时内存空间的状态为

3.调用函数sum

该过程会使用汇编指令call调用函数sum,而在进入函数sum内部之前,call指令会进行一些准备工作

  • 保存下一条指令的地址,也就是将下一条指令的地址压入栈中
  • 保存函数调用前的上下文环境

(1)首先将下一条指令的地址压入栈中

由于系统为形参变量分配了内存空间,而当函数调用结束后会回收这块内存空间,因此下一条指令就是回收函数形参变量内存空间的指令,如下所示,就是将栈顶指针esp“增加四个字节的偏移”(栈是向下增长的,开辟栈空间是esp减去偏移,回收栈空间时esp增加偏移)

(2)保存上下文环境

在这里所谓的保存上下文环境,就是保存main函数栈帧空间的ebp值(栈的栈底地址)

因为进入sum函数后,会为sum函数开辟单独的栈空间,因此ebp值会被覆盖,而为了要在sum函数调用结束后回到main函数的栈空间,就需要将此时的ebp值进行保存,如下所示

之后,将ebp(栈低地址)移动到esp的位置,并移动esp(栈顶指针)为sum函数开辟栈帧空间,如下所示

该过程的汇编过程为

push ebp
mov ebp,esp
sub esp,4Ch

值得说明的是,该过程也就是sum函数的大括号里左括号 { 的作用 

进入函数内部

当系统为sum函数开辟完栈帧空间之后,就已经进入sum函数内部了,接下来就在sum函数这个栈帧空间里执行sum函数的代码

int temp=0;

首先,上述这段代码的汇编指令为

mov dword ptr[ebp-4],0

如下所示,内存空间的状态为

temp=a+b;

同理,这段代码的汇编过程为

mov eax,dword ptr[ebp+0Ch];取出形参a的值,放入到寄存器eax中
add eax,dword ptr[ebp+8];取出形参b的值,并与形参a的值(在寄存器eax)相加,并将相加后的结果放到eax中
mov dword ptr[ebp-4],eax;将运算结果赋值为temp

此时,内存空间的状态为 

 

接下来,执行这段代码

return temp;

该过程为函数返回,这段代码的汇编结果是将temp的值保存到寄存器eax中,即

mov eax,dword ptr[ebp-4]

接下来,就要开始回收栈帧空间

栈帧空间回收

1.首先,直接回退栈顶指针esp到ebp,汇编指令为

mov esp,ebp

此时内存空间的状态为

需要说明的是,该过程并没有清空sum函数栈帧空间的内容,也就是说,此时仍旧可以访问到函数内部的局部变量的值,但是如果在sum函数回退之后还有其他函数的执行,则必然会重新开辟栈帧空间,此时就会把sum函数的局部变量的值给覆盖掉

这也是为什么不建议返回一个局部指针和局部引用的原因,因为指针和引用类型的局部变量并不是按值返回的,也就是说返回时并不进行拷贝,这样就会很可能就会访问一个非法空间

2.接下来,系统会弹出栈顶值,而从图中可以看到,此时栈顶指针esp指向的值是进入sum函数前保存的main的栈底地址,因此,该过程会让ebp重新回退到main的栈底 

该过程的汇编指令为

pop ebp

此时,内存空间的状态为

需要说明的是,该过程也就是sum函数代码里右括号 } 的作用,即

mov esp,ebp
pop ebp

3.接下来,系统会调用ret指令

ret指令的作用是将此时栈顶指针的内容赋值为IP寄存器,由图我们知道,此时栈顶指针esp保存的是进入sum函数前下一条指令的地址,而IP寄存器的作用就是指向下一条需要执行的指令的地址

此时状态为

 

由图我们可以看到,上述指令的执行结果是回收main函数分配的形参变量空间,因此执行结束后,内存空间的状态为

至此,sum函数的栈帧空间就已经退出了

接下来,系统会执行以下指令,将函数的执行结果(此前返回时保存在寄存器eax中)返回给ret

mov dword ptr[ebp-0Ch],eax

 即

至此,整个的函数调用的堆栈过程就结束了 

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

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

相关文章

粒子群优化算法PSO与鹈鹕优化算法(POA)求解无人机三维路径规划(MATLAB代码)

一、无人机路径规划模型介绍 二、算法介绍 close all clear clc dbstop if all error warning (off) global model model CreateModel(); % 创建模型 FF1; [Xmin,Xmax,dim,fobj] fun_info(F);%获取函数信息 pop100;%种群大小(可以自己修改) maxgen100;%最大迭代次数(可以自己…

电商数据采集的网页抓取数据、淘宝、天猫、京东等平台的电商数据抓取|电商数据API接口网页爬虫、采集网站数据

电商数据采集的网页抓取数据、淘宝、天猫、京东等平台的电商数据抓取&#xff0c;网页爬虫、采集网站数据、网页数据采集软件、python爬虫、HTM网页提取、APP数据抓包、APP数据采集、一站式网站采集技术、BI数据的数据分析、数据标注等成为大数据发展中的热门技术关键词。那么电…

以太网数据量大小字符串生成方法(可变单位)

0 前言 当我们想显示以太网数据量大小时&#xff0c;往往有个头疼的单位需要处理&#xff0c;单位取小了不一目了然&#xff0c;单位取大了精度太低。本例设计一个函数&#xff0c;将根据以太网数据量大小自动生成单位可变的字符串&#xff08;KB、MB、GB、TB、PB&#xff09;…

CSS之固定定位、相对定位、绝对定位

一、相对定位 相对元素自身所在的原来的位置进行定位&#xff0c;可以设置 left&#xff0c;right&#xff0c;top&#xff0c;bottom四个属性。 效果&#xff1a;在进行相对定位以后&#xff0c;元素原来所在的位置被保留了&#xff0c;既保留占位&#xff0c;其他元素的位置…

软件全周期检查单

1、立项阶段 2、计划阶段 3、需求阶段 4、设计阶段 5、编码集成阶段 6、测试阶段 7、交付阶段 8、结项阶段 软件全套资料包获取进主页或本文末个人名片直接获取。

Bezier曲线的绘制 matlab

式中&#xff1a; 称为基函数。 。 因为n表示次数&#xff0c;点数为n1&#xff0c;显然i表示第i个控制点。 显然在Matlab中可以同矩阵的形式来计算C(u)。 关键代码为&#xff1a; clc clear % 假设控制点P取值为&#xff1a; P [4,7;13,12;19,4;25,12;30,3]; % 因此&a…

5 个让日常编码更简单的 Python 库

今天我们一起来研究一些非常有用的第三方模块&#xff0c;可以使得我们的日常编码变得更加简单方便 sh https://github.com/amoffat/sh 如果曾经在 Python 中使用过 subprocess 库&#xff0c;那么我们很有可能对它感到失望&#xff0c;它不是最直观的库&#xff0c;可能还有些…

C语言中局部变量和全局变量是否可以重名?为什么?

可以重名 在C语言中, 局部变量指的是定义在函数内的变量, 全局变量指的是定义在函数外的变量 他们在程序中的使用方法是不同的, 当重名时, 局部变量在其所在的作用域内具有更高的优先级, 会覆盖或者说隐藏同名的全局变量 具体来说: 局部变量的生命周期只在函数内部,如果出了…

mars3d.MaterialType.Image2修改配置面状:图片2的speed数值实现动画效果说明

摘要&#xff1a; mars3d.MaterialType.Image2修改配置面状&#xff1a;图片2的speed数值实现动画效果说明 前提&#xff1a; 1.在示例中&#xff0c;尝试给mars3d.MaterialType.Image2材质的图片加上speed参数&#xff0c;实现动画效果&#xff0c;但是没有看到流动效果说明…

酷漫熊,最好用的漫画工具,资源全,支持下载,全部免费!

hi&#xff0c;大家好我是技术苟&#xff0c;每周准时上线为你带来实用黑科技&#xff01;由于公众号改版&#xff0c;现在的公众号消息已经不再按照时间顺序排送了。因此小伙伴们就很容易错过精彩内容。喜欢黑科技的小伙伴&#xff0c;可以将黑科技百科公众号设为标星&#xf…

互联网轻量级框架整合之MyBatis核心组件

在看本篇内容之前&#xff0c;最好先理解一下Hibernate和MyBatis的本质区别&#xff0c;这篇Hibernate和MyBatis使用对比实例做了实际的代码级对比&#xff0c;而MyBatis作为更适合互联网产品的持久层首选必定有必然的原因 MyBatis核心组件 MyBatis能够成为数据持久层首选框&a…

中国移动传关停8元保号套餐?或是5G成本带来的压力所致

日前有网友发现希望使用中国移动的保号套餐&#xff0c;却发现已无法办理&#xff0c;媒体对此多有报道&#xff0c;这意味着中国移动的套餐业务发生了重大变动&#xff0c;如此做或许在于5G成本上涨带来的压力促使它不得不提高套餐的门槛。 中国移动已建成最多的5G基站&#x…

世界各国柴油价格22.7统计

数据详情介绍&#xff1a; 统计时间为2022年7月4日。在该月份&#xff0c;全球柴油的平均价格为每升1.43美元。然而&#xff0c;各国间存在明显的价格差异。一般而言&#xff0c;西欧等发达国家的价格基本在每升2美元以上&#xff1b;相反&#xff0c;像伊朗、委内瑞拉、利比亚…

基于springboot实现视频网站管理系统【项目源码+论文说明】计算机毕业设计

基于springboot实现视频网站管理系统演示 摘要 使用旧方法对视频信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在视频信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问…

【信号与系统 - 8】取样定理

1 定义 取样处理就是对连续信号的离散化处理 p ( t ) p(t) p(t) 是开关函数 f s ( t ) f ( t ) ⋅ p ( t ) f_s(t)f(t)\cdot p(t) fs​(t)f(t)⋅p(t) 当 p ( t ) p(t) p(t) 为周期矩形函数时 该取样为均匀抽样&#xff0c;周期为 T s T_s Ts​&#xff0c;则取样角频率为&…

Python快速获取编程问题答案的方法库之howdoi使用详解

概要 howdoi是一个命令行工具,它提供了一种快速获取编程问题答案的方法,通过搜索和抓取Stack Overflow等网站的内容,直接在终端中显示编程问题的解决方案。 安装 通过pip可以轻松安装howdoi: pip install howdoi特性 快速访问编程解决方案:无需手动浏览Stack Overflow。…

AI大模型探索之路-实战篇:基于CVP架构-企业级知识库实战落地

目录 前言 一、概述 二、本地知识库需求分析 1. 知识库场景分析 2. 知识库应用特点 3. 知识库核心功能 三、本地知识库架构设计 1. RAG架构分析 2. 大模型方案选型 3. 应用技术架构选型 4. 向量数据库选型 5. 模型选型 三、本地知识库RAG评估 四、本地知识库代码落地 1. 文件…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果 一、简单介绍 二、简单动态聚光灯效果实现原理 三、简单动态聚光灯效果…

【数据结构】树与森林(树的存储结构、森林与二叉树的转化、树与森林的遍历)

目录 树和森林树的存储结构一、树的双亲表示法&#xff1a;二、树的孩子表示法方法一&#xff1a;定长结点的多重链表方法二&#xff1a;不定长结点的多重链表方法三&#xff1a;孩子单链表表示法 三、树的二叉链表(孩子-兄弟)存储表示法 森林与二叉树的转换树和森林的遍历先根…

回溯算法练习day.1

回溯算法 回溯法的作用 递归函数与回溯算法是相辅相成的&#xff0c;回溯法往往在递归函数的“下面” 使用原因&#xff1a;有些问题无法暴力进行搜索&#xff0c;只能通过回溯法来解决&#xff0c;例如 1.组合问题 2.切割问题 3.子集问题 4.排列问题 5.棋盘问题 回溯算法是一…