函数栈帧的创建和销毁(详细理解)

2024-05-15 23:44

本文主要是介绍函数栈帧的创建和销毁(详细理解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

🎁个人主页:我们的五年

🔍系列专栏:c语言课程学习

🎉欢迎大家点赞👍评论📝收藏⭐文章

目录

 问题:

1.ebp,esp两个寄存器用来维护函数栈帧

2.main函数也一个函数,main函数也要被其他函数调用

 3.函数栈帧创建的过程

4.函数栈帧的销毁过程


 

 问题:

1.局部变量是怎么创建的?

调用函数的时候,会为函数开辟一块空间,然后第一个局部变量从栈低分配一块空间给局部变量。

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

因为在为函数开辟空间的时候,这块空间的里的内存都被初始化为一个值,不同编译器中值可能不同。如果只是创建局部变量,没有初始化覆盖里面的值,那此时局部变量里的值就是为函数内存初始化的值。

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

调用函数的时候,会在该函数的栈顶压栈,该内存里放的是形参,然后通过ebp的偏移量就可以找到形参。        传参的顺序是从右到左。

4.形参和实参是什么关系?

形参是实参的零时拷贝,形参是在函数栈顶新开辟的一块空间,这块空间与实参的空间相互独立,只是数值一样。改变形参不会改变实参。

5.函数调用是怎么做的?

函数会把函数的下一指令的地址保存在call中,并且保存ebp的位置。

然后为新的函数开辟空间,在新的函数的栈顶压入三个寄存器ebx,esi,edi,然后新的空间全部初始化为一个值。然后就执行新新函数里的指令。

6.函数调用以后是怎么返回的?

返回值是通过寄存器带回来的,寄存器是全局的,不会因为函数的销毁而销毁。

然后根据保存的ebp,和下一指令的地址找到新的函数,即要执行的指令的地址。

不同的函数会开辟不同的空间。

1.ebp,esp两个寄存器用来维护函数栈帧

1.ebp寄存器:栈底寄存器。

2.esp寄存器:栈顶寄存器。

3.pc指针寄存器:也叫程序计数器,它永远指向当前指令的下一条指令。

当前有下面代码:

#define CRT_SECURE_NO_WARNINGS 1
#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", c);return 0;
}

 

 ●这个程序中,我们先进入main函数,esp寄存器和ebp寄存器就用来维护main函数的函数栈帧。当指令到达c=Add(a,b);的时候,就要调用Add函数,这时候,esp寄存器和ebp寄存器就要区维护Add函数的函数栈帧。

●每一个函数都有自己的ebp和esp,即每个函数都有自己的栈顶和栈底。

●在CPU中,ebp和esp不会有很多,但是函数却有很多。但是程序运行的时候,不可能一边运行两个函数,当运行main函数的时候,ebp和esp去维护main函数的函数栈帧。当进入Add函数,去运行Add函数的时候,esp和ebp就去维护Add函数的函数栈帧,并且把mian函数的esp和ebp的指针保存下来,等Add函数结束以后,esp和ebp就又可以去维护main函数的函数栈帧。

●地址的使用顺序是从高地址,到低地址。

2.main函数也一个函数,main函数也要被其他函数调用

当main函数结束以后,函数栈帧回到__tmianCRTStartup()。

●由此可知main函数被__tmainCRTStartup()调用。

●__tmainCRTStartup()函数被mainCRTStartup()函数调用。

 

 

 程序先进入mainCRTStartup函数,为mainCRTStartup函数开辟函数栈帧,然后调用__tmainCRTStartup函数,为__tmainCRTStartup函数开辟函数栈帧。所以上面的图中比main高地址处还有这两个函数的函数栈帧,这两个函数的函数栈帧比main函数的函数栈帧高。

 3.函数栈帧创建的过程

在调用main函数时,已经存在来到下面情形,__tmainCRTStartup()调用main函数

🚗1.push  ebp:在栈顶,在栈顶把ebp指针的值放进去。esp就要改变位置,往上移一点,栈顶改变,esp也要改变。指针的大小是四个字节,在栈顶存ebp的值,所以就开辟4个字节的空间,里面放着ebp的值。

🚗 2.mov        ebp,esp:把esp的值给ebp,那么ebp就指向esp指向的地方。

🚗3.sub        esp,0E4H:0E4H是一个16进制数,转化为10进制是228.让esp减小228。减小是往上增长,往低地址处变化。

🚗4.push        ebx

        push        esi

        push        edi:

        在栈顶压入ebx,esi,edi,esp跟着变化。

🚗5.lea=lode effective address

把edi往下的到ebp内存里的值全部变为0cccccccch.word是两个字节,dword是double word占4个字节。

🚗6显示地址以后:

🚗7.Add函数调用

 [ebp+8]找到a,[ebp+0ch]找到b,b给eax,然后eax+(add)a,然后eax给z。

Add函数中没有创建形参a,b。

4.函数栈帧的销毁过程

【ebp-8】表示z,也就是把z的值给寄存器eax,这样z的值就不会丢失。

 三次pop销毁edi,esi,ebx。

ebp的值给esp,esp就指向ebp指向的位置。

然后pop        ebp,把ebp指向空间的值给ebp也就是main  ebp。

然后ret  call的下一条指令的地址。使程序可以从main函数调用完Add函数以后,执行Add函数的下一条指令。

然后把main函数的指令执行完。

最后把main函数的函数栈帧给销毁。

回到__tmainCRTStartup函数。

这篇关于函数栈帧的创建和销毁(详细理解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/993262

相关文章

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

如何为Yarn配置国内源的详细教程

《如何为Yarn配置国内源的详细教程》在使用Yarn进行项目开发时,由于网络原因,直接使用官方源可能会导致下载速度慢或连接失败,配置国内源可以显著提高包的下载速度和稳定性,本文将详细介绍如何为Yarn... 目录一、查询当前使用的镜像源二、设置国内源1. 设置为淘宝镜像源2. 设置为其他国内源三、还原为官方

最详细安装 PostgreSQL方法及常见问题解决

《最详细安装PostgreSQL方法及常见问题解决》:本文主要介绍最详细安装PostgreSQL方法及常见问题解决,介绍了在Windows系统上安装PostgreSQL及Linux系统上安装Po... 目录一、在 Windows 系统上安装 PostgreSQL1. 下载 PostgreSQL 安装包2.

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

MySql match against工具详细用法

《MySqlmatchagainst工具详细用法》在MySQL中,MATCH……AGAINST是全文索引(Full-Textindex)的查询语法,它允许你对文本进行高效的全文搜素,支持自然语言搜... 目录一、全文索引的基本概念二、创建全文索引三、自然语言搜索四、布尔搜索五、相关性排序六、全文索引的限制七

python中各种常见文件的读写操作与类型转换详细指南

《python中各种常见文件的读写操作与类型转换详细指南》这篇文章主要为大家详细介绍了python中各种常见文件(txt,xls,csv,sql,二进制文件)的读写操作与类型转换,感兴趣的小伙伴可以跟... 目录1.文件txt读写标准用法1.1写入文件1.2读取文件2. 二进制文件读取3. 大文件读取3.1

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效

如何在Mac上安装并配置JDK环境变量详细步骤

《如何在Mac上安装并配置JDK环境变量详细步骤》:本文主要介绍如何在Mac上安装并配置JDK环境变量详细步骤,包括下载JDK、安装JDK、配置环境变量、验证JDK配置以及可选地设置PowerSh... 目录步骤 1:下载JDK步骤 2:安装JDK步骤 3:配置环境变量1. 编辑~/.zshrc(对于zsh