栈:
- 在数据结构中, 栈是限定仅在表尾进行插入或删除操作的线性表。栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。
- 在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值,是由系统自动分配的,一般速度较快;存储地址是连续且存在有限栈容量,会出现溢出现象程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增大,而弹出操作使栈减小。栈用于维护函数调用的上下文,离开了栈函数调用就没法实现。
栈帧:
每一次函数的调用,都会在调用栈(call stack)上维护一个独立的栈帧(stack frame).每个独立的栈帧一般包括:
- 函数的返回地址和参数
- 临时变量:包含函数的函数的非静态局部变量以及编译器自动生成的其他临时变量
- 函数调用的上下文
栈是从高地址向低地址延伸的,一个函数的栈帧用ebp和esp这两个寄存器来划定范围。ebp指向当前栈帧的底部,esp指向栈帧的顶部
ebp寄存器又称为帧指针(Frame Point)(fp)
esp寄存器又称为(Stack Point)(sp)
在函数调用的过程中,有函数的调用者(caller)和被调用的函数(callee)
调用者需要知道被调用者函数的返回值
被调用者需要知道传入的参数和返回的地址
函数的调用
函数调用分为一下几步:
- 参数入栈:将参数按照调用约定(c是从右向左)依次压入系统栈中;
- 返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行;
- 代码转跳:处理器将代码区跳转到被调用函数的入口处;
- 栈帧调整:
- 将调用者的ebp压栈处理,保存指向栈底的ebp的地址(方便函数返回之后的现场恢复),此时esp指向新的栈顶位置push ebp
- 将当前栈帧切换到新栈帧(将eps值装入ebp更新栈帧底部),这时ebp指向栈顶。而此时栈顶就是old ebp mov ebp, esp
- 给新栈帧分配空间sub esp, xxx
函数返回
- 保存被调用函数的返回值到eax寄存器中 mov eax, xxx
- 恢复esp同时回收局部变量空间 mov ebp,esp
- 将上一个栈帧底部位置恢复到ebppop ebp
- 弹出当前栈顶的元素,,从栈中取出返回地址,并转跳到该地址ret