从汇编层看64位程序运行——栈帧(Stack Frame)边界

《从汇编层看64位程序运行——栈帧(Stack Frame)入门》中,我们简单介绍了栈帧的概念,以及它和函数调用之间的关系。如文中所述,栈帧是一种虚拟的概念,它表达了一个执行中的函数的栈空间区域。在这个区域中,该函数的局部非静态变量便被置于这个空间中,即我们常常说起的栈上变量。

那么这个区间是通过什么划分的?

RBP,RSP

这就需要引入寄存器这个概念。

寄存器(Register)是中央处理器内用来暂存指令、数据和地址的存储器。 寄存器的存贮容量有限,读写速度非常快。 在计算机体系结构里,寄存器存储在已知时间点所作计算的中间结果,通过快速地访问数据来加速计算机程序的执行。

CPU有非常多的寄存器,本节我们主要讲解与栈帧相关的两个寄存器:

  • 栈底指针寄存器(Stack Base pointer register): 在16位系统中,有个寄存器叫bp;在32位系统中,这个寄存器叫ebp;在64位系统中,这个寄存器叫rbp。
  • 栈顶指针寄存器(Stack pointer register): 在16位系统中,有个寄存器叫sp;在32位系统中,这个寄存器叫esp;在64位系统中,这个寄存器叫rsp。

需要注意的是,栈底指针寄存器(rbp)保存的并不是当前栈帧的栈底地址,而是保存了栈上变量分配的起始地址
如下图,0x7fffffffdf20到0x7fffffffdf10是main函数栈帧的部分,它保存了函数调用需要用到的一些信息(我们在《从汇编层看64位程序运行——函数的调用和栈平衡》将会介绍)。从0x7fffffffdf10开始的内存,保存的是main函数局部非静态变量的值。
在这里插入图片描述
栈顶指针寄存器(rsp)不仅可以被直接设置,还会随着栈上Push和Pop的操作而改变。这个特性和rbp有很大不同,rbp只能直接被设置,栈上Push和Pop操作并不会直接导致rbp的值发生变动。
如果函数有局部非静态变量,则在函数开始时,编译器会计算好这个函数需要的局部变量空间,然后通过调整rsp的值(值变小,即栈增长),来声明当前函数的栈上变量空间。
比如下面代码的反汇编,在汇编代码的+8行,通过sub $0x10,%rsp,让当前函数的栈扩展了0x10个字节。

int main() {
    int b = 16;
    b = b + 16;
    foo();
    return 0;
}

在这里插入图片描述

栈帧边界

有了上述的铺垫,我们通过info stack和info frame来查看到程序运行到foo函数时的栈帧
在这里插入图片描述
可以看到一个函数的栈帧起始地址是上一个栈帧的rsp,栈帧结束地址该函数进入下一栈帧前的rsp
在这里插入图片描述
需要注意的是“该函数进入下一栈帧前的rsp并不一定等于局部变量空间的最后一个地址
因为在局部变量空间之后,调用者函数可能还需要将一些参数Push到栈中,从而传递给调用者。这个时候rsp会继续扩张。于是栈帧的结束地址也在扩张。关于这块知识我们可以在《从汇编层看64位程序运行——参数传递的底层实现》中看到。
正因为存在需要使用栈来给不同函数传递参数的情况,让一个函数的栈帧的结束地址是持续变化的。比如一个函数调用的A,需要栈上传递1个参数;这个函数调用的B,需要栈上传递2个参数。那么相较于进入A函数,进入B函数时调用者函数的栈帧就要更大些(大1个参数空间)。
如下图main函数的栈帧在它调用不同函数时,其栈帧的结束地址是持续变化的。
在这里插入图片描述

总结

  • 栈帧运行时虚拟的结构。
  • 函数的栈帧起始地址是调用者调用本函数时RSP的值。
  • 函数的栈帧的结束地址分为两种情况:
    • 有调用其他函数时。结束地址是调用其他函数时RSP的值。
    • 没有调用其他函数时。结束地址是栈上最后一个变量的结束地址。
  • 栈帧的结束地址可能会随着其调用其他函数而不停改变。

参考资料

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-16 05:26:06       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-16 05:26:06       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-16 05:26:06       58 阅读
  4. Python语言-面向对象

    2024-07-16 05:26:06       69 阅读

热门阅读

  1. 【AI绘画教程】什么是Huggingface

    2024-07-16 05:26:06       25 阅读
  2. python开发面试-20240715

    2024-07-16 05:26:06       24 阅读
  3. 喜欢dp动态规划的第二天(暑假提升)

    2024-07-16 05:26:06       24 阅读
  4. 习题1 回文数 python、C++ 不同解法

    2024-07-16 05:26:06       29 阅读
  5. js的多线程示例

    2024-07-16 05:26:06       26 阅读