Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment?
Asked Answered
M

2

11

I'm reading a textbook which shows assembly code based on C code:

C code:

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

assembly code:

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  

I don't understand why stack pointer %rsp is decremented by 24 bytes. I only assign 8 bytes' buffer as char buf[8];, and there no callee saved registers to push on stack, shouldn't the instruction be

subq $8, %rsp
Matri answered 21/7, 2020 at 7:0 Comment(2)
I think stack frame sizes are rounded up to 32 byte alignmentBlythe
@Barmar: No, gcc only maintains 16-byte alignment, the minimum required by x86-64 ABIs. If you did alignas(32) buf[8], you'd see extra code to over-align the stack.Lou
L
13

Allocating an extra 16 bytes of stack space is a GCC missed optimization that pops up occasionally. I don't know why it happens, but it's reproducible with GCC10.1 -O3. Clang doesn't do it, it just reserves 8 bytes (with a dummy push). Example on Godbolt, where -fno-stack-protector -fno-pie is the default, unlike GCC in many GNU/Linux distros.

Even int buf; / foo(&buf) results in over-allocation.

My wild guess is that there's something GCC doesn't optimize away until after it's already decided it needs more than 8 bytes of space (and thus needs 24). Hopefully this good MCVE will let GCC devs find an fix that bug, if it's easily fixable.

Feel free to report this as a GCC missed-optimization bug (https://gcc.gnu.org/bugzilla/); I looked recently but didn't find an existing one.


You're correct that allocating 8 bytes would be enough for char buf[8] and re-align RSP by 16 before the call, as required by the x86-64 System V ABI (Why does System V / AMD64 ABI mandate a 16 byte stack alignment?).

GCC is not trying to maintain 32-byte stack alignment or anything. The default for -mpreferred-stack-boundary is the minimum allowed by the ABI, 4 (2^4 = 16).

Lou answered 21/7, 2020 at 8:13 Comment(0)
M
1

AFAIK the stack must be 16 byte aligned for function calls but I have no clue as to why 24 bytes were allocated and not only 16.

There are some questions about this on SO already. Why does GCC 6 assume data is 16-byte aligned?

and on GCCs bugzilla https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838

Milquetoast answered 21/7, 2020 at 7:17 Comment(2)
That seems to depend on the optimization: with -O0 there's a push rbp and a sub rsp, 16, however with -O3 it is sub rsp, 24 instead and there is no push. Also, the size does indeed increase in increments of 16 bytes (24, 40, 56, ...)Unhorse
Yes, x86-64 System V requires 16-byte alignment before a call. Why does System V / AMD64 ABI mandate a 16 byte stack alignment?. The GCC bug you linked is about 32-bit mode. The x86-64 System V ABI has always required 16-byte stack alignment, there was no breaking change (like there was for i386 System V, probably introduced by accident; see my comment on the bug: gcc.gnu.org/bugzilla/show_bug.cgi?id=40838#c91).Lou

© 2022 - 2024 — McMap. All rights reserved.