函数栈帧的创建和销毁
- 越高级的编译器,越不容易学习和观察该过程
- 同时在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现
1.寄存器:ebp 和 esp(和函数栈帧有关)
esp:栈顶指针 ; ebp:栈低指针
寄存器集成在CPU上的
ebp 和 esp 这两个寄存器中存放的是地址
这两个地址是用来维护函数栈帧的
1. 每一次函数调用,都要在栈区创建一个空间
2. 正在调用哪个函数,esp 和 ebp 就在维护哪个函数的函数栈帧
3. esp 和 ebp 之间的空间就是系统为这次函数所调用的空间,叫这次函数的函数栈帧
4. 栈区的使用习惯是先使用高地址,再使用低地址
5. 空间消耗时,从高地址向低地址消耗
6. 再开辟新空间时,使用的空间是上面的空间(往上使用)
7. 像栈一样,放数据是在顶上(栈顶)放数据
测试代码:
#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; }
在VS2013中,main函数也是被其它函数调用的
mainCRTStartup --> __tmainCRTStartup --> main函数
(调用) (调用)
(所以实际开辟的空间为:)
(查看汇编代码:)
(1).push(压栈):给栈顶放一个元素
[补充:pop(出栈) --> 从栈顶删除一个元素]
(压栈前:)
(压栈后:esp会往上移,移到压的元素上方)
(2).mov(把后面的值赋给前面,把esp的值赋给ebp):
(3).sub(让esp减去一个十六进制数):
(4).连续push三次:
(5).lea(load effective address -- 加载有效地址,把一个有效地址加载到edi中):
(6).两次mov后,rep stos:
之前出现过的“烫烫烫”乱码的原因:
变量未初始化,变量里面的数据就是“cc cc cc cc”,这些“cc cc cc cc”在使用后会产生随机值,即"烫烫烫",而初始化就会将这些随机值覆盖。
(7).产生局部变量:int a = 10; (mov)
(8).产生局部变量:int b = 20; (mov)