函数调用过程详解:函数栈帧的创建与销毁
前言:我们在学习C语言的过程中,可以会产生很多疑问,比如:
- 局部变量是怎么创建的
- 为什么局部变量的值不做初始化就是随机值
- 函数是怎么传参的?传参的顺序是怎么样的?
- 形参和实参是什么关系?
- 函数调用是怎么做的?
- 函数调用结束后是怎样返回的?
注意:本文博主选用VS2013进行讲解,同时在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现。
而这些种种的疑问,我们都能在 函数栈帧的创建与销毁中 一一进行解答,相信大家看了本文后,都能对函数是如何调用的做出自己独特的见解,话不多说,下面博主就将函数栈帧的创建与销毁过程一一讲解:
目录
- 1. 基础认知
- 2. 函数栈帧的创建
- 3.函数栈帧的销毁
- Last .总结
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\n", c);return 0;
}
我们对代码F10进行调式,之后在反汇编窗口中我们可以看到以下信息:
通过观察底层代码中我们不难发现,我们平时一直使用的main函数竟然也是被调用的,他们的调用关系如下:
3 调用了 2 , 2 又去调用了 1 (main函数)
接着我们需要了解,在CPU中存在在若干寄存器,如: (加粗是重点)
(1)esp:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。 (栈顶指针)
(2)ebp:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。 (栈底指针)
(3)eax 是”累加器”(accumulator), 它是很多加法乘法指令的缺省寄存器。
(4)ebx 是”基地址”(base)寄存器, 在内存寻址时存放基地址。
(5)ecx 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。 (6)edx 则总是被用来放整数除法产生的余数。
(7)esi/edi分别叫做”源/目标索引寄存器”(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串. 在32位平台上,ESP每次减少4字节。
寄存器中存放的是地址,esp ebp 这两个地址是用来维护函数栈帧的。
2. 函数栈帧的创建
在开始讲解前我们先来了解提交反汇编指令:
mov :数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址(寄存器间的数据传送本质上也是一样的) (右边传进左边)
sub:减法指令
lea:取偏移地址 (加载有效地址 )
push:实现压入操作的 (压栈)
pop:实现弹出操作的指令
call:用于保存当前指令的下一条指令并跳转到目标函数。
3.函数栈帧的销毁
至此,有关该函数的栈帧的创建与销毁我们就大致梳理了一遍,最终 Add 函数加法运算的值是存放在寄存器 eax 中的,所以 Add函数栈帧销毁了也不会影响和©的值的打印。
Last .总结
通过该函数栈帧的创建与销毁过程分析我们就可以解答文章开头给出的种种疑问:
- 局部变量是怎么创建的
答:局部变量是通过在该函数栈帧初始化一定空间后,在该空间分配的一部分空间创建的。- 为什么局部变量的值不做初始化就是随机值
答:因为不初始化操作的话这些空间中的值是编译器给定的一些随机数 (如上面的cccccccc)- 函数是怎么传参的?传参的顺序是怎么样的?
答:在调用函数前已经push push 从右向左顺序压栈进去,在Add函数中通过指针的偏移找到了实参。- 形参和实参是什么关系?
答:形参只是实参的一份临时拷贝,改变形参的量不影响实参的变化- 函数调用是怎么做的?
答: 详情见上文。- 函数调用结束后是怎样返回的?
答:再调用Add函数之前我们就把call指令下面的地址压栈进去啦,返回时候弹出ebp就能找到原始main函数ebp的地址,实现返回。返回值是存在寄存器eax中的 ,实现打印
至此有关函数栈帧的创建与返回介绍就完毕啦,如果觉得文章对自己有所帮助还望大家多多点赞 ~ 谢谢各位啦 !
函数调用过程详解:函数栈帧的创建与销毁相关推荐
- (动图详解)汇编视角观察函数栈帧的创建和销毁
目录 1.阅读本文的价值 2.函数栈帧及栈的概念 3.部分寄存器及汇编指令 4.main函数的调用 5.main函数的栈帧创建 6.变量的栈帧创建 6.函数传参 7.函数内部运算及销毁 ...
- C函数调用过程原理及函数栈帧分析
在x86的计算机系统中,内存空间中的栈主要用于保存函数的参数,返回值,返回地址,本地变量等.一切的函数调用都要将不同的数据.地址压入或者弹出栈.因此,为了更好地理解函数的调用,我们需要先来看看栈是怎么 ...
- 函数栈帧的创建与销毁
目录 前言 一.预备知识 1.内存区域的划分和分配 2.栈帧简介 3.寄存器简介 二.函数栈帧介绍 1.源代码 2.如何查看汇编代码 3.函数栈帧的创建与销毁(重点) 三.小彩蛋 总结 前言 最近在学 ...
- 程序员内功心法之函数栈帧的创建和销毁
目录 1.本节目标 2.相关寄存器 3.相关汇编指令 4.什么是函数栈帧 5.什么是调用堆栈 6.函数栈帧的创建和销毁 (1).main函数栈帧的创建与初始化 (2).main函数的核心代码 (3). ...
- 【C语言】程序员筑基功法——《函数栈帧的创建与销毁》
<函数栈帧的创建与销毁> 文章目录 1. 前言 2. 问题引入 3. 前提准备 3.1 寄存器 3.2 汇编指令 4. 函数栈帧的维护 5. 如何调用堆栈 6. 函数栈帧的创建和销毁 6. ...
- C语言内功修炼之函数栈帧的创建与销毁(举例加图解)
大家可能会函数栈帧不了解,可能都没有听过这个,不用着急,在理解函数栈帧之前,我们先来了解一下程序对内存使用的分区大概情况: 区域 作用 栈区(stack) 由编译器自动分配和释放,存放函数的参数值, ...
- 程序员内功修炼——函数栈帧的创建与销毁
一.什么是函数的栈帧 c语言是由函数构成的,那么函数是如何进行传参的?如何调用的?如何返回值的?这些问题与函数的栈帧有关. 函数栈帧:就是函数调用过程中程序的调用栈所开辟的空间,这些空间用来存放: 1 ...
- 内功修炼《函数栈帧的创建和销毁》建议收藏
文章目录 前言 一. 寄存器的概念 二. 通用寄存器的结构 三. 指针寄存器和变址寄存器 四. EBP和ESP 五.总结 前言 在前期的学习过程中,我们可能会有很多的困惑: 1️⃣ 局部变量是怎么创建 ...
- 函数栈帧的创建和销毁图解
目录 一.问题: 二.寄存器 栈区 1.寄存器有哪些?有什么作用? 2.编译环境 3.栈区的使用习惯: 4.main函数也是被其他函数调用的 5.汇编代码 三.为main函数创建栈帧 1.main函数 ...
最新文章
- Facebook AI新研究:可解释神经元或许会阻碍DNN的学习
- python自学免费课堂-python自学——文件打开
- Maven 项目名称红色感叹号的问题总结
- C# 调用 Delphi Dll链接库方法及示例
- 300WLP、AFLW2000-3D、Biwi Kinect Head Pose Database姿态数据的读取
- c++连接云服务器_如何简单搭建Minecraft服务器
- c# key event
- golang 生成定单号
- 用户画像之基础知识(人群画像|会话环境维度|行为画像)
- 2020 年最具潜力 44 个顶级开源项目,涵盖 11 类 AI 学习框架、平台(值得收藏)...
- R:数据分析-----汽车数据可视化
- 缺陷跟踪管理工具-Mantis BugFree Bugzilla
- 【软件工程课后习题】
- WordCount单词计数详解
- 求e的近似值 (15 分)Java【循环】
- 可以同时合并不同尺寸不同格式视频的视频合并工具
- Tableau实战 房地产估值分析
- HAPPE+ER软件:标准化事件相关电位ERP的预处理的pipeline
- 用Python掷骰子——打麻将没骰子还要出去买?
- 在你眼里我只是个演员 演着你倒出的戏
热门文章
- Python异步通信模块asynchat
- SPU表管理之保存SPU表数据
- 爬虫之requests模块介绍
- 数据流分析与 SSA | 什么是静态单赋值 SSA
- idea软件,如何不每次弹出“欢迎界面!”
- bs4库的prettify()方法|粉饰的意思。就是多了换行!
- 最大公约数与最小公约数!_只愿与一人十指紧扣_新浪博客
- C++ 使用 curl 进行 http 请求(GET、POST、Download)的封装
- Android Studio中新建和引用assets文件
- Win7:“找不到该项目”错误解决大法