一.什么是函数的栈帧

c语言是由函数构成的,那么函数是如何进行传参的?如何调用的?如何返回值的?这些问题与函数的栈帧有关。
函数栈帧:就是函数调用过程中程序的调用栈所开辟的空间,这些空间用来存放:
1.函数参数和返回值
2.临时变量
3.保存上下文信息

二.内存分布

要想明白函数怎么调用内存的,首先得知道内存的分布,如图:

知道了内存的分布,下面让我们认识寄存器ebp和esp。

ebp esp这2个寄存器是用来存放地址的,同时维护函数的栈帧。每一个函数的创建都要用到函数的栈帧。

三.函数栈帧创建的原理

我们先从一个简单的代码看起

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

这是一个简单的计算两数之和的代码,他是怎么运行的呢?首先程序进入main函数,函数的调用都会在栈区上开辟一块内存空间。
esp:栈指针寄存器,其内存放着一个指针,该指针永远指向栈顶
ebp:内存也放着一个指针,指向栈低。


通过调试我们发现函数在创建main函数之前会调用二个函数

我们去找到这二个函数


通过调试我们发现 _tmain函数——>maincr——>main形成这样的调用逻辑关系。main函数开辟空间的时候会先调用前面二个函数,那么调用前二个函数有什么意义呢?
在开始调用前二个函数时候内存也会为它们开辟新的空间

我们转到反汇编上,从最底层看看是怎么创建出空间的。

这就是上述代码在反汇编下的运行逻辑。我们一步步的分析

开始时栈区如上图所示,接着我们看反汇编第一条指令,push意思是压栈

运行完第一条指令其结果如下

第二条指令mov ,意思是把esp的值给ebp

第三条指令sun,意思是给esp的值减上0E4h;esp是地址地址由高到底,减上一个数相当于把esp上移。

上述黄色部分就是main函数开辟的空间

第4,5,6条指令都是push压栈,3次push给顶上压元素。

第7,8,9行指令指把main函数空间全部初识化为cccc

这也充分的说明了如果不给局部变量初始化那么其存的是一个随机的值,所以在定义变量的时候一定要给变量初始化。
到目前为止,程序执行的准备工作已经结束,接下来是程序运行阶段我们继续看反汇编

这条指令的意思是把ebp的地址向上移8,同时放入值0ah(10进制为10)

同理接下来的指令把20放入内存中

到这里main函数内部的变量已经定义完成,接下来进入Add函数内部去看看函数是如何进行传参的。

第1,2,3条指令说明把ebp-14h放到eax,如何push压栈,接着找到main函数里面放20的地址,把20的地址放到eax,相当于eax里面放了20,同理ecx里面放入10。

然后到达call指令,call指令把下一条指令的地址存下,因为进入函数内部实现函数功能,等函数结束后会找到原来函数外部的地址,接着运行代码。


和main函数一样前面都是add函数的准备阶段接着要进入add函数内部了。

前面和main函数做法类似不在说明

首先把ebp-8的值放入eax,相当于eax里面放了10,接着ebp+0ch相当于把ebp+12的值放入eax,eax变为30,加起来后把eax放入ebp减8里面,把30放入ebp-8。接着返回call指令保存的地址。

总结:局部变量怎么创建的?
首先为函数开辟一块空间,再在空间里面为我的局部变量开辟一块小空间。
形参和实参怎么样的?
形参只是形参的一份临时拷贝,二者的空间不同。改变形参不影响实参。
函数调用结果怎么返回的?
通过call指令保存原来的地址,等函数调用结束后返回地址

程序员内功修炼——函数栈帧的创建与销毁相关推荐

  1. 程序员内功心法之函数栈帧的创建和销毁

    目录 1.本节目标 2.相关寄存器 3.相关汇编指令 4.什么是函数栈帧 5.什么是调用堆栈 6.函数栈帧的创建和销毁 (1).main函数栈帧的创建与初始化 (2).main函数的核心代码 (3). ...

  2. 【C语言】程序员筑基功法——《函数栈帧的创建与销毁》

    <函数栈帧的创建与销毁> 文章目录 1. 前言 2. 问题引入 3. 前提准备 3.1 寄存器 3.2 汇编指令 4. 函数栈帧的维护 5. 如何调用堆栈 6. 函数栈帧的创建和销毁 6. ...

  3. (动图详解)汇编视角观察函数栈帧的创建和销毁

    目录 ​1.阅读本文的价值 ​2.函数栈帧及栈的概念 ​3.部分寄存器及汇编指令 ​4.main函数的调用 5.main函数的栈帧创建 ​6.变量的栈帧创建 ​6.函数传参 ​7.函数内部运算及销毁 ...

  4. 函数栈帧的创建与销毁

    目录 前言 一.预备知识 1.内存区域的划分和分配 2.栈帧简介 3.寄存器简介 二.函数栈帧介绍 1.源代码 2.如何查看汇编代码 3.函数栈帧的创建与销毁(重点) 三.小彩蛋 总结 前言 最近在学 ...

  5. 函数调用过程详解:函数栈帧的创建与销毁

    前言:我们在学习C语言的过程中,可以会产生很多疑问,比如: 局部变量是怎么创建的 为什么局部变量的值不做初始化就是随机值 函数是怎么传参的?传参的顺序是怎么样的? 形参和实参是什么关系? 函数调用是怎 ...

  6. C语言内功修炼之函数栈帧的创建与销毁(举例加图解)

    大家可能会函数栈帧不了解,可能都没有听过这个,不用着急,在理解函数栈帧之前,我们先来了解一下程序对内存使用的分区大概情况:  区域 作用 栈区(stack) 由编译器自动分配和释放,存放函数的参数值, ...

  7. 内功修炼《函数栈帧的创建和销毁》建议收藏

    文章目录 前言 一. 寄存器的概念 二. 通用寄存器的结构 三. 指针寄存器和变址寄存器 四. EBP和ESP 五.总结 前言 在前期的学习过程中,我们可能会有很多的困惑: 1️⃣ 局部变量是怎么创建 ...

  8. 函数栈帧的创建和销毁图解

    目录 一.问题: 二.寄存器 栈区 1.寄存器有哪些?有什么作用? 2.编译环境 3.栈区的使用习惯: 4.main函数也是被其他函数调用的 5.汇编代码 三.为main函数创建栈帧 1.main函数 ...

  9. 一文带你深入了解函数栈帧的创建和销毁

    作者介绍:友友们好我是沐曦希,可以叫我小沐

最新文章

  1. mysql error number 1130,[转]mysql error number 1130的解决方法
  2. 重磅!分布式数据库解决方案Apache ShardingSphere毕业成为顶级项目
  3. android Adapter剖析理解
  4. Storm单节点部署及启动
  5. systemctl 命令完全指南
  6. Java防止Xss注入json_XSS的两种攻击方式及五种防御方式
  7. 艾为数字ic面试题_每日学习:数字后端面试100问(2019全新版)
  8. 二维动画作品_「咻动画」二维动画制作中角色造型的设计要点
  9. 经纬度之间的距离计算
  10. 使用Docker Swarm部署MinIO ​​​​​​​
  11. SPOJ DQUERY 求区间内不同数的个数 主席树
  12. C#基础复习(4) 之 浅析List、Dictionary
  13. 十六、C语言中的头文件与模块化设计
  14. 数电——全减器分析(用74HC138设计提示)
  15. 实例讲解木马的分析方法
  16. MEGA-X 3D打印机教程:05_更换步进电机驱动
  17. ubuntu修复linux分区表,硬盘分区表的修复(Ubuntu安装盘的另类用法)
  18. 基于华三交换机,限制其他网段的IP访问
  19. FTP虚拟用户(转发)
  20. 学习计划 -- 实时更新

热门文章

  1. 1070[Hansel and Grethel]
  2. Educoder - Java类和对象之对象组合之求圆柱体积
  3. (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  4. idea,配置checkstyle 【提高代码质量,检查代码规范的工具 】Checkstyle,FindBugs,PMD,Jtest
  5. 福禄克网络:突破百米布线的四种方法及优缺点分析
  6. Android自定义View,你必须知道的几点
  7. 点读机什么牌子好,那个牌子的点读机好
  8. 这是您在Factorio上的大脑
  9. 网易云音乐是怎么做曲库缓存的?设计动机大揭秘!
  10. c266 设置邮箱_柯美C226-广东柯美-柯美C226 扫描到u盘设置