栈帧(Stack Frame)

0x01.栈在计算机中的应用

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

0x02.栈帧和栈帧的结构

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

一个函数的栈帧用ebp 和 esp 这两个寄存器来划定范围。

栈帧包括:

  1. 函数的返回地址和参数。
  2. 临时变量。 包括函数的非静态局部变量以及编译器自动生成的其他临时变量。
  3. 栈帧状态值:ebp (帧指针),指向当前的栈帧的底部;esp(栈指针) 始终指向栈帧的顶部;

栈帧从低到上依次是(从高地址到低地址的方向):

  1. 参数
  2. 返回地址
  3. ebp
  4. 局部变量
  5. esp

0x03.函数的调用过程

调用约定:

  •  函数调用约定描述了函数传递参数方式和栈帧同工作的技术细节。不同的操作系统、不同的语言、不同的编译器在实现函数调用时的原理虽然基本相同,但具体的调用约定还是有差别的。这包括参数传递方式,参数入栈顺序是从右向左还是从左向右,函数返回时恢复堆栈平衡的操作在子函数中进行还是在母函数中进行。
  • 同一段代码用不同的编译选项、不同的编译器编译链接后,得到的可执行文件会有很多不同。

调用过程:

  1. 参数入栈。将参数按照一定的顺序入栈。
  2. 返回地址入栈。将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。
  3. 代码区跳转。处理器从当前代码区跳转到被调用函数的入口处。
  4. 栈帧处理步骤:EBP入栈,保存当前栈帧状态值,已备后面恢复本栈帧时使用。push ebp
  5. 栈帧处理步骤:ESP值赋给EBP,更新栈帧底部。mov ebp,esp
  6. 栈帧处理步骤:给新栈帧分配空间。sub esp,xxx

0x04.函数的返回过程

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

0x05.图示

(图片转载自https://www.cnblogs.com/clover-toeic/p/3755401.html

0x06.x86和x64在栈帧上的区别

x86:

 

x64:

  • System V AMD64 ABI (Linux、FreeBSD、macOS 等采用)中前六个整型或指针参数依次保存在RDI, RSI, RDX, RCX, R8 和 R9 寄存器中,如果还有更多的参数的话才会保存在栈上。
  • 内存地址不能大于 0x00007FFFFFFFFFFF,6 个字节长度,否则会抛出异常。

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATFWUS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值