Microsoft Stack 是否始终与 16 字节对齐? [英] Is the Microsoft Stack always aligned to 16-bytes?

查看:26
本文介绍了Microsoft Stack 是否始终与 16 字节对齐?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

汇编语言,x86 第七版Processors by Kip Irvine,第 211 页,在 5.53 x86 调用约定下说明了 Microsoft x64 调用约定,

<块引用>

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

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

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

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

解决方案

我在询问是否满足 x64 ABI 的要求.通过在每次调用后为 16 字节对齐增加 8 字节来盲目调整堆栈是否安全.

是的,这就是 ABI 要求/保证 16 字节对齐之前调用的全部意义.

<小时>

您可以在函数内做任何您想做的事情,例如 3x 16 位推送,然后 sub rsp, (24 - 3*2) 重新获得 16-进入函数后字节栈对齐.

或者 movq xmm0, rsp 然后使用 rsp 作为额外的暂存寄存器来获得 16 个整数寄存器,直到你在进行另一个 调用之前恢复它ret.1

没有要求 RSP 在每个指令后对齐 16 字节,仅在函数调用边界处.这就是它们被称为调用约定"的原因,不是编码标准".

这与保留调用的 rbx 的概念相似.无论您是在堆栈中、xmm0 中、静态存储中保存/恢复它,还是否定它然后再次否定它,或者根本不接触它,都没有关系.重要的是,当您返回给调用者时,它具有与调用函数时相同的值.

<小时>

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

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

我见过一个 32 位示例 avisynth 视频过滤器(我认为),它使用它来获得 8 tmp regs(当没有 MMX 可用时),在使用此技巧之前先调试代码中的大警告注释.

In Assembly Language, Seventh Edition for x86 Processors by Kip Irvine, on page 211, it says under 5.53 The x86 Calling Convention which addresses the Microsoft x64 Calling Convention,

  1. When calling a subroutine, the stack pointer (RSP) must be aligned on a 16-byte boundary (a multiple of 16). The CALL instruction pushes an 8-byte return address on the stack, so the calling program must subtract 8 from the stack pointer, in addition to the 32 it already subtracts for the shadow space.

It goes on to show some assembly with a sub rsp, 8 right before the sub rsp, 20h (for the 32-bytes of shadow space).

Is this a safe convention though? Is the Microsoft stack guaranteed to be aligned on 16-bytes before the CALL instruction? Or, is the book wrong in assuming that the stack was

  1. aligned to 16-bytes prior to the CALL
  2. had an 8-byte return addresses push onto the stack with the CALL
  3. requires an additional sub rsp, 8; to get back to 16-byte alignment?

解决方案

I'm asking about meeting the requirements of the x64 ABI. Is it safe to blindly adjust the stack by growing it 8 bytes for a 16-byte alignment after every call.

Yes, that's the whole point of the ABI requiring / guaranteeing 16-byte alignment before a call.


You can do whatever you want inside a function, for example 3x 16-bit pushes and then sub rsp, (24 - 3*2) to regain 16-byte stack alignment after entry to a function.

Or movq xmm0, rsp and then use rsp as an extra scratch register to get 16 total integer regs, until you restore it before making another call or ret.1

There's no requirement that RSP be 16-byte aligned after every instruction, only at function call boundaries. This is the why they're called "calling conventions", not "coding standards".

This is a similar concept to rbx being call-preserved. It doesn't matter if you save/restore it on the stack, in xmm0, in static storage, if you negate it and then negate it back again, or if you don't touch it at all. All that matters is that it has the same value when you return to the caller as it did when your function was called.


Footnote 1: Works as long as you don't have any async callbacks / SEH handlers that could possibly run on the user-space stack. This is not really guaranteed to be safe, but may work as a hack.

Is it valid to write below ESP? is related: as Ped7g points out, if something can asynchronously use space below the stack pointer, it will probably break if RSP isn't pointing to stack memory at all.

I've seen a 32-bit example avisynth video filter (I think) that used this to get 8 tmp regs (when no MMX was available), with big warning comments in the code to debug first before using this trick.

这篇关于Microsoft Stack 是否始终与 16 字节对齐?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆