详解栈帧结构

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

https://www.1024do.com/?p=367

栈帧结构

含义:C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。栈帧也叫过程活动记录,是编译器用来实现过程函数调用的一种数据结构。

从逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。实现上有硬件方式和软件方式(有些体系不支持硬件栈)首先应该明白,栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。

注意:ebp指向当前位于系统栈最上边一个栈帧的底部,而不是系统栈的底部。严格说来,“栈帧底部”和“栈底”是不同的概念;esp所指的栈帧顶部和系统栈的顶部是同一个位置。

首先画一个地址空间图给大家加深理解:

 

既然今天分析的是栈帧,那么肯定是在栈区展开研究,下面为大家总体上画一张栈帧结构图:

 

接下来,首先看一下变量压栈的次序以及对应的汇编代码:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <stdio.h>

#include <windows.h>

int fun(int x, int y)

{

int c = 0xcccccccc;

printf("I am fun function!\n");

return c;

}

int main()

{

int a = 0xaaaaaaaa;

int b = 0xbbbbbbbb;

int ret = fun(a, b);

printf("you should running here!\n");

system("pause");

return 0;

}

 

在main函数调用fun函数之前,也就是main的栈帧结构:main函数的栈底ebp,栈顶esp。从低地址esp到高地址ebp,就是main函数的栈帧:

 

现在开始调用fun函数:这里用到了一条汇编指令:call:调用函数。

call有两大功能:①保存当前指令的下一条指令②修改栈底指针ebp。换句话说:call指令的效果是将返回地址入栈,并跳转到被调用过程的起始点。返回地址是在程序中紧跟call后面的那条指令的地址,这样被调用过程返回时,执行会从此处开始。

同样的一点,我们首先看一下汇编代码:

 

从代码和图中不难看出,在main函数里面,地址为008B14A4 的call指令调用函数fun,其中指明了栈帧esp和程序计算器pc的值,call指令随即将返回地址008B14A9压栈,并跳转到fun的第一条指令。到此main栈帧结束。

Call命令出现预示着一个旧的栈帧的结束,也印证了新的栈帧的到来:(汇编代码过长,图中将取重要的点来说)

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

#include <stdio.h>

#include <windows.h>

int fun(int x, int y)

{

int c = 0xcccccccc;

int *p = &x;

printf("I am fun function!\n");

p++;

printf("before: %x\n", y);

*p = 0xdddddddd;

printf("after : %x\n", y);

 

return c;

}

 

int main()

{

int a = 0xaaaaaaaa;

int b = 0xbbbbbbbb;

int ret = fun(a, b);

printf("you should running here!\n");

system("pause");

return 0;

}

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

int fun(int x, int y)

{

008B13A0  push        ebp  

008B13A1  mov         ebp,esp  

008B13A3  sub         esp,0D8h  

008B13A9  push        ebx  

008B13AA  push        esi  

008B13AB  push        edi  

008B13AC  lea         edi,[ebp-0D8h]  

008B13B2  mov         ecx,36h  

008B13B7  mov         eax,0CCCCCCCCh  

008B13BC  rep stos    dword ptr es:[edi]  

int c = 0xcccccccc;

008B13BE  mov         dword ptr [c],0CCCCCCCCh  

int *p = &x;

008B13C5  lea         eax,[x]  

008B13C8  mov         dword ptr [p],eax  

printf("I am fun function!\n");

008B13CB  mov         esi,esp  

008B13CD  push        offset string "I am fun function!\n" (8B575Ch)  

008B13D2  call        dword ptr [__imp__printf (8B82B8h)]  

008B13D8  add         esp,4  

008B13DB  cmp         esi,esp  

008B13DD  call        @ILT+305(__RTC_CheckEsp) (8B1136h)  

p++;

008B13E2  mov         eax,dword ptr [p]  

008B13E5  add         eax,4  

008B13E8  mov         dword ptr [p],eax  

printf("before: %x\n", y);

008B13EB  mov         esi,esp  

008B13ED  mov         eax,dword ptr [y]  

008B13F0  push        eax  

008B13F1  push        offset string "before: %x\n" (8B574Ch)  

008B13F6  call        dword ptr [__imp__printf (8B82B8h)]  

008B13FC  add         esp,8  

008B13FF  cmp         esi,esp  

008B1401  call        @ILT+305(__RTC_CheckEsp) (8B1136h)  

*p = 0xdddddddd;

008B1406  mov         eax,dword ptr [p]  

008B1409  mov         dword ptr [eax],0DDDDDDDDh  

printf("after : %x\n", y);

008B140F  mov         esi,esp  

008B1411  mov         eax,dword ptr [y]  

008B1414  push        eax  

008B1415  push        offset string "after : %x\n" (8B573Ch)  

008B141A  call        dword ptr [__imp__printf (8B82B8h)]  

008B1420  add         esp,8  

008B1423  cmp         esi,esp  

008B1425  call        @ILT+305(__RTC_CheckEsp) (8B1136h)  

 

return c;

008B142A  mov         eax,dword ptr [c]  

}

008B142D  pop         edi  

008B142E  pop         esi  

008B142F  pop         ebx  

008B1430  add         esp,0D8h  

008B1436  cmp         ebp,esp  

008B1438  call        @ILT+305(__RTC_CheckEsp) (8B1136h)  

008B143D  mov         esp,ebp  

008B143F  pop         ebp  

008B1440  ret

 


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

相关文章

函数栈帧详解

目录 一.什么是函数栈帧 1.寄存器&#xff1a; 2.函数栈帧 3.栈帧的作用和维护 4.栈帧结构 二.函数栈帧的创建 1.汇编代码 2.main函数函数栈帧的创建 1.汇编语言讲解&#xff1a; 2.栈帧创建&#xff1a; 3.详细步骤 3.ADD函数栈帧的创建 栈帧创建&#xff1a; 3.函…

栈帧

首先应该明白,栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(地址地)。下图为典型的存取器安排,观察栈在其中的位置 入栈操…

什么是函数栈帧

函数栈帧的创建与销毁 一、函数栈帧的创建1.寄存器2.函数栈帧3.函数中调用函数 二、函数栈帧的销毁总结 一、函数栈帧的创建 1.寄存器 一般来说&#xff0c;计算机中的寄存器有六种 分别是&#xff1a;eax, ebx, ecx,edx,ebp,esp 而ebp,esp这两个寄存器中存放的是地址&#…

栈帧 stack frame

栈帧 stack frame 每一次函数调用都会维护一个栈帧&#xff08;stack frame&#xff09;&#xff0c;栈帧主要用于传递参数、保存返回地址、保存局部变量等。先直接上一个《深入理解计算机系统》上的原图。 其中&#xff0c;%rsp 指向栈顶位置&#xff0c;%rbp 指向栈底位置。…

C/函数栈帧

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;C语言学习笔记 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ​ 目录 前言 寄存器 1. 寄存器的种类与功能 C语言汇编指令介绍 函数栈帧的创建与销毁过程 1.函数栈帧的…

浅谈函数栈帧(Stack Frame)

&#x1f499;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;C 本文目录 什么是栈帧 在调试中观察 总结 什么是栈帧 那我们先来看看什么是栈&#xff1a; 栈(stack)是限定仅在表尾进行插入或者删除的线性表。栈是一种数据结构&#xff0c;它按照后进先出的原则存储…

栈和栈帧

栈 堆栈(stack)又称为栈或堆叠&#xff0c;是计算机科学里最重要且最基础的数据结构之一&#xff0c;它按照FILO&#xff08;First In Last Out&#xff0c;后进先出&#xff09;的原则存储数据。 栈的相关概念&#xff1a; 栈顶和栈底&#xff1a;允许元素插入与删除的一端…

函数栈帧的创建和销毁(图解)

目录 基础知识介绍1. 寄存器的种类与功能2. 常用汇编指令3. 内存模型 演示函数栈帧的创建销毁过程1. 为main()函数开辟栈帧2. 在main()函数中创建变量3. 调用Add()函数前的准备4. 为Add()函数开辟栈帧5. 在Add()函数中创建变量并运算6. Add()栈帧的销毁7. 返回main()函数栈帧 总…

运行时栈帧结构是怎样的?

写在前面 本文隶属于专栏《100个问题搞定Java虚拟机》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和文献引用请见100个问题搞定Java虚拟机 解答 栈帧(Stack Frame)是J…

函数栈帧(详细图解)

目录 一、栈 二、常用寄存器及简单汇编指令 三、理解栈帧 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…

栈帧详解——C语言进阶

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

栈帧结构详解

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

浅谈栈帧

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

栈帧(Stack Frame)

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

什么是栈帧

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

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

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

【mcuclub】模数转换ADC0832

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

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

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

ADC0832的使用

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

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

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