【发布时间】:2014-08-24 08:29:19
【问题描述】:
我一直在阅读关于 Windows x64 ABI 的非常好的文章的长目录。这些文章的一个非常小的方面是对帧指针的描述。一般的要点是,因为 Windows x64 调用堆栈规则非常严格,所以通常不需要专用的帧指针,尽管它是可选的。
我经常看到的一个例外是alloca() 用于在堆栈上动态分配内存。这样做的函数显然需要一个帧指针。例如,引用微软在"Stack Allocation" 上的文档(我添加的斜体和粗体):
如果空间是在函数中动态分配(alloca)的,那么非易失性寄存器必须用作帧指针来标记固定部分的基址 堆栈 并且该寄存器必须在序言中保存和初始化。请注意,当使用 alloca 时,来自同一个调用者的对同一个被调用者的调用可能具有不同的注册参数的家乡地址。
对此,微软的 x64 ABI alloca() documentation 神秘地补充道:
_alloca 需要 16 字节对齐,另外 需要使用帧指针。
首先,为什么必须使用它?我假设调用堆栈在异常时展开,但我还没有找到令人满意的解释。
下一个问题:必须指向哪里?在上述两个引用中的第一个中,它说“必须”用于标记“堆栈的固定部分”的基础。什么是“堆栈的固定部分”?我得到的印象是,这个术语表示,在给定的框架中,地址范围包括(较高的地址到较低的地址):
- 调用者返回地址(如果你认为它是当前函数框架的一部分);
- 函数序言保存非易失性寄存器的地址;和
- 存储局部变量的地址。
同样,我还没有为这个“固定部分”找到一个令人满意的定义。我在上面链接的"Stack Allocation" 页面包含下图以及“如果使用,堆栈指针将一般指向此处”的字样:
This very nifty blog post 同样含糊不清,包括一个图表说明帧指针“指向此处某处”,其中“此处”是保存的非易失性寄存器和本地寄存器的地址。
最后一点神秘,来自微软的 MSDN 文章"Dynamic Parameter Stack Area Construction",其中仅包含以下内容:
如果使用帧指针,则存在动态创建参数堆栈区域的选项。目前在 x64 编译器中没有这样做。
“一般”是什么意思? “这里的某个地方”在哪里?存在的选项是什么?有规律吗?谁在乎?
或者,tl;dr:标题要求什么。任何包含带注释的程序集的答案都非常感谢。
【问题讨论】:
标签: c windows assembly 64-bit calling-convention