首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >深度解剖之函数栈帧的创建和销毁原理(上)

深度解剖之函数栈帧的创建和销毁原理(上)

作者头像
小此方
发布2025-12-24 17:35:55
发布2025-12-24 17:35:55
70
举报

◆ 博主名称: 小此方-CSDN博客

大家好,欢迎来到小此方的博客。

🔥个人专栏:《C语言》_小此方的博客-CSDN博客

🔥 努力成就未来,代码改变世界,相信我有一天也能成为改变世界的那个人


●局部变量是怎么创建的? ●为什么局部变量的值是随机值? ●函数是怎么传参的?传参的顺序是怎样的? ●形参和实参是什么关系? ●函数调用是怎么做的? ●函数调用结束后怎么返回的?

你是否还在为这些问题而困扰?

没关系,看完这篇文章,你一定能对这些问题门儿清。

让我们直接上正片:

(以以下代码为例,考虑到编译器版本过新,对栈帧创建和销毁的封装就越深,越不容易被观察;所以本次采用VS2013编译器进行观察。)

代码语言:javascript
复制
int Add(int a,int b)
{
    z=a+b;
    return z;
}

int main ()
{
    int a=10;
    int b=20;
    int c=Add(a,b);
    return 0;
}

F10开始调试:右击代码转到反汇编:如图

一,反汇编界面介绍

如图,当我们打开反汇编界面:

◆ 淡蓝色部分:该项汇编语句执行的操作。

◆ 橙色部分:执行的操作内容。

◆ 深红色部分:该语句的地址。

◆ 深蓝色部分:源代码。

建议将右上角的显示符号名关闭;方便观察。

二,怎样为main函数开辟栈帧

1.函数的起点

如果在反汇编页面翻一翻,你会看到,事实上main并不是整个”程序真正的出发点“

● mainCRTStartup()调用了__tmainCRTStartup();

● __tmainCRTStartup()再调用了main()函数。所以我们画一个图:

2.寄存器

接下来为大家介绍一个新概念:寄存器

寄存器是CPU内部的高速存储单元,用于临时存放指令、数据和地址。其读写速度远高于内存,用于支持CPU的快速运算和数据交换。

常见的寄存器有这些:eax,ebx,ecx,edx.

以及两个特殊寄存器:esp和ebp(用来维护被创建出来的函数栈帧)

如图:

esp被称为栈顶指针;ebp被称为栈底指针。

分别指向这块函数栈帧的顶部和底部:

3.压栈,开辟,填充

回到反汇编这张图

在main任然没有被调用时,

esp和ebp被用来维护 __tmainCRTStartup()函数的栈帧,。

我们可以将函数栈帧的开辟想想成搭积木(房子)

◆ 第一步:”push“,这一步被称为压栈:顾名思义就是将数据压到当前栈帧的顶部。

压栈分为两个小步骤:压数据和移动栈顶指针:相当于把房子造高了,房顶(esp)也就跟着变高了。

◆ 第二步:“mov”(move)移动:就是将esp的数据(栈顶地址)给到ebp,让ebp指向esp所指向的位置(如图)。

◆ 第三步:“sub”做减法:意思就是esp指针减去0E4h这个十六进制数字。我们把房顶抬升到了一个非常高的高度:main函数的栈帧初步创建完成。

三,烫烫烫烫烫烫烫烫

”手持两把锟斤拷,口中疾呼烫烫烫“

这是在时是每个程序员都知道的一句梗:也就是”乱码“。当我们试图打印没有被初始化的变量时也会出现这种情况。原因在这里

接着前文,我们继续分析:

◆ 第四步:我们将ebp-0E4h给到edi(如图),

◆ 接下来三步是合在一起的

39h这个数字存入ecx寄存器,0CCCCCCCCh存入eax寄存器

【插曲:word表示双字两个字节,dword(double word)表示两倍双字:也就是4个字节】

dwoed ptr es : [edi]表示:将从edi开始的39h个长度的内存全部初始化为0CCCCCCCCh。

◆ 第八步:

为变量开辟空间:如图:我们为变量a,b,c分别在ebp-8h,ebp-14h,ebp-20h处创建空间,并赋值。赋值是关键!如果不赋值:当我们打印比如a的时候,我们实际上访问到的0CCCCCCCCh。

解析出来也就是乱码:烫烫烫烫烫烫烫烫。

本期内容就到这里,感谢大家的观看!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 你是否还在为这些问题而困扰?
    • 一,反汇编界面介绍
    • 二,怎样为main函数开辟栈帧
      • 1.函数的起点
      • 2.寄存器
      • 3.压栈,开辟,填充
    • 三,烫烫烫烫烫烫烫烫
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档