【问题标题】:Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment?为什么 GCC 在堆栈上分配的空间超出了对齐所需的空间?
【发布时间】:2026-01-05 04:00:02
【问题描述】:

我正在阅读一本教科书,其中显示了基于 C 代码的汇编代码:

C 代码:

void echo()
{
   char buf[8];
   otherFunction(buf);
}

汇编代码:

echo:
   subq $24, %rsp      //Allocate 24 bytes on stack, but why allocate 24 instead of 8 bytes?
   movq %rsp, %rdi     //Compute buf as %rsp
   call otherFunction  

我不明白为什么堆栈指针 %rsp 会减少 24 个字节。我只分配了 8 个字节的缓冲区为char buf[8];,并且没有被调用者保存的寄存器可以压入堆栈,该指令不应该是

subq $8, %rsp

【问题讨论】:

  • 我认为堆栈帧大小被四舍五入到 32 字节对齐
  • @Barmar:不,gcc 只维护 16 字节对齐,这是 x86-64 ABI 所需的最小值。如果您执行了alignas(32) buf[8],您会看到额外的代码来过度对齐堆栈。

标签: c assembly gcc x86-64 stack-memory


【解决方案1】:

分配额外的 16 字节堆栈空间是 GCC 错过的优化,偶尔会弹出。我不知道它为什么会发生,但它可以通过 GCC10.1 -O3 重现。 Clang 不这样做,它只保留 8 个字节(带有一个虚拟的 push)。 Godbolt 上的示例,其中 -fno-stack-protector -fno-pie 是默认值,这与许多 GNU/Linux 发行版中的 GCC 不同。

即使int buf; / foo(&buf) 也会导致过度分配。

我的疯狂猜测是,GCC 直到 确定它需要超过 8 个字节的空间(因此需要 24 个)之前,才会优化某些东西。希望这个好的 MCVE 能让 GCC 开发人员找到修复该错误的方法,如果它很容易修复的话。

请随时将此报告为 GCC missed-optimization 错误 (https://gcc.gnu.org/bugzilla/);我最近看了,但没有找到现有的。


您是正确的,分配 8 个字节对于 char buf[8] 就足够了 并且按照 x86-64 System V ABI 的要求,在 call 之前将 RSP 重新对齐 16(@ 987654323@)。

GCC 试图保持 32 字节堆栈对齐或任何东西。 -mpreferred-stack-boundary 的默认值是 ABI 允许的最小值,4 (2^4 = 16)。

【讨论】:

  • 很好解释。 +1
【解决方案2】:

AFAIK 对于函数调用,堆栈必须是 16 字节对齐的,但我不知道为什么分配了 24 个字节,而不仅仅是 16 个。

在 SO 上已经有一些关于此的问题。 Why does GCC 6 assume data is 16-byte aligned?

在 GCC 上的 bugzilla https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838

【讨论】:

  • 这似乎取决于优化:使用-O0 有一个push rbp 和一个sub rsp, 16,但是使用-O3 它是sub rsp, 24,并且没有推送。此外,大小确实以 16 个字节(24、40、56、...)的增量增加
  • 是的,x86-64 System V 在调用前需要 16 字节对齐。 Why does System V / AMD64 ABI mandate a 16 byte stack alignment?。您链接的 GCC 错误大约是 32 位模式。 x86-64 System V ABI 总是需要 16 字节堆栈对齐,没有重大更改(就像 i386 System V 一样,可能是偶然引入的;请参阅我对错误的评论:@ 987654324@).