在大多数平台上,alloca
只是归结为堆栈指针的内联调整(例如,在 x64 上从 rsp
中减去,加上一些逻辑以保持堆栈对齐)。
我正在查看 gcc
为 alloca 生成的代码,它很奇怪。以下面的简单例子1为例:
#include <alloca.h>
#include <stddef.h>
volatile void *psink;
void func(size_t x) {
psink = alloca(x);
}
这将在
-O2
编译为以下程序集:func(unsigned long):
push rbp
add rdi, 30
and rdi, -16
mov rbp, rsp
sub rsp, rdi
lea rax, [rsp+15]
and rax, -16
mov QWORD PTR psink[rip], rax
leave
ret
这里有几个令人困惑的事情。我知道
gcc
需要将分配的大小四舍五入到 16 的倍数(以保持堆栈对齐),通常的方法是 (size + 15) & ~0xF
但它在 add rdi, 30
处添加 30 ?那是怎么回事?其次,我只希望
alloca
的结果是新的 rsp
值,它已经很好地对齐了。相反,gcc 这样做: lea rax, [rsp+15]
and rax, -16
这似乎是“重新对齐”
rsp
的值以用作 alloca
的结果 - 但我们首先已经完成了将 rsp
与 16 字节边界对齐的工作。那是怎么回事?
您可以使用代码 on godbolt 。值得注意的是
clang
和 icc
至少在 x86 上做了“预期的事情”。使用 VLA(如之前的评论中所建议的),gcc
和 clang
效果很好,而 icc
会产生可憎的效果。1 这里,对
psink
的赋值只是为了消耗 alloca
的结果,否则编译器会完全忽略它。 最佳答案
这是一个非常古老的普通优先级 bug 。代码工作正常。只是当大小大于 1 个字节时,不必要地分配了 16 个字节。所以这不是一个正确性错误,它是一个小效率错误。
关于c - gcc 对 alloca 的处理是怎么回事?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42496286/