Microsoft Stack 是否始终与 16 字节对齐?

Eva*_*oll 10 windows assembly stack x86-64 calling-convention

Kip Irvine 的《Assembly Language, Seventh Edition for x86 Processors》第 211 页中,它在5.53 The x86 Calling Convention下说,它解决了 Microsoft x64 Calling Convention,

  1. 调用子程序时,堆栈指针 ( RSP) 必须在 16 字节边界(16 的倍数)上对齐。该CALL指令将 8 字节返回地址压入堆栈,因此调用程序除了已经为影子空间减去 32 之外,还必须从堆栈指针中减去 8 。

它继续显示一些sub rsp, 8在 之前带有 的程序集sub rsp, 20h(对于 32 字节的影子空间)。

但这是一个安全的约定吗?Microsoft 堆栈是否保证在指令之前按 16 字节对齐CALL?或者,这本书假设堆栈是错误的

  1. 对齐到之前的 16 字节CALL
  2. 将 8 字节返回地址压入堆栈CALL
  3. 需要额外的操作sub rsp, 8;才能恢复到 16 字节对齐吗?

Pet*_*des 8

我询问如何满足 x64 ABI 的要求。每次调用后通过将堆栈增加 8 个字节以实现 16 字节对齐来盲目调整堆栈是否安全?

是的,这就是 ABI 要求/保证call.


您可以在函数内执行任何操作,例如 3x 16 位压入,然后sub rsp, (24 - 3*2)在进入函数后重新获得 16 字节堆栈对齐。

或者movq xmm0, rsp然后用作rsp额外的暂存寄存器以获得总共 16 个整数寄存器,直到您在创建另一个call或之前恢复它ret1

不要求 RSP 在每条指令后都 16 字节对齐,仅在函数调用边界处。 这就是为什么它们被称为“调用约定”,而不是“编码标准”。

这与调用保留的 rbx 类似。如果您将其保存/恢复到堆栈中、xmm0 中、静态存储中,如果您对它取反然后再次对它取反,或者如果您根本不碰它,都没有关系。重要的是,当您返回到调用者时,它的值与调用函数时的值相同。


脚注 1:只要您没有任何可能在用户空间堆栈上运行的异步回调/SEH 处理程序,就可以工作。这并不能真正保证安全,但可能会起到黑客作用。

下面写ESP有效吗?相关的是:正如 Ped7g 指出的那样,如果某些东西可以异步使用堆栈指针下方的空间,那么如果 RSP 根本不指向堆栈内存,它可能会中断。

我见过一个 32 位的 avisynth 视频过滤器示例(我认为),它使用它来获取 8 个 tmp 寄存器(当没有 MMX 可用时),在代码中包含大量警告注释,以便在使用此技巧之前首先进行调试。