目录
一、问题:
- 局部变量是怎么创建的:
- 为什么局部变量不初始化是随机值:
- 函数是怎么传参的,传参的顺序是怎样的:
- 形参和实参是什么关系:
- 函数调用结束后是怎么返回的:
- 返回值如何带回:
二、寄存器 栈区
1、寄存器有哪些?有什么作用?
eax
ebx
ecx
edx
ebp
esp
ebp和esp这2个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的。
2、编译环境
越高级的编译器函数栈帧的封装越不容易看,这里的代码是用VS2013写的
//测试代码
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;
}
3、栈区的使用习惯:
先使用高地址空间再使用低地址空间,高地址空间使用完再使用低地址的空间。
所以esp称为栈顶指针,ebp称为栈底指针
4、main函数也是被其他函数调用的
5、汇编代码
三、为main函数创建栈帧
1、main函数之前的函数
2、压栈push
3、为main函数预开辟空间
三、准备abc变量
四、调用Add函数
五、进入函数
六、返回
七、总结:
1、局部变量是怎么创建的:
为函数分配好栈帧空间,栈帧空间里初始了部分空间,局部变量在栈帧里分配一些空间
2、为什么局部变量不初始化是随机值:
因为是我们初始化时放进去的,如果不对局部变量进行初始化,就是CCCCCCCC,也就是我们看见的随机值。
3、函数是怎么传参的,传参的顺序是怎样的:
还没有传参的时候,已经push从右向左开始压栈,把两个参数压进去了,
4、形参和实参是什么关系:
形参是我们压栈的时候开辟的空间,形参是实参的一份临时拷贝,他们的空间是独立的,改变形参不会影响实参。
5、函数调用结束后是怎么返回的:
在调用函数之前我们就把call指令的下一条指令压进去了,把ebp调用这个函数的上一个函数的栈帧ebp地址记住了,当我们要返回函数的时候,弹出ebp,就能找到上一个函数调用的ebp,指针往下走的时候,就能够找到esp的顶部,回到栈帧空间。
记住了call指令的下一条指令的地址,返回的时候,就能跳转到call指令的下一条指令的地址,这样就能返回函数。