十、函数栈帧的创建和销毁

前期学习的时候我们可能会有很多困惑,如:

(1)局部变量的值是随机值?

(2)为什么局部变量的值是随机值?

(3)函数是怎么传参的?传参的顺序是怎样的?

(4)形参和实参是什么关系?

(5)函数调用是怎么做的?

(6)函数调用结束后是怎么返回的?

我们接下来使用VS2013的环境,因为编译器越高级,函数栈帧的过程和封装会更不容易去观察,同时在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现。

寄存器

函数栈帧

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

每一个函数调用,都要在栈区创建一个空间。

使用调用堆栈可以看到main函数被调用了,但是有一个比较困惑的点,main函数被谁调用了?

等程序走完可以发现--tmainCRTStartup函数调用了main函数。

--tmainCRTStartup( )函数调用main函数

mainCRTStartup( )函数调用--tmainCRTStartup( )函数

每次main函数都有return0,这个返回值返回到了mainret中去了。

在VS2013中main函数也是被其他函数调用的

--tmainCRTStartup( )

mainCRTStartup( )

打开反汇编我们可以看到这个程序的汇编代码,方便接下来的理解分析。

等类似的汇编代码。

接下来我们按照顺序来依次分析

push  ebp 就是把ebp的值放到栈顶上面(压栈)

mov        ebp,esp

这一步就是把esp的值赋给ebp

sub        esp,0E4h

这一步就是esp - 0E4h(8进制数字,十进制为228)

push        ebx

push        esi

push        edi

这三个push就是分别把ebx、esi、edi压栈。

lea        edi,[ebp-24h]

这个意思是把[ebp-24h]的地址放到edi里

mov        ecx,9

把9的数据放到ecx中

mov        eax,0CCCCCCCCh

把0CCCCCCCCh的数据放到eax中

rep  stos        dword ptr es:[edi]

把从edi开始向下39h次这么多的双字节的数据空间全部都改成eax这样0CCCCCCCCh的内容。

这里强调一下:

压栈:就是在栈顶放一个数据进去(push)

出栈:就是在栈顶拿走一个数据(pop)

int a = 10;

mov        dword  ptr [ebp-8],0Ah

0A就是10就是把10放到 [ebp-8]的位置。

int b = 20;

mov        dword  ptr  [ebp-14h],14h

把20放到[ebp-14]的位置上

int c = 0;

mov        dword ptr [ebp-20h]

把0放到[edp-20h]的位置上。

c = Add(a,b);

mov        eax,dword  ptr [edp-14h]

把[edp-14]这个位置上的值放到eax中去。

push        eax

eax压栈

mov        ecx , dword ptr [edp-8]

把[edp-8]位置上的值放到ecx中去

push        ecx

ecx压栈

当遇见call时我们使用F11进入Add函数中

在进入Add函数之前我们发现

call后面有这样一串编码,栈区情况如下:

这个编码是call指令的下一条指令的地址。

进入Add函数

push        edp

edp压栈。

这里注意edp压栈,这里存放的数据是edp指针指向的main函数栈底的地址。

mov        edp,esp 

把esp位置的值赋给edp,此时edp指针指向esp指针指向的位置。

sub        esp,0CCh

就是[esp-0CCh]

我们来看这个过程

mov        ebp,esp

sub        esp,0CCh

这个过程中先把esp的值赋给ebp,使ebp上移至当前esp指向的位置,然后将esp减去0CCh这个值使得esp向小地址移动。

我们可以发现这个过程前面为main函数创建函数栈帧的过程很像,其实这个过程就是在为Add函数创建函数栈帧。

push        ebx

push        esi

push        edi

这三步操作分别将ebx、esi、edi压栈。

lea          edi,[edp-0Ch]

mov        ecx,33h

mov        eax,0CCCCCCCCCCh

rep          dword ptr es:[edi]

这几步指令执行的是一下操作(前面有说过类似的指令,这里就不再重复了)

这里我们来看一下之前创建Add函数的代码:

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

int z = 0;

mov        dword ptr [edp-8],0

把0放到[edp-8]的位置

z = x + y;

mov        eax,dword ptr [ebp - 8]

这个里面放的10

把[ebp + 8]里面放的值赋给eax

add        eax,dword ptr [ebp + 0Ch]

这个里面放的20

把[ebp + 0Ch]里面放的值加到eax里,这时eax里面放的值为30

mov        dword ptr [edp - 8],eax

把eax里的值放到[ebp - 8]中去

这一步结束后我们回想一下:

在创建Add函数中根本就没有创建形参,而是在main函数中将x、y的值压栈压出来然后在创建Add后引用了压栈压出来的值,并且Add(int x,int y)中先y后x从右到左。

return z;

mov        eax,dword ptr [ebp - 8]

把[ebp - 8]里的值放到eax中去,eax是一个寄存器,在程序退出后eax寄存器会销毁。

pop        edi 一次pop esp会加加,并且弹出栈顶

把esp所在的栈顶弹出换成edi然后esp加加指向地址高的地方,后面几步pop操作同理

pop        esi

pop        ebx

mov        esp,ebp

把ebp中的值赋给esp

执行完此步骤后:

pop        ebp

把栈顶上的东西弹掉,并把栈顶中存放的数据赋值给ebp,由于在前面创建main函数时ebp在main函数的栈底,ebp压栈时将ebp当时的值压到这里的,所以ebp赋到这个值后会回到main函数的栈底。

ret

将程序从子程序中返回到003710B9这个程序,同时esp加加

这时就回到了call指令

call

add        esp,8

esp加8

mov        dword ptr [edp - 20h],eax

把eax中的值 (出Add函数返回的z的值) 放到[ebp - 20h]中去。


如此我们可以回答下列问题:

局部变量是怎么创建的?

首先函数分配好栈帧空间,然后在函数的栈帧空间中给局部变量分配一部分空间。

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

因为随机值是我们放进去的CCCCCCCCC,给局部变量赋值后才会见这个随机值覆盖。

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

当要去调用函数之前,就已经用push将参数从右到左压栈,真正进入要调用的函数中通过指针的偏移量找到形参

形参和实参是什么关系?

形参确实是在压栈时开辟的空间和实参在值上是相同的单实参是独立的,所以形参是实参的一份临时拷贝,改变形参不会改变实参。

感谢各位大佬的观看!!!

歪比巴卜

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

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

相关文章

Burp Suite Professional 2024.6 for macOS x64 ARM64 - 领先的 Web 渗透测试软件

Burp Suite Professional 2024.6 for macOS x64 & ARM64 - 领先的 Web 渗透测试软件 世界排名第一的 Web 渗透测试工具包 请访问原文链接:https://sysin.org/blog/burp-suite-pro-mac/,查看最新版。原创作品,转载请保留出处。 作者主页…

万字学习——DCU编程实战补充

参考资料 2.1 详解DCU架构 DCU 开发与使用文档 (hpccube.com) DCU架构是什么样的 计算单元阵列,如图CU0、CU1等缓存系统(L1一级缓存,L2二级缓存)全局内存(global memory)CPU和DCU数据通路(DMA) 我的理解…

通过图像高频信息保留图像细节,能保留多少细节-Comfyui

🧨前情提要 如果还不了解comfyui中图像高频信息保留细节的内容,可以参考上一篇文章: 图像中高频信息、低频信息与ComfyUI中图像细节保留的简单研究-CSDN博客 这次主要是简单测试下保留图像细节,能保留到什么程度; …

江波龙 128G msata量产

一小主机不断重启,用DG格式化 无法完成,应该是有坏块了 找一个usb转msata转换板 查了一下是2246en aa主控 颗粒应该是三星的 缓存是现代的 找到量产工具sm22XMPToolP0219B 打开量产工具 用镊子先短接一下jp1 插入usb口,再拿走镊子 scan …

每天五分钟计算机视觉:目标检测算法之R-CNN

本文重点 在计算机视觉领域,目标检测一直是一个核心问题,旨在识别图像中的物体并定位其位置。随着深度学习技术的发展,基于卷积神经网络(CNN)的目标检测算法取得了显著的进步。其中,R-CNN(Regions with CNN features)是一种开创性的目标检测框架,为后续的研究提供了重…

微积分-导数6(隐式导数)

隐式导数 前面我们学了如何求这些方程的导数: y x 3 1 or y x sin ⁡ x y \sqrt{x^31} \quad \text{or} \quad y x\sin x yx31 ​oryxsinx 但是如果是下面的方程,又该如何求导呢? x 3 y 3 6 x y x^3 y^3 6xy x3y36xy 这个方程的图…

【Linux】进程的基本概念(已经进程地址空间的初步了解)

目录 一.什么是进程 进程和程序的区别 Linux查看进程 进程的信息 fork函数 二.进程状态 操作系统上进程状态的概念 运行 阻塞 挂起 Linux中的进程状态 R状态 S状态和D状态 T状态 t状态 X状态 Z状态 三.进程的优先级 修改进程优先级 四.环境变量 常见的环境变量 PATH HOME PW…

科普文:jvm笔记

一、JVM概述# 1. JVM内部结构# 跨语言的平台,只要遵循编译出来的字节码的规范,都可以由JVM运行 虚拟机 系统虚拟机 VMvare 程序虚拟机 JVM JVM结构 HotSpot虚拟机 详细结构图 前端编译器是编译为字节码文件 执行引擎中的JIT Compiler编译器是把字节…

关于无法定位程序输入点 SetDefaultDllDirectories于动态链接库KERNEL32.dll 上 解决方法

文章目录 1. ERNEL32.dll 下载2. 解决方法 👍 个人网站:【 洛秋小站】 1. ERNEL32.dll 下载 Windows 7 在安装postman时报错缺少动态链接库,提示缺少.NET Framework,这是因为本地缺少相应的dll文件导致的,这时就需要下载ERNEL32.dll文件,在解…

前端/python脚本/转换-使用天地图下载的geojson(echarts4+如果直接使用会导致坐标和其他信息不全)

解决echarts4如果直接使用天地图下载的geojson会导致坐标和其他信息不全 解决方法是使用python脚本来补全其他信息:center,level,adcode等内容 前提是必须有一个之前使用的json文件(需要全一点的数据供echarts使用) …

Linux文件编程应用

目录 一、实现cp命令 二、修改程序的配置文件 三、写一个整数/结构体到文件 1.写一个整数到文件 2.写一个结构体到文件 四、写结构体数组到文件 我们学习了文件编程的常用指令以及了解文件编程的基本步骤后,试着来写一些程序实现某些功能。(没有学…

记录一次微信小程序申诉定位权限过程

1 小程序接到通知,检测到违规,需要及时处理,给一周的缓冲时间,如果到期未处理,会封禁能力(2023-11-17) 2 到期后,仍未处理,封禁能力(2023-11-24) …

【04】微服务通信组件Feign

1、项目中接口的调用方式 1.1 HttpClient HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包,并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统 JDK 自带的 URLConnectio…

打印任务无法删除怎么办?

在删除打印任务的时候,你可能会遇到这样的情况,当我们想把打印任务取消的时候,却一直显示正在删除,而过了很久还没有取消掉,下面就分享一下处理这个问题的方法。 1、停止打印服务,按WinR键打开运行对话框&a…

Unity WebGL 嵌入前端网页并通信

1. 前言 最近在做项目时遇到需要将 UnityWebGL 嵌入到网页中去,且需要点击网页中的按钮 UnityWebGL 可以做出响应。新建项目部分直接略过 2. 最终效果 3. 基础设置 设置导出平台为WebGL 在Player Settings -> Publishing Settings 中勾选 Data Caching 和Deco…

《Windows API每日一练》9.1.5 自定义资源

自定义资源(Custom Resources)是在 Windows 程序中使用的一种资源类型,用于存储应用程序特定的数据、图像、音频、二进制文件等。通过自定义资源,开发者可以将应用程序所需的各种资源文件集中管理和存储,便于在程序中访…

imx6ull/linux应用编程学习(17)利用mqtt上传开发板数据,和控制开发板led(基于正点)

1.关于如何创建自己的服务器,可看上篇文章 imx6ull/linux应用编程学习(16)emqx ,mqtt创建连接mqtt.fx-CSDN博客 2.实现任务:(正点原子教程源码改) (1)用户可通过手机或电脑远程控制开发板上的…

小白的OS Copilot 产品测评

背景 通过群友介绍才知OS Copilot 。不想错过任何优秀的AI产品。随着互联网的发展和时代的进步,要紧跟时代,了解市面上的优秀的AI科技产品。 OS Copilot 产品体验评测 1)您的角色是什么?开发、运维、学生?如果使用O…

类和对象——【const成员】【static成员】【友元】【内部类】

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。 P. S.:测试代码均未展示头文件iostream的声明,使用时请自行添加。 博主主页:Yan. yan.                        …

css文字自适应宽度动态出现省略号...

前言 在列表排行榜中通常会出现的一个需求:从左到右依次是名次、头像、昵称、徽标、分数。徽标可能会有多个或者没有徽标,徽标长度是动态的,昵称如果过长要随着有无徽标进行动态截断出现省略号。如下图布局所示(花里胡哨的底色是…