栈帧

部分来源:https://www.jianshu.com/p/b666213cdd8a

什么是栈?

在数据结构中, 栈是限定仅在表尾进行插入或删除操作的线性表。栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。

“栈” 一般是指一种数据结构,而 “堆栈” 是指内存中的存储结构。

在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值,是由系统自动分配的,一般速度较快;存储地址是连续且存在有限栈容量,会出现溢出现象程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增大,而弹出操作使栈减小。
栈用于维护函数调用的上下文,离开了栈函数调用就没法实现。

而什么是栈帧(Stack Frame)呢?

每个线程创建时会被分配 1MB 大小的私有内存空间,这个空间就是 堆栈。而堆(heap)不同,堆是整个进程共享的,用于存放无法预知大小的数据,例如对象。

方法是在栈上执行的,其局部变量(值类型和引用类型的指针)占用空间较小,所用空间是可以提前计算的,因此放在栈上,可以提高运行效率。

线程栈 中包括很多栈帧,栈帧就是栈的一部分连续空间,用以存放一个方法的变量、出口等信息。当一个方法被调用时,就会给它分配一个栈帧,方法调用结束后回收这个栈帧。

每一次函数的调用, 都会在调用栈(call stack)上维护一个独立的栈帧(stack frame).每个独立的栈帧一般包括:

  • 函数的返回地址和参数
  • 临时变量: 包括函数的非静态局部变量以及编译器自动生成的其他临时变量
  • 函数调用的上下文。栈是从高地址向低地址延伸,一个函数的栈帧用ebp 和 esp 这两个寄存器来划定范围,ebp 指向当前的栈帧的底部,esp 始终指向栈帧的顶部

ebp 寄存器又被称为帧指针(Frame Pointer)。
esp 寄存器又被称为栈指针(Stack Pointer)。

在函数调用的过程中,有函数的调用者(caller)和被调用的函数(callee)。
调用者需要知道被调用者函数返回值,被调用者需要知道传入的参数和返回的地址。

函数调用

函数调用分为以下几步:

  • 参数入栈:将参数按照调用约定(C 是从右向左)依次压入系统栈中;
  • 返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行;
  • 代码跳转:处理器将代码区跳转到被调用函数的入口处;
  • 栈帧调整:
    1. push ebp 将调用者的ebp压栈处理,保存指向栈底的ebp的地址(方便函数返回之后的现场恢复),此时esp指向新的栈顶位置;
    2. mov ebp, esp 将当前栈帧切换到新栈帧(将eps值装入ebp,更新栈帧底部), 这时ebp指向栈顶,而此时栈顶就是old ebp;
    3. sub esp, XXX 给新栈帧分配空间

函数返回

函数返回分为以下几步:

  • mov eax, XXX 保存被调用函数的返回值到 eax 寄存器中 
  • mov ebp, esp 恢复 esp 同时回收局部变量空间 
  • pop ebp 将上一个栈帧底部位置恢复到 ebp
  • ret 弹出当前栈顶元素,从栈中取到返回地址,并跳转到该位置

到这里栈帧以及函数的调用与返回已经结束了,这里涉及一些汇编的知道,这里还没有记录不同平台的调用约定和一些特殊的寄存器。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值