【C语言】——函数栈帧的创建与销毁

news2024/11/25 12:49:05

函数栈帧的创建与销毁

本文主要讲解了函数调用过程中其栈帧的创建与销毁,内容干货较多,希望大家认真品味。

使用C语言进行函数调用时,是否会有很多疑问:
1.局部变量是如何创建的?
2.局部变量在未初始化的情况下,其值为什么会是随机值?
3.函数是如何进行传参的?
4.函数在传参的过程中顺序是怎样的?
5.形参和实参是什么关系?
6.函数调用是如何实现的?
7.函数在调用结束后如何返回的?

这些问题应该都困扰大家许久,本文应该会给大家提供些许思路!

在进行讲解之前,大家应该都会了解C语言的一个关键字register——寄存器: 【关键字】——register在C语言中的使用,寄存器中有eax,ebx,ecx,edx,ebp,esp等。

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

每一次的函数调用都会在栈区开创一个空间(包括main函数)。

#include<stdio.h>
int add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}
int main(void)
{
	int a = 10;
	int b = 20;
	int ret = 0;

	ret = add(a, b);

	return 0;
}

在这里我们使用vs2022来观察函数栈帧的创建与销毁。

同时,本次调试的环境是X86环境

在这里插入图片描述

  • 将代码转为反汇编

在这里插入图片描述

  • 打开监视、调用堆栈、内存方便观察

在这里插入图片描述

  • 转为反汇编

在这里插入图片描述

在函数调用开始前,我们应该了解到main函数也是被其他函数调用的,这点在vs2022中没有体现

在这里插入图片描述

main函数是被__mainCRTStartup函数调用的,__mainCRTStartup函数是被mainCRTStartup函数调用的。

esp与ebp俩个寄存器是用来维护函数栈帧的俩个寄存器。

在这里插入图片描述
首先执行第一条汇编代码:push ebp

push——压栈,即从栈顶存放一个数据
pop——出栈,即从栈顶拿出一个数据

在这里插入图片描述

此时,将epb的地址存放在__mainCRTStartup函数顶部,移动寄存器esp

在这里插入图片描述

执行下一条汇编代码:move ebp,esp

move——即将后面的值赋给前面

在这里插入图片描述
此时,将esp的地址赋予ebp,二者指向同一地址

在这里插入图片描述
下一个汇编代码:sub sep,0E4h

sub——即submit,将前面的数据减去后面数据
0E4h——E4个字节,即228个字节

在这里插入图片描述
此时,将寄存器esp向上移动228个字节

在这里插入图片描述

下面三条汇编代码:
push ebx
push esi
push edi
即将ebx,esi,edi三个寄存器压栈

在这里插入图片描述

此时,将ebx,esi,edi三个寄存器的地址放入顶部

在这里插入图片描述

下面一条汇编代码:lea edi,[ebp-24h]
lea——load effective address即加载有效地址
将[ebp-24h]的地址加载到edi寄存器上

在这里插入图片描述

此时,处于栈区的edi记录了ebp-24h的地址
在这里插入图片描述
ebp-24h的地址为:0x0095FAEC

在这里插入图片描述

下面一条汇编代码:mov ecx,9
move——将后面的值赋给前面,即将9保存在寄存器ecx中

在这里插入图片描述
该寄存器的地址未保存在栈,这里阐述一下,将寄存器压栈,即保存寄存器的地址,然后改变寄存器内部数据是不影响寄存器在栈地址的保存的,如果了解指针的话,对这里的认知应该会更加清晰的。

在这里插入图片描述
下一条汇编代码:move eax,0CCCCCCCCh
将0CCCCCCCCh移动正在eax寄存器中

在这里插入图片描述
此时,将0CCCCCCCCh移动到寄存器中

在这里插入图片描述
下一条汇编代码:rep stos dword ptr es:[edi]
rep——repeat重复操作
stos——store string 存储字符串
rep stos——重复存储字符串操作
dword——double word双字,即四个字节
ptr——pointer指针
即用指针找到edi上存储的[ebp-24h],将[ebp-24h]下面的9个dword,即9个四个字节的数字初始化为0CCCCCCCCh.

在这里插入图片描述
由于画图面积有限,画出初始化部分0CCCCCCCCh.

在这里插入图片描述
可以在内存窗口看见初始化部分。

在这里插入图片描述
下一条汇编代码:call 00CA1320
call——跳转到子程序的地址
此时,表明已经创建好一个函数,即main函数已经创建完成,通过call一个地址,进入此函数中

在这里插入图片描述
下一条汇编代码:mov dword ptr [ebp-8],0Ah
0Ah——转为十进制为10
通过一个指针找到[ebp-8]的地址,将0Ah的值放入该地址

在这里插入图片描述

此时,在栈区存储局部变量0Ah

在这里插入图片描述
通过地址可以查看到[ebp-8]这个地址的存储值

在这里插入图片描述
下一条汇编代码:mov dword ptr [ebp-14h],14h
14h——转为十进制为20
通过一个指针找到[ebp-14h]的地址,将14h的值放入该地址

在这里插入图片描述
此时,在栈区存储局部变量014h

在这里插入图片描述
通过地址可以查看到[ebp-14h]这个地址的存储值

在这里插入图片描述
下一条汇编代码:mov dword ptr [ebp-20h],0
通过一个指针找到[ebp-20h]的地址,将0的值放入该地址

在这里插入图片描述
此时,在栈区存储局部变量0

在这里插入图片描述

通过地址可以查看到[ebp-20h]这个地址的存储值

在这里插入图片描述

下一条汇编代码:mov eax,dword ptr [ebp-14h]
将[ebp-14h]这个地址保存的【值】保存在eax寄存器中

在这里插入图片描述

此时,寄存器eax中保存[ebp-14h]中的值

在这里插入图片描述
下一条汇编代码:push eax
将寄存器eax的地址压栈

在这里插入图片描述
此次行动可以称为传参。

在这里插入图片描述
可以通过监视器观察到,寄存器中存的是20这个值,而非地址

在这里插入图片描述

下面俩条代码是同样的操作:
mov ecx,dword ptr[ebp-8]
push ecx
将[ebp-8]这个地址里的值保存在ecx寄存器中,利用寄存器将值压栈

在这里插入图片描述

传参过程,即将[ebp-8]的保存的值传到寄存器ecx中

在这里插入图片描述

可以通过监视器观察到,寄存器中存的是10这个值,而非地址

在这里插入图片描述
下一条汇编代码:call 00921023
即跳转到子程序中,此时点击F11,进入add函数内部

在这里插入图片描述

接下来的操作,是创建函数过程,与创建main函数过程相同,本人使用图例演示。

下一条汇编代码:push ebp
在这里插入图片描述

下一条汇编代码:mov ebp,esp

在这里插入图片描述
下一条汇编代码:sub esp,0CCh

在这里插入图片描述

下一条汇编代码: push ebx

在这里插入图片描述

下一条汇编代码: push esi

在这里插入图片描述

下一条汇编代码: push edi

在这里插入图片描述

下一条汇编代码: lea edi,[ebp-0Ch]

在这里插入图片描述

下一条汇编代码: mov ecx,3

在这里插入图片描述

下一条汇编代码: mov eax,0CCCCCCCCh

在这里插入图片描述

下一条汇编代码:rep stos dword ptr es:[edi]

在这里插入图片描述

下一条汇编代码:mov ecx,92C008h

在这里插入图片描述

下一条汇编代码: call 00921320

在这里插入图片描述

在这里插入图片描述

下一条汇编代码:mov dword ptr [ebp-8],0

在这里插入图片描述

在这里插入图片描述

下一条汇编代码:mov eax,dword ptr [ebp+8]

在这里插入图片描述

将[ebp+8]中存储的20放入寄存器中

在这里插入图片描述

下一条汇编代码:add eax,dword ptr [ebp+0Ch]

在这里插入图片描述

将俩个地址的值放在寄存器中相加

在这里插入图片描述

下一条汇编代码:dword ptr [ebp-8],eax

在这里插入图片描述
将寄存器eax中的数值放在[ebp-8]

在这里插入图片描述

下一条汇编代码:eax,dword ptr [ebp-8]

在这里插入图片描述

将z中的数值保存在寄存器中

在这里插入图片描述

下一条汇编代码:pop edi
pop——出栈,即从顶上拿出一个元素

在这里插入图片描述
edi被释放

在这里插入图片描述
下一条汇编代码:pop esi

在这里插入图片描述
esi被释放

在这里插入图片描述

下一条汇编代码:pop ebx

在这里插入图片描述
ebx被释放

在这里插入图片描述

下一条汇编代码:esp,0CCh

在这里插入图片描述

将维护函数的esp向栈底移动
在这里插入图片描述
下一条汇编代码:cmp ebp,esp

cmp——compare比较,功能相当与减法指令,但不保存结果

在这里插入图片描述
下一条汇编代码:call 00461244
即跳转到下一个程序中。

在这里插入图片描述

下一条汇编代码:mov esp,ebp

在这里插入图片描述
释放add函数,将esp与ebp寄存器返回

在这里插入图片描述
下一条汇编代码:pop ebp

在这里插入图片描述

释放存放ebp的地址

在这里插入图片描述

下一条汇编代码:ret

ret——return,返回

在这里插入图片描述
下一条汇编代码:add esp,8

在这里插入图片描述

将esp向下移动8个字节,释放存放局部变量的地方

在这里插入图片描述
下一条汇编代码:mov dword ptr [ebp-20h],eax

在这里插入图片描述
将寄存器eax中存放的30放在[ebp-20h]地址中

在这里插入图片描述

下一条汇编代码:xor eax,eax
xor——XOR指令进行按位逻辑异或操作,将结果存放在目标操作数中1。它可以将一个寄存器的值和一个常量进行异或操作,结果会存储到原寄存器中2。
大家还记得异或操作符吗?——相同为0,相异为1

在这里插入图片描述

那么俩个相同的值进行异或会?哈哈当然会变成0啊!

在这里插入图片描述

下面这些操作是释放main函数,main函数也是被调用的

在这里插入图片描述

  • 今天的内容就到这里啦!希望大家可以提出建议!!!让我多多学习!!

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

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

相关文章

物理服务器介绍

物理服务器介绍 概述分类按服务器应用分类按服务器结构分类塔式服务器机架式服务器刀片式服务器机架式服务器与刀片式服务器的对比按处理器个数分类按处理器架构分类 主板概述工作原理物理结构技术参数 CPU概述工作原理指令集相关技术技术参数主流产品 内存概述类型相关技术技术…

安卓分身大师4.6.0解锁会员安卓14可用机型伪装双开多开

需登录解锁会员功能&#xff0c;除了加速进入不能&#xff0c; 其他主要功能都是可以使用&#xff0c;由于验证较多一些功能需要特定操作使用&#xff0c;进行伪装时请不要直接伪装&#xff0c;先生成成功后再进行自定义伪装&#xff01;链接&#xff1a;https://pan.baidu.com…

Transformer详解(3)-多头自注意力机制

attention multi-head attention pytorch代码实现 import math import torch from torch import nn import torch.nn.functional as Fclass MultiHeadAttention(nn.Module):def __init__(self, heads8, d_model128, droput0.1):super().__init__()self.d_model d_model # 12…

通过el-tree自定义渲染网页版工作目录,实现鼠标悬浮显示完整名称、用icon区分文件和文件夹等需求

目录 一、通过el-tree自定义渲染网页版工作目录 1.1、需求介绍 1.2、使用el-tree生成文档目录 1.2.1、官方基础用法 ①效果 ②代码&#xff1a; 1.2.2、自定义文档目录&#xff08;实现鼠标悬浮显示完整名称、用icon区分文件和文件夹&#xff09; ①效果&#xff08;直接效…

JavaScript表达式和运算符

表达式 表达式一般由常量、变量、运算符、子表达式构成。最简单的表达式可以是一个简单的值。常量或变量。例&#xff1a;var a10 运算符 运算符一般用符号来表示&#xff0c;也有些使用关键字表示。运算符由3中类型 1.一元运算符&#xff1a;一个运算符能够结合一个操作数&…

YOLOv8_seg的训练、验证、预测及导出[实例分割实践篇]

实例分割数据集链接,还是和目标检测篇一样,从coco2017val数据集中挑出来person和surfboard两类:链接:百度网盘 请输入提取码 提取码:3xmm 1.实例分割数据划分及配置 1.1实例分割数据划分 从上面得到的数据还不能够直接训练,需要按照一定的比例划分训练集和验证集,并按…

如何远程实时查看监控管理员工电脑屏幕?远程查看多台员工电脑屏幕的方法

现代化企业管理中&#xff0c;远程监控员工电脑屏幕已经成为一种有效的手段&#xff0c;用于提升工作效率、确保信息安全以及维护工作纪律。 而这种事情&#xff0c;也仿佛已经很常见了。 那么一般都如何监控的呢&#xff1f; 一、选择合适的远程监控软件 1.域智盾 域智盾提…

2024 电工杯高校数学建模竞赛(B题)数学建模完整思路+完整代码全解全析

你是否在寻找数学建模比赛的突破点&#xff1f;数学建模进阶思路&#xff01; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024电工杯数学建模竞赛&#xff08;B题&#xff09;的全面解析。这个解决方案包不仅包括完整的代码实现&#xff0c;还有详尽的建模过程和解…

markdown 文件渲染工具推荐 obsidian publish

背景 Markdown 是一种轻量级的标记语言&#xff0c;最开始使用它是觉得码字非常方便&#xff0c;从一开始的 word 排版到 markdown &#xff0c;还不太不习惯&#xff0c;用了 obsidian把一些文字发在网上后&#xff0c;才逐渐发现他的厉害之处。 让人更加专注于内容本身&…

机器学习云环境测试

等待创建完成后&#xff0c;点击 PyTorch 打开&#xff0c;创建一个全新的 notebook 在 Cell 中输入如下代码&#xff0c;并点击 Run 完成后点击 New Cell &#xff0c;在 New Cell 中输入如下代码 输入完成后点击 Run &#xff0c;运行 New Cell 。&#xff08;每个 Cell 代…

Java面试八股之Thread类中的yeild方法有什么作用

Thread类中的yeild方法有什么作用 谦让机制&#xff1a;Thread.yield()方法主要用于实现线程间的礼让或谦让机制。当某个线程执行到yield()方法时&#xff0c;它会主动放弃当前已获得的CPU执行权&#xff0c;从运行状态&#xff08;Running&#xff09;转变为可运行状态&#…

朴素贝叶斯+SMSSpamCollections

1. 打开 Jupyter 后&#xff0c;在工作目录中&#xff0c;新建一个文件夹命名为 Test01 &#xff0c;并且在文件夹中导入数据 集。在网页端界面点击 “upload” 按钮&#xff0c;在弹出的界面中选择要导入的数据集。然后数据集出现 在 jupyter 文件目录中&#xff0c;此时…

基于SSM的大学生兼职管理系统

基于SSM的大学生兼职管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 登录界面 企业界面 前台学生界面 管理员界面 摘要 随着大学生兼职市场的日益繁…

VTK9.2.0+QT5.14.0绘制三维显示背景

背景 上一篇绘制点云的博文中&#xff0c;使用的vtkCameraOrientationWidget来绘制的坐标轴&#xff0c;最近又学习到两种新的坐标轴绘制形式。 vtkOrientationMarkerWidget vtkAxesActor 单独使用vtkAxesActor能够绘制出坐标轴&#xff0c;但是会随着鼠标操作旋转和平移时…

Java设计模式 _行为型模式_迭代器模式

一、迭代器模式 1、迭代器模式 迭代器模式&#xff08;Iterator Pattern&#xff09;是一种行为型设计模式&#xff0c;用于顺序访问集合对象的元素&#xff0c;不需要关心集合对象的底层表示。如&#xff1a;java中的Iterator接口就是这个工作原理。 2、实现思路 &#xff0…

linux 中 fd 申请和释放管理(两级 bitmap)

linux 中 fd 的几点理解_linux fd-CSDN博客 通过上边的文章&#xff0c;我们可以知道&#xff0c;在 linux 中&#xff0c;fd 有以下几点需要了解&#xff1a; &#xff08;1&#xff09;fd 表示进程打开的文件&#xff0c;是进程级别的资源&#xff0c;不是系统级别的资源 …

Rhinoceros v7.5 解锁版安装教程 (3D三维造型软件)

前言 Rhinoceros 中文名称犀牛是一款超强的三维建模工具&#xff0c;全称Rhinoceros&#xff0c;Rhino是美国Robert McNeel & Assoc开发的PC上强大的专业3D造型软件&#xff0c;它可以广泛地应用于三维动画制作、工业制造、科学研究以及机械设计等领域。它能轻易整合3DS M…

Nodejs及stfshow相关例题

Nodejs及stfshow相关例题 Node.js 是一个基于 Chrome V8 引擎的 Javascript 运行环境。可以说nodejs是一个运行环境&#xff0c;或者说是一个 JS 语言解释器而不是某种库。 Node.js可以生成动态页面内容Node.js 可以在服务器上创建、打开、读取、写入、删除和关闭文件Node.js…

设计模式9——适配器模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 适配器模式&#xff08;Adapte…

【Linux】Centos7安装JDK

【Linux】Centos7安装JDK 下载 Oracle 官网下载 JDK17 https://www.oracle.com/cn/java/technologies/downloads/#java17 安装 使用rz命令上传 jdk tar 包&#xff0c;上传失败直接用 xftp 上传 在安装图形界面时&#xff0c;有勾选开发工具&#xff0c;会自动安装 JDK 需要先…