.seh_stackalloc 和堆栈对齐

.seh_stackalloc and stack alignment

我正在为 GNU 汇编程序编写一些 x64 程序集。我一直在尝试 read 关于 .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),难道我不应该对齐堆栈吗?根据MS:

The stack will always be maintained 16-byte aligned, except within the prolog

也许我可以'reason' 解决这个问题?如果打电话给我的人做对了(如果...),那么当他执行 call 时堆栈是对齐的,所以现在我少了 8 个字节(return 地址)加上无论我在序言中做什么。我可以依赖这个吗?看起来很脆弱。

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

如果我要这样做,我想把它做好。堆栈对齐似乎很常见,所以这里必须有人有解决方案。我只是没看到。

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

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

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

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