目录

​1、阅读本文的价值

​2、函数栈帧及栈的概念

​3、部分寄存器及汇编指令

​4、main函数的调用

5、main函数的栈帧创建

​6、变量的栈帧创建

​6、函数传参

​7、函数内部运算及销毁

​8、通过函数栈帧引发的思考

​1、局部变量是如何创建的?

​2、 为什么局部变量不初始化是随机的?

​3、函数调用时参数时如何传递的?传参的顺序是怎样的?

4、 函数的形参和实参分别是怎样实例化的?

​5、 函数的返回值是如何带回的?


1、阅读本文的价值

话不多说先上图!

先从某招聘网站随便扒了两张岗位JD。由于博主在宁波,实体经济还是比较强的【外边真的全是嵌入式

那么面试官就会问了,小伙子你了解过汇编么?

我曾从汇编的角度描述过函数栈帧的创建与销毁!(本篇的意义在于了解汇编与深挖函数栈帧的创建与销毁,为后期理解栈区打好基础。)

2、函数栈帧及栈的概念

函数栈帧(stack frame)就是函数调用过程中在程序的调用栈(call stack)所开辟的空间,这些空间是用来存放:

1、函数参数和函数返回值

2、临时变量(包括函数的非静态的局部变量以及编译器自动生产的其他临时变量)

3、保存上下文信息(包括在函数调用前后需要保持不变的寄存器)。

栈:用户可以将数据压入栈中(入栈,push),也可以将已经压入栈中的数据弹出(出栈,pop),但是栈这个容器必须遵守一条规则:先入后出(First In Last Out, FILO)。在计算机系统中,栈则是一个具有以上属性的动态内存区域。压栈操作使得栈增大,而弹出操作使得栈减小。 在经典的操作系统中,栈总是向下增长(由高地址向低地址)的。

3、部分寄存器及汇编指令

1、部分寄存器

eax (通用寄存器)

通常用来执行加法,函数调用的返回值一般也放在这里面

ebx (通用寄存器)

保留临时数据

esp (通用寄存器)

栈顶寄存器,指向栈的顶部

ebp (通用寄存器)

栈底寄存器,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量

eip (指令寄存器)

最重要的寄存器,它指向了下一条要执行的指令所存放的地址

2、部分汇编指令

mov (通用数据传送指令)

数据转移指令

push (通用数据传送指令)

数据入栈,同时esp栈顶寄存器也要发生改变

pop (通用数据传送指令)

数据弹出至指定位置,同时esp栈顶寄存器也要发生改变

sub (算术运算指令)

减法

add (算术运算指令)

加法

call (子程序调用指令)

函数调用1. 压入返回地址 2. 转入目标函数

jump(无条件程序转移指令)

通过修改eip,转入目标函数,进行调用

ret (子程序或函数返回指令)

恢复返回地址,压入eip,类似pop eip命令

4、main函数的调用

本次以加法函数为例:

#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()函数被static int __cdecl invoke_main()进行调用,从__cdecl中能看出C语言函数参数的压栈的顺序是从右向左压入栈中,例如C函数 Fun(a,b,c)函数调用时,参数压栈顺序为 c , b , a。

main()函数结束时的return 0,返回至int const main_result中。

5、main函数的栈帧创建

1、main函数汇编代码

int main()
{
003A18B0  push        ebp//在栈中压入ebp的值
003A18B1  mov         ebp,esp//把esp的值给ebp
003A18B3  sub         esp,0E4h//把esp的值减去0E4h
003A18B9  push        ebx//在栈中压入ebx的值
003A18BA  push        esi//在栈中压入esi的值
003A18BB  push        edi//在栈中压入edi的值
003A18BC  lea         edi,[ebp-24h]//把ebp-24h放入edi中
003A18BF  mov         ecx,9//把9的值给ecx
003A18C4  mov         eax,0CCCCCCCCh//把0CCCCCCCCh放入eax
003A18C9  rep stos    dword ptr es:[edi]//从edi开始向下ecx的区域放入eax 

2、动图详解

此处注意0CCCCCCCCh是从低地址向高地址创建的。

6、变量的栈帧创建

1、变量的汇编代码

    int a = 10;
003A18D5  mov         dword ptr [ebp-8],0Ah//在ebp-8位置处放入0Ah,即a的值  int b = 20;
003A18DC  mov         dword ptr [ebp-14h],14h//在ebp-14h位置处放入14,即b的值int c = 0;
003A18E3  mov         dword ptr [ebp-20h],0//在ebp-20h位置处放入0,即c的值 

2、动图详解

6、函数传参

1、传参的汇编代码

 c = Add(a, b);
003A18EA  mov         eax,dword ptr [ebp-14h]//把ebp-14h地址的值放入eax中
003A18ED  push        eax//压入eax
003A18EE  mov         ecx,dword ptr [ebp-8]//把ebp-8地址的值放入ecx中
003A18F1  push        ecx//压入ecx
003A18F2  call        003A10B4//调用add函数,栈顶保存call指令的下一条指令
003A18F7  add         esp,8//形参销毁
003A18FA  mov         dword ptr [ebp-20h],eax//形参销毁  

2、动图详解

注意传参时,形参是实参的一份临时拷贝,需要创建相同大小的空间用于传参,所以传值调用的效率往往不如传址调用。

7、函数内部运算及销毁

1、函数的汇编代码

int Add(int x, int y)
{
003A1770  push        ebp
003A1771  mov         ebp,esp
003A1773  sub         esp,0CCh
003A1779  push        ebx
003A177A  push        esi
003A177B  push        edi
003A177C  lea         edi,[ebp-0Ch]
003A177F  mov         ecx,3
003A1784  mov         eax,0CCCCCCCCh
003A1789  rep stos    dword ptr es:[edi]
003A178B  mov         ecx,3AC008h
003A1790  call        003A131B  int z = 0;
003A1795  mov         dword ptr [ebp-8],0  z = x + y;
003A179C  mov         eax,dword ptr [ebp+8]
003A179F  add         eax,dword ptr [ebp+0Ch]
003A17A2  mov         dword ptr [ebp-8],eax  return z;
003A17A5  mov         eax,dword ptr [ebp-8]//把ebp-8的值放到eax寄存器中,让寄存器把结果带出函数
}
003A17A8  pop         edi//弹出edi,同时esp地址增加
003A17A9  pop         esi
003A17AA  pop         ebx
003A17AB  add         esp,0CCh
003A17B1  cmp         ebp,esp
003A17B3  call        003A1244
003A17B8  mov         esp,ebp
003A17BA  pop         ebp//通过ebp找回main的栈底
003A17BB  ret

2、动图详解

通过eax寄存器把函数计算结果带给c。

8、通过函数栈帧引发的思考

1、局部变量是如何创建的?

首先需要为函数分配栈帧空间,在函数的栈帧空间初始化完成后,再为局部变量分配空间。

2、 为什么局部变量不初始化是随机的?

因为在栈帧空间初始化的过程中,通过动图演示,可以看到栈帧空间的部分区域被初始化为0CCCCCCCCh,若局部变量不初始化,将会被赋值为这个值,这也是“烫烫烫”的成因。(全局变量不初始化为0)

3、函数调用时参数时如何传递的?传参的顺序是怎样的?

函数调用时,会先在main函数内压入形参,函数参数通过从右向左的压栈方式向函数传递形参。当函数内部需要使用形参时,通过指针偏移量找到传参时生成的形参。

4、 函数的形参和实参分别是怎样实例化的?

在函数调用时,形参才开辟空间,形参与实参的值相同,但所属的空间不同,改变形参不会改变实参。

5、 函数的返回值是如何带回的?

在函数调用前,把call指令下一条指令的地址压入栈中,并且把上一个函数的ebp压入栈中,函数调用完毕,通过弹出ebp找到原始函数的栈底,同时使用压入栈中的地址找到下一条所要执行语句的地址。返回值是通过寄存器带出的。


关注!点赞!评论!收藏!关注!点赞!评论!收藏!关注!点赞!评论!收藏!关注!点赞!评论!收藏!关注!点赞!评论!收藏!

(动图详解)汇编视角观察函数栈帧的创建和销毁相关推荐

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

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

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

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

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

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

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

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

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

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

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

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

  7. 程序员内功修炼——函数栈帧的创建与销毁

    一.什么是函数的栈帧 c语言是由函数构成的,那么函数是如何进行传参的?如何调用的?如何返回值的?这些问题与函数的栈帧有关. 函数栈帧:就是函数调用过程中程序的调用栈所开辟的空间,这些空间用来存放: 1 ...

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

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

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

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

最新文章

  1. 【scala】类的定义和单例对象
  2. is_best = recent_bleu4 > best_bleu4
  3. .netcore2.0 发布CentOS7
  4. dataframe修改列名_python dataframe操作大全数据预处理过程(dataframe、md5)
  5. java中截取部分字符串_JAVA中截取字符串substring用法详解
  6. 【guava】GuavaCache缓存失效的时候做一些操作 RemovalListener
  7. MSSQL 2012 密钥
  8. 银监计算机类考试题库,干货!国考银监会财经类面试题库
  9. [开源] PLC梯形图转指令表的算法源代码
  10. LSB算法分析与实现
  11. AB测试-最佳方案测试
  12. 13级计算机商务沟通与礼仪结课论文,商务沟通论文
  13. 常州一中训练试题泛做 Part 1
  14. count(1)、count(*)、count(列名) 详解
  15. 吴恩达:如何学习机器学习
  16. 微信小程序 展示地图指定位置导航
  17. java坦克大战案例_JAVA实现经典坦克大战源代码
  18. 008 解决问题的策略 转化(苏教版 五下)
  19. 内蒙古最新八大员安全员模拟真题题库及答案
  20. python 运行不过去SyntaxError: Non-ASCII character '\xc2' in file

热门文章

  1. 益圆木门 | 门墙同色,营造高级艺术范儿!
  2. 平均电流型LED降压恒流驱动器
  3. UE4 实现UMG 简单涂鸦
  4. Redis HA篇 +集群搭建
  5. c语言健康状况检查系统设计,智能健康监护仪设计(含电路原理图)
  6. [045] 微信公众平台开发教程第21篇-“可信网址”白名单
  7. 【QT 5 学习笔记-学习绘图相关+画图形图片等+绘图设备+基础学习(2)】
  8. 【Solidity】6. 合约 - 深入理解Solidity
  9. docker的基础使用
  10. dell系统重装后无法进入系统_小编告诉你dell装系统按哪个键进入bios