目录
- 1.栈帧
- 1.进程地址空间
- 2.栈帧说明
- 2.认识相关寄存器
- 3.认识相关汇编命令
- 4.过程理解
- 5.栈帧总结
- 6.补充
1.栈帧
1.进程地址空间
.进程地址空间
2.栈帧说明
- 调用函数,形成栈帧
- 函数返回,释放栈帧
- 局部变量是存放在栈区上的
- 栈区内存的使用习惯是:
- 先使用高地址空间,再使用低地址空间
- 如:数组随着下标的增长,地址是由低到高变化的
2.认识相关寄存器
eax
:通用寄存器,保留临时数据,常用于返回值ebx
:通用寄存器,保留临时数据ebp
:栈底寄存器esp
:栈顶寄存器eip
:指令寄存器,保存当前指令的下一条指令的地址
3.认识相关汇编命令
mov
:数据转移指令push
:数据入栈,同时esp
栈顶寄存器也要发生改变pop
:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变sub
:减法命令add
:加法命令call
:函数调用,1. 压入返回地址 2. 转入目标函数- 将当前指令的下一条指令入栈(push到栈中,影响ESP)
- 跳转到目标函数起始地址处运行(修改EIP,到达目标函数)
jump
:通过修改eip
,转入目标函数,进行调用ret
:恢复返回地址,压入eip
,类似pop eip
命令
4.过程理解
-
起步,
main()
也是要被调用的
-
main()
也要形成栈帧结构
-
起步
-
开始调用
-
调用
call
前
-
调用
call
后
-
整体图解
-
-
形成栈帧
-
释放栈帧
-
释放临时拷贝,彻底释放空间
5.栈帧总结
- 调用函数,需要先形成临时拷贝,形成过程是从右向左的
- 临时空间的开辟,是在对应函数栈帧内部开辟的
- 函数调用完毕,栈帧结构被释放掉
- 临时变量具有临时性的本质:栈帧具有临时性
- 调用函数是有成本的,成本体现在时间和空间上,本质是形成和释放栈帧有成本
- 函数调用,因拷贝所形成的临时变量,变量和变量之间的位置关系是有规律的(地址连续)
6.补充
- 堆上都是动态分配,做不到静态分配
- 栈既可以静态分配,也可以动态分配
- 静态分配 – 在函数体中创建了一个变量
- 动态分配
- 头文件
<malloc.h>
下,有一个void* __cdecl alloca(size_t)
- 作用与malloc等类似,但是它申请的是“栈(stack)”空间的内存
- 用完会在退出栈时自动释放,无需手动释放
- 头文件