0

我正在为 GNU 汇编器编写一些 x64 程序集。我一直在尝试阅读有关 .seh_* 指令的信息,但我没有找到关于它们的太多信息。gas文档根本没有提到它们。

但据我了解,如果我的代码在 SEH 展开操作期间可能在堆栈中,我应该使用这些。而且由于我的代码会进行堆栈操作并调用其他函数,因此 SEH 是可能的,所以我应该使用这些。

大多数情况下,我认为我做对了:

.seh_proc FCT
FCT:

push %rbp
.seh_pushreg    %rbp

mov  %rsp, %rbp
.seh_setframe   %rbp, 0

push %r14
.seh_pushreg %r14

lea -(iOffset + iBytes)(%rsp), %rsp
.seh_stackalloc iOffset + iBytes

andq $-16, %rsp <---- But what about this?

.seh_endprologue

etc...

但是有一点不清楚。我有这个指令:

andq $-16, %rsp

我到底如何告诉 SEH 我正在执行堆栈对齐?这可能会将堆栈从 15 个字节(非常不可能)到 8 个字节(很可能)再到 0 个字节(当然可能)调整。由于实际金额可能要到运行时才能确定,所以我被卡住了。

我想我可以跳过 .seh 指令,但是如果确实在那里保留了 8 个字节的堆栈,我可能已经破坏了展开,不是吗?这不是破坏了这里的全部目的吗?

或者,我可以省略对齐。但是如果我调用其他函数(比如 memcpy),我不应该对齐堆栈吗?根据女士

堆栈将始终保持 16 字节对齐,序言内除外

也许我可以通过这个“推理”我的方式?如果打电话给我的人做对了(如果...),那么当他做call. 我可以依赖这个吗?看起来很脆弱。

我试过查看其他代码,但我不确定我是否相信我所看到的。我怀疑gas报告误用 .seh_* 的错误。您可能只会在实际异常期间看到问题(甚至可能并非总是如此)。

如果我要这样做,我想把它做对。看起来堆栈对齐是一件很常见的事情,所以这里必须有人有解决方案。我只是没看到。

4

1 回答 1

0

看看gcc输出的一些代码,我想我知道答案了。我的“理性”方法走在了正确的轨道上。

当一个函数被调用时,堆栈暂时变得未对齐(由于call),但几乎立即通过 重新对齐pushq %rbp。之后,总是使用 16 的倍数对堆栈(局部变量或调用函数的参数的堆栈空间等)进行调整。因此,在序言结束时,堆栈总是再次正确对齐,并保持这种状态直到下一个call

这意味着虽然andq $-16, %rsp可以用来对齐堆栈,但如果我正确编写我的序言,我不需要这样做。

CAVEAT:叶函数(即不调用其他函数的函数)不需要对齐堆栈(https://msdn.microsoft.com/en-us/library/67fa79wz.aspx)。

于 2016-07-04T22:31:18.903 回答