windows - Microsoft Stack 是否始终与 16 字节对齐?
问题描述
在Kip Irvine 的Assembly Language, Seventh Edition for x86 Processors中,第 211 页,它在5.53 The x86 Calling Convention which address the Microsoft x64 Calling Convention 下说,
- 调用子例程时,堆栈指针 (
RSP
) 必须在 16 字节边界(16 的倍数)上对齐。该CALL
指令将一个 8 字节的返回地址压入堆栈,因此调用程序必须从堆栈指针中减去 8,此外它已经为影子空间减去 32。
它继续显示一些在(对于 32 字节的影子空间)sub rsp, 8
之前带有右侧的程序集。sub rsp, 20h
这是一个安全的约定吗?Microsoft 堆栈是否保证在指令之前的16 字节上对齐?CALL
或者,这本书假设堆栈是错误的
- 对齐到 16 字节之前
CALL
- 有一个 8 字节的返回地址用
CALL
- 需要额外
sub rsp, 8;
的才能恢复到 16 字节对齐?
解决方案
我在询问是否满足 x64 ABI 的要求。每次调用后通过将堆栈增长 8 字节以进行 16 字节对齐来盲目调整堆栈是否安全?
是的,这就是 ABI 要求/保证call
.
您可以在函数内执行任何操作,例如 3x 16 位推送,然后sub rsp, (24 - 3*2)
在进入函数后重新获得 16 字节堆栈对齐。
或者movq xmm0, rsp
,然后rsp
用作额外的临时寄存器以获得 16 个整数寄存器,直到您在制作另一个call
或ret
. 1
没有要求 RSP 在每条指令之后对齐 16 字节,仅在函数调用边界处。 这就是为什么它们被称为“调用约定”,而不是“编码标准”。
这与保留调用的 rbx 的概念类似。如果您将它保存/恢复到堆栈中、xmm0 中、静态存储中、是否将其取反然后再次取反,或者您根本不触摸它,都没有关系。重要的是,当您返回调用者时,它具有与调用函数时相同的值。
脚注 1:只要您没有任何可能在用户空间堆栈上运行的异步回调/SEH 处理程序,就可以工作。这并不能真正保证安全,但可能会像黑客一样工作。
写在ESP下面是否有效?相关:正如 Ped7g 指出的那样,如果某些东西可以异步使用堆栈指针下方的空间,那么如果 RSP 根本不指向堆栈内存,它可能会中断。
我已经看到了一个 32 位示例 avisynth 视频过滤器(我认为),它使用它来获得 8 个 tmp regs(当没有 MMX 可用时),在使用这个技巧之前首先在代码中进行调试的大警告注释。
推荐阅读
- angularjs - AngularJS 1.0.7 和 angular-translate 中的性能问题
- titanium - Appcelerator Hyperloop 使用 TiApplication 类
- stata - 在汇总表中显示子组的计数
- corda - 如何监控排水过程中的流量?
- annotations - @Activate 内的 Sling ResourceResolverFactory 抛出 RunTimeException
- javascript - 如何使用承诺返回 TypeError - javascript
- mysql - mysql需要对一列进行完整计数并按某些列分组
- c# - Autofac 没有从 Multi Target .Net 标准库中加载模块
- pixi.js - 使用法线贴图旋转对象而不破坏照明的策略
- python - 使用正则表达式提取文件名