函数栈帧(详细图解)

article/2025/10/18 22:17:01

目录

 一、栈

二、常用寄存器及简单汇编指令

三、理解栈帧

3.1 main函数栈帧创建

 3.1.1 main函数栈帧创建动态演示

3.2 局部变量创建

 3.2.1 局部变量创建动态演示 

3.3 函数传参与调用

3.3.1 函数传参

3.3.2 函数传参动态演示 

3.3.3 函数调用

3.3.4 函数返回

四、END


 一、栈

  简单来说栈的主要特点有:

  • 一个限定表尾进行删除(出栈)和插入(入栈)操作的线性表,其过程类似与压子弹与退子弹(后进先出)。
  • 一个由系统自动分配的内存空间,譬如调用函数、创建临时变量时内存空间的创建与销毁。
  • 用于存储函数内部的局部变量、方法调用、函数传参数值等。
  • 由高地址向低地址生长。

 


二、常用寄存器及简单汇编指令

        

寄存器用途
EAX累加寄存器:用于乘除法、函数返回值
EBX用于存放内存数据指针
ECX计数器
EDX用于乘除法、IO指针
ESI源索引寄存器,存放源字符串指针
EDI目标索引寄存器,存放目标字符串指针
ESP存放栈顶指针
EBP存放栈底指针

汇编指令用途
movmov A,B 将数据B移动到A
push压栈
pop出栈
call函数调用
add加法
sub减法
rep重复
lea加载有效地址

三、理解栈帧

       首先,什么是栈帧?引用百度百科:C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。从这句话中,可以提炼以下几点信息:

  • 栈帧是一块因函数运行而临时开辟的空间。
  • 每调用一次函数便会创建一个独立栈帧。
  • 栈帧中存放的是函数中的必要信息,如局部变量、函数传参、返回值等。
  • 当函数运行完毕栈帧将会销毁。

      下面进入主题,图解函数栈帧的创建与销毁过程。

3.1 main函数栈帧创建

     根据VS2013编译器调试,调用堆栈,不难发现main函数的调用链条如下:

     很显然main函数在被调用时,创建了栈帧。在调试过程中将转到反汇编,便能直观的看到main函数栈帧创建的过程。首先需明确的是,函数栈帧由寄存器esp,ebp维护。

008B1410  push        ebp  
008B1411  mov         ebp,esp  
008B1413  sub         esp,0E4h  
008B1419  push        ebx  
008B141A  push        esi  
008B141B  push        edi  
008B141C  lea         edi,[ebp-0E4h]  
008B1422  mov         ecx,39h  
008B1427  mov         eax,0CCCCCCCCh  
008B142C  rep stos    dword ptr es:[edi] //dword 为 4个字节
  1. __tmainCRTStartup()函数顶部压入ebp,如图所示esp指向ebp,ebp成功压入栈中。

     2.esp值传递给ebp。

     3.esp减去0E4h:由于栈先使用高地址后使用低地址,减去一个值意味着esp指针向低地址移动了0E4h个地址,此处便开辟了main函数的栈帧。

     4.压入ebx,esp指向ebx顶部。

     5.压入esi,esp指向esi顶部。

     6.压入edi,esp指向edi顶部。

     7.将edi向下39h个空间全部改为0xCCCCCCCC。

 3.1.1 main函数栈帧创建动态演示

3.2 局部变量创建

int a = 10;
00AA142E  mov         dword ptr [ebp-8],0Ah  int b = 20;
00AA1435  mov         dword ptr [ebp-14h],14h  int ret = 0;
00AA143C  mov         dword ptr [ebp-20h],0  
  1. 将十六进制整数:0Ah(DEC 10)放入ebp 向低地址移动8个字节。
  2. 将十六进制整数:14h(DEC 20)放入ebp 向低地址移动20个字节。
  3. 将十六进制整数:0(DEC 0)放入ebp 向低地址移动32个字节。

 3.2.1 局部变量创建动态演示 

3.3 函数传参与调用

ret = Add(a, b);
00AA1443  mov         eax,dword ptr [ebp-14h]  
00AA1446  push        eax  
00AA1447  mov         ecx,dword ptr [ebp-8]  
00AA144A  push        ecx  
00AA144B  call        00AA10E1  
00AA1450  add         esp,8  
00AA1453  mov         dword ptr [ebp-20h],eax  

     从以上汇编代码可知函数是先传参后调用,函数传参顺序是从右往左。

3.3.1 函数传参

  1. ebp - 14h 的地址传给eax,即eax中实际存放了20。
  2. eax 压栈。
  3. ebp - 8 的地址传给ecx,即ecx中实际存放了10。
  4. ecx 压栈。

3.3.3 函数调用

 ​​​​    可以发现,在执行call指令后,栈中压入call指令的下一条地址。

       进入Add()函数,可以看出这与此前main函数开辟栈帧的过程类似,说明Add()函数调用又开辟了一块独立的栈帧。

       在函数栈帧、局部变量创建完毕后,进行Add()函数运算过程:

c = a + b;
00AA13E5  mov         eax,dword ptr [ebp+8]  
00AA13E8  add         eax,dword ptr [ebp+0Ch]  
00AA13EB  mov         dword ptr [ebp-8],eax  
  1. 将(ebp + 8)的值传递给eax,此时的ebp存放Add函数的栈底指针,(ebp + 8) 的位置即函数传参时创建的ecx的地址,其内部存放的正是10。
  2. eax寄存器中执行求和指令,加上(ebp + 0ch) 中的值,同理可以得知(ebp + 0ch)中的值是20。
  3. 将eax的经过求和的结果,传递到(ebp - 8)的位置 。 

      通过上述过程可以得知函数内部并未给形参开辟空间,而是直接查找了实参传递时的地址,由此解释了形参其实是实参的一份临时拷贝。 

3.3.4 函数返回

return c;
00AA13EE  mov         eax,dword ptr [ebp-8]  

      将返回值传递至寄存器eax中,因此在函数调用结束函数栈帧被销毁时,返回值并不会销毁。在函数拿到返回值后,开始出栈:

00AA13F1  pop         edi  
00AA13F2  pop         esi  
00AA13F3  pop         ebx  
00AA13F4  mov         esp,ebp  
00AA13F6  pop         ebp  
00AA13F7  ret  

      从低位置到高位置依次弹出edi,esi,ebx,随后将ebp赋给esp并弹出ebp,最后执行ret指令返回到调用Add函数的call指令的下一地址,在执行ret指令时实际已弹出After call,以执行指令 add  esp,8,此时esp向高地址移动8字节,esp,ebp重新维护main函数,eax中存放的返回值将被传递给地址(ebp - 20h)即ret的地址。至此,Add函数返回完毕。main函数栈帧销毁过程与前述过程类似。

 


四、END

      通过对函数栈帧创建、销毁过程的剖析使我们不仅了解计算机做了什么,还了解了它是如何做的。通过函数栈帧尝试解析递归等问题相信也会更加直观。笔者水平有限,不足之处还请各位大佬多指教。


http://chatgpt.dhexx.cn/article/l5sPSrbh.shtml

相关文章

栈帧详解——C语言进阶

目录 传统艺能😎过渡区🤣正片开始👀寄存器👏main函数创建👏局部变量创建👏函数部分👏形参与实参👏 传统艺能😎 小编是大一菜鸟不赘述,欢迎大佬指点江山&…

栈帧结构详解

前言 Java虚拟机以方法作为基本的执行单位,“栈帧”是用于支持虚拟机进行方法调用和执行的数据结构,每一个方法从调用开始到执行结束,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程,栈帧也是虚拟机运行时数据区中虚拟机栈的栈…

浅谈栈帧

一、 什么是栈帧? 什么是栈帧,首先引用百度百科的经典解释:“栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。 实际上,可以简单理解为:栈帧就是存储在用户栈上的(当然内…

栈帧(Stack Frame)

0x01.栈在计算机中的应用 在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值,是由系统自动分配的,一般速度较快;存储地址是连续且…

什么是栈帧

栈帧浅析 什么是栈帧 引用百度百科中的解释: 栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。函数的每次调用,都有它自己独立的栈帧。栈帧中维持着函数调用所需要的各种信息,包括函数的入参、函数的局部变…

【详解】函数栈帧——多图(c语言)

目录 前言 一.函数栈帧是什么? 二、栈帧准备知识 1.内存分区 2.什么是栈? 3.esp,ebp,eax寄存器 三、详解栈帧创建与销毁全过程 调用函数之前: 将传入函数的值放入栈中 函数执行: 1.保护当前ebp 2.…

【mcuclub】模数转换ADC0832

一、实物图 二、原理图 编号名称功能1CS片选使能,低电平芯片使能。2CH0模拟输入通道0,或作为IN/-使用。3CH1模拟输入通道1,或作为IN/-使用。4GND电源地5DI数据信号输入,选择通道控制。6DO数据信号输出,转换数据输出。7…

[技术讨论] [DDS] AD9833原理介绍及chiliDDS驱动分享(上)

​ 其实本文还有另一标题:《AD9833调不通?看这篇**就够了》 总觉字里行间隐隐霸气外露,不符合作者低调的风格,于是换了个朴素标题。标题狂不狂暂且不评,作者水平有限却是个事实;看到这篇**是你我缘分&…

ADC0832的使用

百度搜索ADC0832 Datasheet便可以免费获取该芯片的权威数据手册。 最重要的是查看它的时序及对应英文词组的意思。 CLK为时钟信号,需要外部输入,可直接与单片机引脚相连 Chip Select(CS):从Timing图中可以看出芯片工作期间要保持…

ADC0832的AD模数转换原理及编程

✅作者简介:嵌入式领域优质创作者,博客专家 ✨个人主页:咸鱼弟 🔥系列专栏:单片机设计专栏 目录 一、描述 二、模数转换原理: 三、模数转换的过程: 四、八位串行A/D转换器ADC0832简介&…

ADC0809的使用

一、前言介绍 使用ADC0809对一个模拟电压进行转换转换后的电压使用数码管显示出来 二、ADC0809的介绍 1、ADC0809简介 ADC0809是采用COMS工艺制造的双列直插式单片8位A/D转换器。分辨率8位,精度7位,带8个模拟量输入通道,有通道地址译码锁…

基于STM32F103RCT6的AD9833驱动开发(代码可以免费发邮箱)

基于STM32F103RCT6的AD9833驱动开发(代码可以免费发邮箱) AD9833手册分析 管脚定义: 手册就先讲到这里,不明白的欢迎评论区留言,另外我会把代码还有手册一并发送给感兴趣的朋友。 AD9833典型应用电路&#x…

AD9833数字信号发生器模块

简 介: 本文记录了使用快速制版测试AD9833这款数字信号发生器的内容。 关键词: AD9388,数字信号发生,快速制版 基于AD9833的正弦波,三角波,方波频率发生模块可以通过ZIGBEE来完成输入输出控制。其中还包括有…

STM32驱动AD9833模块

STM32驱动AD9833模块 前言软硬件准备一、本次使用的硬件二、代码 链接 前言 淘宝上买了个AD9833模块,stm32用商家的例程代码可以调频,可以调相,就是调不了幅度。换了几块不同32开发板都不行,重新以正点原子F103的工程为基础把驱动…

AD9833信号波形谐波

AD9833产生高频信号的谐波 ~ AD9833是一款AnalogDevices公司提供的数字信号可编程信号发生器芯片。它一般配有外置的主时钟信号,每次时钟信号将将内部28位的相位累加器递增一个相位数值。该相位数值由芯片SPI串口被外部的MCU设置。 相位累加器的高12位选择内部4096…

51驱动AD9833

使用51驱动AD9833模块的使用 关于AD9833相关参数程序流程代码片上传程序总结 原文链接:https://www.yourcee.com/newsinfo/2925703.html 关于AD9833 AD9833是一款低功耗、可编程波形发生器,能够产生正弦波、三角波和方波输出。各种类型的检测、信号激励…

Arduino + AD9833 波形发生器

Arduino SI5351 方波发生器_姜戈12的博客-CSDN博客SI5351 方波发生器https://blog.csdn.net/jiangge12/article/details/125815044 感觉 Si5351 只有方波还是少点意思。 看到有人做 AD9833 ,成品卖355元。https://www.bilibili.com/video/av463721457/ 上面视频…

[技术讨论][DDS] AD9833原理介绍及chiliDDS驱动分享(上)

其实本文还有另一标题:《AD9833调不通?看这篇**就够了》 总觉字里行间隐隐霸气外露,不符合作者低调的风格,于是换了个朴素标题。标题狂不狂暂且不评,作者水平有限却是个事实;看到这篇**是你我缘分&#xff…

STM32单片机TFT显示AD9833 DDS信号发生器语音播报正弦波方波三角波

实践制作DIY- GC0146---TFT显示AD9833 DDS信号发生器 基于STM32单片机设计---TFT显示AD9833 DDS信号发生器 二、功能介绍: 硬件组成:STM32F103C系列最小系统板 1.8寸TFT彩屏AD9833信号模块4*4矩阵键盘DY-SV17F语音播报模块 1.通过4*4键盘来设定频率值和…

失真很大的波形发生器AD9833

波形发生器AD9833 01 波形发生器 一、AD9833 AD9833是一款AnalogDevices公司提供的数字信号可编程信号发生器芯片。 它一般配有外置的主时钟信号,每次时钟信号将将内部28位的相位累加器递增一个相位数值。 该相位数值由芯片SPI串口被外部的MCU设置。  相位累加器…