【函数栈帧解析:代码的迷人堆积和无限嵌套】

news2024/11/25 13:36:52

本章重点

一、何为函数栈帧

二、函数栈帧特性 - 同栈 - 后进先出

三、认识内存空间布局图

四、认识相关寄存器

五、认识相关汇编命令

六、测试代码:

七、函数栈帧全过程

要解决的问题​​​​​​​

  • 局部变量是怎么创建的?
  • 为什么局部变量的值是随机值?
  • 函数是怎么传参的?传参的顺序是怎么样的?
  • 形参和实参是什么关系?
  • 函数调用是怎么做的?
  • 函数调用结束后怎么返回的?

一、何为函数栈帧

        函数栈帧(Function Stack Frame),也被称为调用栈帧(Call Stack Frame),是在计算机程序中用于管理函数调用和执行的一种数据结构。每当函数被调用时,都会创建一个新的函数栈帧,用于存储该函数的局部变量、参数、返回地址和其他执行相关的信息。当函数执行完毕或返回时,相应的函数栈帧将被销毁,控制权回到上一个函数的栈帧中。

二、函数栈帧特性 - 同栈 - 后进先出

        函数栈帧的管理遵循一种后进先出(Last-In, First-Out,LIFO)的原则。这意味着最后调用的函数的栈帧会首先被执行,然后在函数返回时销毁,程序控制权回到上一个函数的栈帧中,以此类推,直到回到主程序的栈帧,整个程序执行完毕。

三、认识内存空间布局图

  1. 栈(Stack)

    • 栈是一种线性数据结构,用于存储函数调用时的局部变量、函数参数以及函数调用的返回地址。
    • 栈内存是有限的,以栈帧的方式分配和释放,遵循后进先出(Last-In, First-Out,LIFO)原则。
    • 栈内存的生命周期与函数调用关联,当函数返回时,其栈帧上的数据会被销毁。
  2. 堆(Heap)

    • 堆是一块较大的、动态分配的内存区域,用于存储程序运行时动态分配的数据,如动态分配的对象和数组。
    • 堆内存的生命周期不受函数调用的影响,需要手动分配和释放,否则可能导致内存泄漏。
    • 在C中,通常使用malloc()calloc()realloc()等函数来分配堆内存,使用free()来释放堆内存。
  3. 全局变量区(Global Variables)

    • 全局变量区存储程序中的全局变量,这些变量在整个程序的生命周期内都可访问。
    • 全局变量在程序启动时被分配,在程序结束时被释放。
  4. 常量区(Constants)

    • 常量区存储常量数据,如字符串文字和全局常量。
    • 这些数据在程序运行期间是只读的。
  5. 代码区(Code)

    • 代码区存储程序的二进制代码,包括所有函数的机器代码。
    • 代码区通常是只读的,不允许修改程序代码。

四、认识相关寄存器

注:ebp和esp主要用于维护当前存在的这个函数栈帧。

问:函数是被调用的,那main函数呢???它是谁调用的???

        在VS2013,main函数也是被其他函数调用的,该函数是_tmainCRTStartup,而该函数又是mainCRTStartup函数调用的,而mainCRTStartup函数则是由操作系统调用的。所以从编程者的角度来看,main函数似乎是程序的入口点,但实际上,在特定的编程环境中,它是由启动代码调用的。这些启动代码负责设置程序环境并确保main函数能够正确执行。

五、认识相关汇编命令

  • mov:数据转移指令
  • push:数据入栈,同时esp栈顶寄存器也要发生改变
  • pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变
  • sub:减法命令
  • add:加法命令
  • call:函数调用,1. 压入返回地址 2. 转入目标函数
  • jump:通过修改eip,转入目标函数,进行调用
  • ret:恢复返回地址,压入eip,类似pop eip命令
  • lea:将表达式addr的值放入寄存器

六、测试代码:

#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;
}

七、函数栈帧全过程

1.ebp寄存器push压栈,同时esp栈顶寄存器地址值改变 - 变小

2.ebp寄存器数据转移到esp寄存器

3.0E4h的十进制是288,sub减法指令,此时开始创建main函数栈帧,main函数此时空间大小就是ebp寄存器-esp寄存器的差 = 0E4h

4.ebx寄存器,esi寄存器和edi寄存器push压栈,同时esp栈顶寄存器地址值改变 - 变小

5. 将表达式ebp-24h的值放入edi寄存器

6.word一个字两个字节,dword表示双字四个字节,刚好表示一个整型变量的大小。move将表达式9移入到ecx寄存器中,代表重复的次数,move将表达式CCCCCCCCh移入eax寄存器中,代表数值。rep stos就是重复执行stos指令,stos指令将eax中的值拷贝到ES:EDI指向的地址,所以这串指令就是在main函数中找到9个连续的4字节空间,将其值设置为CCCCCCCCh。

7.局部变量a,b,c开始创建,并进行初始化

8.函数传参过程,传参过程仍然是在main函数,且传参的过程是从右到左,先传y,后传x。

9.call函数调用,1. 压入返回地址 00682297,方便函数调用后返回到main函数栈帧,2. 转入目标Add函数

10.Add函数栈帧形成,这个过程同mian函数栈帧形成的过程相同,唯一的区别是在Add函数中找到3个连续的4字节空间,将其值设置为CCCCCCCCh。

11.变量z创建,并被初始化为0.

12.将地址为ebp+8放到eax寄存器中,然后在将ebp+14h的值与eax寄存器之前存放的值相加放到eax寄存器中,再将eax寄存器的值放到ebp-8处,也就是z变量地址处。

13.将运算的结果放到寄存器中,由于变量z是局部变量,出了函数作用域就会被销毁,为了能顺利带回返回值,利用寄存器不会被销毁的特点,将运算的结果放到eax寄存器。

14.pop数据弹出至指定位置,同时esp栈顶寄存器也要发生改变,Add函数栈帧被释放。

15.ret是恢复返回地址,找到call指令压入的地址,返回到main函数栈帧。

16.局部变量被销毁,变量c接收返回值

17.后面就是main函数的栈帧销毁过程,同Add函数相同

要解决的问题​​​​​​​

  • 局部变量是怎么创建的?

        在栈帧中,会分配一块内存空间来存储函数的局部变量。这些局部变量是在函数内部定义的,只在函数的生命周期内可见。编译器会根据函数的局部变量声明来确定需要分配多少内存空间。

  • 为什么局部变量的值是随机值?

        局部变量的值可能会被认为是随机的主要是因为在栈帧创建过程中,这些变量并没有经过显式的初始化。当函数栈帧被分配内存并为局部变量分配空间时,这些变量的内容实际上是未定义的,vs编译器会自动为其初始化为0xcccccc。

  • 函数是怎么传参的?传参的顺序是怎么样的?

函数传参的过程,形参的实例化并不在新的函数栈帧内,而是在调用一方函数栈帧内实例化的,当该函数要使用该形参的时候,是通过地址的方法去寻找该形参变量,传参的顺序是从右到左。

  • 形参和实参是什么关系?

        当调用一个函数时,实参的值被传递给函数的形参。这发生在函数的栈帧创建阶段。形参在函数内部被视为局部变量,并且其值被初始化为相应的实参值。但是实参的地址和形参的地址是不同的,所以形参只是实参的一份临时拷贝,修改形参是不能改变实参的。

  • 函数调用是怎么做的?

        函数栈帧通过call指令先1. 压入返回地址 ,也就是调用完函数后要执行的下一条指令,然后call通过jump转入目标函数,待函数使用完,ret指令会找到call指令压入的地址值,通过这个值返回到main函数的栈帧,即调用完函数要执行的下一条指令。

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

        利用寄存器的值不会随着函数栈帧被销毁而被销毁的特点,利用寄存器将值返回。

​​​​​​​

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

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

相关文章

10项必备的IT国际认证

10项必备国际IT认证对于希望在数字时代提升职业生涯的专业人士来说&#xff0c;已成为一项重要资产。 此类认证不仅肯定了你在特定IT领域的专业知识&#xff0c;还展现了你会在以后的生涯中不断学习和专业成长的决心。为了帮助你查询这些选择&#xff0c;我们编制了一份2023年…

华为OD机试 - 租车骑绿道 - 双指针(Java 2023 B卷 100分)

目录 一、题目描述二、输入描述三、输出描述四、解题思路1、输入2、输出3、说明4、双指针算法 五、Java算法源码六、效果展示 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 一、题目描述 部门组织绿岛骑行团建活动&#xff0c;租用公共双人自行车骑行&#xff0c;…

装箱、拆箱

装箱&#xff1a;将基本类型用它们对应的引用类型包装起来&#xff1b;拆箱&#xff1a;将包装类型转换为基本数据类型&#xff1b; Java 可以自动对基本数据类型和它们的包装类进行装箱和拆箱。 为什么要有包装器类型 因为java的三种集合&#xff0c;List、Set、Map&#xf…

【python零基础入门学习】python基础篇之判断与for循环(二)

本站以分享各种运维经验和运维所需要的技能为主 《python》&#xff1a;python零基础入门学习 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8》暂未更新 《docker学习》暂未更新 《ceph学习》ceph日常问题解…

iTOP-RK3588开发板Android12 设置系统默认不休眠

修改文件&#xff1a; device/rockchip/rk3588/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults. xml 文件&#xff0c;如下图所示&#xff1a; - <integer name"def_screen_off_timeout">60000</integer> <integer name&q…

电子相册制作新技巧,让你惊叹不已!

​近年来&#xff0c;随着科技的不断进步&#xff0c;电子相册制作已经成为了一种流行的趋势。无论是记录旅行的美好瞬间&#xff0c;还是展示生活中的点滴幸福&#xff0c;电子相册都能够将这些珍贵的回忆永久保存下来。 在我们制作电子相册之前&#xff0c;我们需要选择一款专…

QQ邮件营销

邮件营销效果好的莫过于QQ邮件营销&#xff0c;QQ邮件收件会自动弹窗提示&#xff0c;邮件的阅读率是所有目前邮箱中最高的&#xff0c;而QQ邮件规则使用的叶贝思反垃圾邮件算法会有效防止一般的群发邮件&#xff0c;一米智能QQ邮件营销系统针对性的解决了这个难题。另外我们对…

00. 深入编程原理系列文章前言

名称的含义 为什么要用《从0到1&#xff0c;第一行代码》这个名字&#xff0c;有两重含义&#xff1a; 有一本很著名的书&#xff0c;就叫《从0到1》&#xff0c;表示从无到有的意思&#xff0c;这里也叫从0到1&#xff0c;表示代码到底怎么来的&#xff0c;程序到底是怎么运行…

Java 数据库改了一个字段, 前端传值后端接收为null问题解决

前端传值后端为null的原因可能有很多种&#xff0c;我遇到一个问题是&#xff0c;数据库修改了一个字段&#xff0c;前端传值了&#xff0c;但是后台一直接收为null值&#xff0c; 原因排查&#xff1a; 1、字段没有匹配上&#xff0c;数据库字段和前端字段传值不一致 2、大…

事前规划,事半功倍!与大家聊聊项目管理的重要性

大家好&#xff0c;我是你们的小米&#xff01;希望大家都过得开开心心&#xff0c;工作顺利&#xff0c;生活美满。今天我要和大家分享一个让我深有感触的话题——项目管理中的事前规划&#xff0c;以及它所带来的重要性。就在昨晚&#xff0c;我经历了一次让人啼笑皆非的经历…

数据通信——DHCP中继

一&#xff0c;实验背景 之前不是用DHCP来分配IP地址么&#xff01;现在该公司在核心交换机旁挂了一个专用的 DHCP Server 来为终端分配IP地址&#xff0c;那么现在你就要改下配置了&#xff0c;用DHCP中继完成IP分配。 中继的好处就是&#xff0c;我们仅需在中继上配好DHCP所需…

HarmonyOS扫码服务,应用服务一扫直达打造系统级流量新入口

二维码如今是移动应用流量入口以及功能实现的重要工具&#xff0c;也是各App的流量入口&#xff0c;是物、人、服务的连接器&#xff0c;通过扫码我们可以更便捷的生活&#xff0c;更高效的进行信息交互&#xff0c;包括信息的发布、信息的获取。 在日常扫码过程中&#xff0c…

机器学习面试的12个基础问题

毕业季找工作了&#xff1f;如果想应聘机器学习工程师岗位&#xff0c;你可能会遇到技术面试&#xff0c;这是面试官掂量你对技术的真正理解的时候&#xff0c;所以还是相当重要的。近日&#xff0c;JP Tech 发表了一篇文章&#xff0c;介绍了他们面试新人时可能会提出的 12 个…

Android 动画之插值器PathInterpolator

Android 的View动画、属性动画都可以设置动画插值器&#xff0c;以此来实现不同的动画效果。 这篇文章 Android View动画整理 有介绍各种插值器的效果&#xff0c;这一篇专访 PathInterpolator 。 参考官网 添加曲线动作 &#xff0c; PathInterpolator 基于 贝塞尔曲线 或 …

cocos 2.4 版本 设置物理引擎步长 解决帧数不一致的设备 物理表现不一致问题 设置帧刷新率

官网地址Cocos Creator 3.8 手册 - 2D 物理系统 官网好像写的不太对 下面是我自己运行好使的 PhysicsManager.openPhysicsSystem()var manager cc.director.getPhysicsManager();// 开启物理步长的设置manager.enabledAccumulator true;// cc.PhysicsManagercc.PhysicsManag…

MacBookPro重装系统图文教程

关机 长按电源按钮10s即可强制关机 快捷键选择 Intel Command-R&#xff1a;获得安装过的最新的 macOS&#xff0c;但不会升级到最高版Option-Command-R&#xff1a;获得与 Mac 兼容的最新版 macOSShift-Option-Command-R&#xff1a;获得 Mac 自带的 macOS 或者与它最接近且…

pycharm安装各种包,包括scipy,pulp方法

方法1 在终端输入pip install scipy&#xff0c;然后就会开始下载&#xff0c;可能下载速度不是很快。另外&#xff0c;如果pip没有更新的话&#xff0c;也会影响&#xff0c;你需要在终端输入 python -m pip install --upgrade pip来更新 方法二 在 点击加号后&#xff…

idea解决maven打包不存在报错

maven打包失败 方法一方法二方法三 方法一 删除~/.m2/repository/对应目录或目录下的*.lastUpdated文件&#xff0c;然后再次运行maven命令 方法二 maven命令后加-U&#xff0c;如mvn package -U 方法三

社恐人福音!皮雀app以兴趣为链接,打造陌生人社交新模式

新一代年轻人被各种生活、工作和强社交关系充斥&#xff0c;面临着巨大的社交压力&#xff0c;因此他们在社交的选择方向上&#xff0c;逐渐远离线下社交&#xff0c;去选择线上社交&#xff0c;不同于有心理负担的线下社交&#xff0c;线上社交具有更多的选择性。基于能为年轻…

各种排序算法性能对比

C数据结构与算法 目录 冒泡排序 ​ 插入排序 ​ 选择排序 ​ 上图中最后一列为&#xff1a;nn*(n-1)/2 ​