
◆ 博主名称: 小此方-CSDN博客
大家好,欢迎来到小此方的博客。
🔥个人专栏:《C语言》_小此方的博客-CSDN博客
🔥 努力成就未来,代码改变世界,相信我有一天也能成为改变世界的那个人

●局部变量是怎么创建的? ●为什么局部变量的值是随机值? ●函数是怎么传参的?传参的顺序是怎样的? ●形参和实参是什么关系? ●函数调用是怎么做的? ●函数调用结束后怎么返回的?
没关系,看完这篇文章,你一定能对这些问题门儿清。
让我们直接上正片:
(以以下代码为例,考虑到编译器版本过新,对栈帧创建和销毁的封装就越深,越不容易被观察;所以本次采用VS2013编译器进行观察。)
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并不是整个”程序真正的出发点“

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

接下来为大家介绍一个新概念:寄存器
寄存器是CPU内部的高速存储单元,用于临时存放指令、数据和地址。其读写速度远高于内存,用于支持CPU的快速运算和数据交换。
常见的寄存器有这些:eax,ebx,ecx,edx.
以及两个特殊寄存器:esp和ebp(用来维护被创建出来的函数栈帧)
如图:

esp被称为栈顶指针;ebp被称为栈底指针。
分别指向这块函数栈帧的顶部和底部:
回到反汇编这张图

在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。
解析出来也就是乱码:烫烫烫烫烫烫烫烫。
本期内容就到这里,感谢大家的观看!