C语言杂谈:函数栈帧,函数调用时到底发生了什么

        我们都知道在调用函数时,要为函数在栈上开辟空间,函数后续内容都会在栈帧空间中保存,如非静态局部变量,返回值等。这段空间就叫栈帧

        当函数调用,就会开辟栈帧空间,函数返回时,栈帧空间就会被释放。这里的释放并非清空,而是让其无效化,可以后续的使用。

1,用到的寄存器和汇编指令

1,相关寄存器

eax:保存临时数据,返回值

ebx:保存临时数据

ebp:栈底寄存器

esp:栈顶寄存器

eip:指令寄存器,保存当前指令的下一条指令的地址

2,相关汇编指令

call:函数调用

mov:数据转移

push:出栈指令

pop:入栈指令

sub:减法指令

add:加法指令

jump:修改eip,转入目标函数调用

ret:恢复返回地址

2,虚拟内存地址

除了这些指令和寄存器,我们也需要了解虚拟内存地址是什么样子的

简单来说,高地址向低地址存储的内容分别是:内核,栈(向下增长),共享库的内存映射区域,

堆(向上增长),数据区(未初始化的数据,已初始化的数据),代码区,以及不分配使用的部分

区域。

值得注意的时,栈区是向下增长的,堆区是向上增长的。

3,代码预览

    简单总结调用函数时,发生的行为:

1,先形参实例化,按照参数列表从右向左

2,保护现场//将函数返回地址压入栈,转入目标函数

3,执行函数体

4,释放局部变量的栈帧空间

5,恢复现场//获得函数返回地址,释放栈帧空间

6,继续后续主函数语句
 

下面是演示所用的c语言代码

#include<stdio.h>
int add(int a,int b)
{return a+b;    
}
int main()
{int a=10;int b=10;int c=0;c=add(a,b);return 0;
}

4,调用过程

使用vs2022,点击调试,打开反汇编,打开寄存器

A:主函数栈帧建立

首先我们要知道,主函数也是函数,也需要建立函数栈帧,它被_tmainCRTStartup函数调用,而_tmainCRTStartup又被mainCRTStartup函数调用,mainCRTStartup函数又是被操作系统所调用的。

00007FF7AD0618D0  push        rbp  
00007FF7AD0618D2  push        rdi  
00007FF7AD0618D3  sub         rsp,148h  
00007FF7AD0618DA  lea         rbp,[rsp+20h]  
00007FF7AD0618DF  lea         rcx,[__B782E998_栈帧@c (07FF7AD071008h)]  
00007FF7AD0618E6  call        __CheckForDebuggerJustMyCode (07FF7AD061370h)  

这些是主函数栈帧建立的汇编代码

我们暂且不管这些代码,去关注寄存器的变化,重点关注espebp寄存器

这是主函数栈帧建立前栈底寄存器和栈顶寄存器的位置

这是主函数栈帧建立后栈底寄存器和栈顶寄存器的位置

可以看到栈顶寄存器的数值减少了(D20-C2C)个字节,这就说明了我们栈是由高地址向低地址增长

的,具体的建立过程我们在add函数时介绍。

B:变量初始化

单击F10我们观察寄存器

EIP指向下一条要指向的指令地址,值为00C71985,正是int a=10;这条指令。

此时,栈内空间应该是这样的:

点击F10,将变量a入栈,因为栈是从低地址到高地址增加的,所以我们将内存监视器调到010FF778,观察前后变化。

点击前

点击后

我们可以发现,变量a成功入栈了,距离栈底寄存器所在位置向上偏移八个字节单位

,同理我们将变量b和c入栈

观察到同样入栈成功,这里变量b也是0a的原因是因为数值相同,编译器进行了处理。

现在主函数栈帧就添加了三个变量。

接下来就是调用函数给c赋值了,一共有七条指令,我们一个个来看。

首先是调用Add()前(即call指令前)的4条指令,我们可以看出前两条指令的作用是先将变量b的值移

动到eax寄存器,然后以压栈push的方式压入栈中,栈顶寄存器更新,先下增长。

这里两个临时变量的产生,就是我们所说的形参实例化。我们需要注意两个点,一个是这是在调用

函数前生成的,其次就是压栈顺序是形参列表从右向左。

接下来,我们将执行函数调用指令,因为我们是通过跳转指令修改eip寄存器转入目标函数地址,

Add函数调用结束后还需返回main函数执行后续代码,所以我们需要将下一条指令的地址先保存起

来,然后进行跳转。

因此这个指令分为两步:1.将返回地址压入栈中 2.转入目标函数。

点击F11进入函数,我们可以发现函数返回后的指令地址被压入栈中(010FF67C ),然后修改eip进行跳转,转入add()函数:

C:转入add函数

下面三条是栈帧建立过程

 首先是第一条指令,单击F10,将栈底寄存器的内容压入栈中,即把main函数栈底的地址压入栈中:

因为是压栈,所以栈顶寄存器向上偏移四个字节。

然后是第二条指令,单击F10,将栈顶寄存器的内容移动到栈底寄存器,使得栈顶寄存器和栈底寄存器指向同一个地址空间:

 最后是第三条指令,单击F10,将esp栈顶寄存器的内容减去0CCH,使其向低地址偏移0C0h个字节,如下:

至此,add函数栈帧建立完成。

建立的栈帧空间

之后的内容我们在之前都有过类似的,我们需要知道几点

1,retnru语句计算时,函数参数是从之前的临时变量处取得数值进行计算

2,计算结果存储在eax寄存器中

至此,ADD函数调用完毕,进入最后一步,栈帧释放。

D:add函数销毁

栈帧的销毁我们重点来谈后三条语句,前几条语句对应着前面栈帧创建时的初始化操作,进行设置,我们不去管。

首先是第一条mov命令,我们单击F10运行,ebp栈底寄存器的值赋给esp栈顶寄存器,此时ebp与esp指向同一个地址空间: 

在这时,理论来说我们就已经释放完成了,因为add函数的内存空间已经被覆盖了。

接下来就是恢复main函数栈帧的操作了。

        我们单击F10,执行下一条pop指令,将栈顶内容弹出并放入ebp栈底寄存器中,还记得我们

刚才栈顶放的是什么了吗,是main函数栈底地址,所以此时ebp重新指向main函数栈底。

同时esp栈顶寄存器的指向发生改变。

        之后执行ret指令,ret作用是恢复返回地址,压入eip,即把栈顶元素弹出到eip指令寄存器

中,改变下一条执行的指令。我们单击F10,发现返回到了main函数,此时eip的内容就是我们之

前保存的下一条main函数指令地址,esp栈顶寄存器发生改变:

之后执行main函数中的下一条add指令,将esp栈顶寄存器的值加8并存回esp栈顶寄存器,此时esp向下偏移8个字节,指向原main函数栈顶,释放临时变量的栈帧空间。

最后使用mov将值赋给c,打印,函数结束。

后面的printf函数也会建立栈帧,但类似,不再讨论。

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

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

相关文章

SpringBoot——整合Servlet的三大组件:过滤器(Filter)

目录 过滤器 一、用过滤器检查用户是否登录 LoginFilter自定义过滤器 FilterConfig配置类 FilterController控制器 SpringbootFilterApplication启动类 二、用过滤器统计资源访问量 LoginFilter FilterController 在开发SpringBoot项目时&#xff0c;开发人员经常需…

数据动态变化时实现多选及回显

<template><el-dialog title"设置权限" :visible.sync"showDialog" :close-on-click-modal"false" :append-to-body"true" width"800px"><div v-loading"loading"><el-radio-group v-model&…

Servlet实现会话追踪登录功能(结合JDBC)

目录 1.技术要求 2.关于会话Session 生活例子 代码体现 1.存储到session 2.从session中拿出 3.完成登录功能 4.利用Session作追踪 关于jstl应用 关于EL表达式应用 注意 5.测试 1.技术要求 核心&#xff1a; &#xff08;1&#xff09;Servlet项目的搭建 &#x…

C++---模板进阶(非类型模板参数,模板的特化,模板分离编译)

我们都学习和使用过模板&#xff0c;而这篇文章我们来将一些更深入的知识。在此之前&#xff0c;我们在使用C编程时可以看到模板是随处可见的&#xff0c;它能支持泛型编程。模板包括函数模板和类模板&#xff0c;我们有的人可能会说是模板函数和模板类&#xff0c;但严格讲这样…

Ripple:使用Wavelet Approximations来加速FHE的Programmable Bootstraps

1. 引言 University of Delaware和Nillion团队的 Charles Gouert、Mehmet Ugurbil、Dimitris Mouris、Miguel de Vega 和 Nektarios G. Tsoutsos&#xff0c;2024年论文《Ripple: Accelerating Programmable Bootstraps for FHE with Wavelet Approximations》&#xff0c;开源…

关于一些优化的知识

1、凸优化&#xff1a;一定可找到全局最优解 非凸优化&#xff1a;一般是局部最优解 2、无约束优化问题求解方法&#xff1a;梯度下降、拟牛顿法、高斯牛顿法、LM算法 3、 解释&#xff0c;就是右边的式子对应于就是当前这个xk这个点基础上朝着pk取走步长为a得到了对应的值&…

vscode运行命令报错:标记“”不是此版本中的有效语句分隔符。

1. 报错问题 标记“&&”不是此版本中的有效语句分隔符。 2. 解决办法 将 terminal 中的 owershell 改成 cmd 就 ok

To C道路越走越夯实,1688彻底变身了?

在偌大的电商市场&#xff0c;消费者都是专业的“掘宝者”&#xff0c;热衷于发现各种新奇商品和采购新通路。 拼多多、1688等平台也正是在这种情况下&#xff0c;成为消费市场的“宠儿”。其中&#xff0c;1688的发展路径较为独特&#xff0c;据天眼查&#xff0c;其为源头厂…

《python-配置》在ubuntu系统上安装pycham并破解

阿丹&#xff1a; 因为ai开发要使用ubuntu系统&#xff0c;整理和总结一下如何在这里安装pycham 官网下载&#xff1a;pycham下载地址 PyCharm: the Python IDE for data science and web development 官网操作流程&#xff1a; 1&#xff0c;点击下载 2、下载其他版本 3、…

如何理解与学习数学分析——第二部分——数学分析中的基本概念——第9章——可积性

第2 部分&#xff1a;数学分析中的基本概念 (Concepts in Analysis) 9. 可积性(Integrability) 本章讨论了可积性(integrability)的概念(它不同于积分过程)。研究了反导数(antiderivative&#xff0c;或称原函数)和函数图像下面积之间的关系&#xff0c;然后通过对面积的近似…

应用解析 | 面向智能网联汽车的产教融合解决方案

背景介绍 随着科技的飞速发展&#xff0c;智能网联汽车已成为汽车产业的新宠&#xff0c;引领着未来出行的潮流。然而&#xff0c;行业的高速发展也带来了对高素质技术技能人才的迫切需求。为满足这一需求&#xff0c;推动教育链、人才链与产业链、创新链的深度融合&#xff0…

文件加密软件排行榜前五名|好用的五款文件加密软件分享

你的公司是否存在这些问题&#xff1a; 数据泄露事件常有发生&#xff0c;数据安全的重要性日益凸显&#xff0c;而文件加密软件则是保护数据安全的重要工具。 市场上存在众多文件加密软件&#xff0c;每款都有其独特的特点和优势。 本文将为您分享五款好用的文件加密软件&…

针对多智能体协作框架的元编程——METAGPT

M ETA GPT: M ETA P ROGRAMMING FOR M ULTI -A GENT COLLABORATIVE F RAMEWORK 1.概述 现有的多智能体系统主要面临以下问题&#xff1a; 复杂性处理不足&#xff1a;传统的多智能体系统主要关注简单任务&#xff0c;对于复杂任务的处理能力有限&#xff0c;缺乏深入探索和…

C++中的priority_queue和deque以及适配器

C中的priority_queue和deque 一丶 priority_queue1.1 priority_queue的介绍1.2 priority_queue的使用1.3 priority_queue的模拟实现 二丶 deque2.1 deque的简单介绍2.2 deque的缺陷2.3 为什么要选择deque作为stack和queue的迭代器 三丶 容器适配器3.1 什么是适配器3.2 STL标准库…

GlaDS缘起

题目:Modeling channelized and distributed subglacial drainage in two dimensions 近年来,冰盖表面融化与冰盖动态之间的联系及其对海平面上升的影响引起了广泛关注。特别是格陵兰冰盖的研究显示,表面融水显著影响冰川移动速度,而冰下排水系统对冰川动力学及冰川水文学…

【WP】猿人学_13_入门级cookie

https://match.yuanrenxue.cn/match/13 抓包分析 抓包分析发现加密参数是cookie中有一个yuanrenxue_cookie 当cookie过期的时候&#xff0c;就会重新给match/13发包&#xff0c;这个包返回一段js代码&#xff0c;应该是生成cookie的 <script>document.cookie(y)(u)(a…

Edge工作区按钮消失了,又出现了

在edge的设置中的自定义工具栏处的显示工作区&#xff0c;打开&#xff0c;右上角就有一个工作区的标志然后就可以进入工作区了

产业,到底需要什么大模型?

[ 产业究竟需要怎样的大模型&#xff1f;关于这个问题&#xff0c;本文作者便提出了他的看法&#xff0c;并总结了产业大模型目前阶段的三点落地挑战。一起来看看&#xff0c;或许可以帮助你更好地理解大模型与行业、与产业的融合。 写下这篇的起因&#xff0c;是前不久的一件事…

[已解决]FinalShell连接CentOS失败:java.net.UnknownHostException: centos

报错&#xff1a; 解决办法&#xff1a; 1.查看Windows:C:\Windows\System32\drivers\etc\ 2.拷贝hosts文件&#xff0c;用记事本打开hosts文件 3.添加主机名centos及对应IP地址&#xff0c;保存并粘贴覆盖C:\Windows\System32\drivers\etc\中的hosts文件 4.打开cmd命令窗口输…

Mac下删除系统自带输入法ABC,正解!

一、背景说明 MacOS 在 14.2 以下的系统存在中文输入法 BUG&#xff0c;会造成系统卡顿&#xff0c;出现彩虹圆圈。如果为了解决这个问题&#xff0c;有两种方法&#xff1a; 升级到最新的 14.5 系统使用第三方输入法 在使用第三方输入法的时候&#xff0c;会发现系统自带的 …