9
(gdb) disas foo
Dump of assembler code for function foo:
0x00000000004004a8 <foo+0>: push   %rbp
0x00000000004004a9 <foo+1>: mov    %rsp,%rbp
0x00000000004004ac <foo+4>: mov    0x13c(%rip),%eax        # 0x4005ee <__dso_handle+30>
0x00000000004004b2 <foo+10>:    mov    %eax,-0x10(%rbp)
0x00000000004004b5 <foo+13>:    lea    -0x10(%rbp),%rax
0x00000000004004b9 <foo+17>:    add    $0x18,%rax
0x00000000004004bd <foo+21>:    mov    %rax,%rdx
0x00000000004004c0 <foo+24>:    mov    $0x400498,%eax
0x00000000004004c5 <foo+29>:    mov    %eax,(%rdx)
0x00000000004004c7 <foo+31>:    leaveq 
0x00000000004004c8 <foo+32>:    retq   
(gdb) l foo
8   void foo() {
9       char overme[4] = "WOW";
10      *(int*)(overme+24) = (int)bad;
11  }

Why not just 8 bytes?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
compile-fan
  • 16,885
  • 22
  • 59
  • 73
  • 1
    Seems to be a duplicate of [Why does the x86-64 / AMD64 System V ABI mandate a 16 byte stack alignment?](https://stackoverflow.com/q/49391001), although the code example is mostly unrelated to alignment, just some version of GCC's choice of where to put things in the red zone with optimization disabled. In a test case that involves 2 different kinds of UB (strict aliasing violation and out-of-bounds array access). So tells us very little. – Peter Cordes Nov 04 '20 at 10:34

2 Answers2

16

gcc is not "assigning" this space to the variable. Rather, the x86_64 abi requires the stack pointer to always be 16-byte-aligned at function calls, in case the callee uses vectorized SSE math. It's a really stupid and wasteful requirement (the callee should ensure the alignment if it needs it), but that's the standard, and gcc follows the standard. You can fix it with -mpreferred-stack-boundary=3 (8 byte alignment, the minimum for 64-bit).

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • @R,The register size is 8 bytes,why does it 16 bytes alignment? – compile-fan Apr 05 '11 at 02:23
  • Can you elaborate about the `vectorized SSE math`? – compile-fan Apr 05 '11 at 02:30
  • Apparently many SSE instructions either crash, do the wrong thing, or do it very slowly (not sure which) if given misaligned addresses. They work on 128 bits at a time, either single 128-bit floating point values or a vector of many smaller integer or floating point values, so the proper alignment is 16. – R.. GitHub STOP HELPING ICE Apr 05 '11 at 02:45
1

It is 8 bytes, not 16. The LEA instruction doesn't show anything alignment related, -0x10 is just an offset applied to the value of the RBP register. Probably to generate the address of a small local array. If the code generator uses any SIMD instructions then 16 could be relevant. None of which is visible in a two-liner question.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • @Hans Passant,I've updated with code,and `mov %eax,-0x10(%rbp)` is assigning 16 bytes for `char overme[4]` – compile-fan Apr 04 '11 at 12:05
  • No, the EAX register stores 4 bytes. It is copying the "WOW" string which just happens to be 4 bytes long as well. I guessed the "small local array" correctly. You'll get very different code when you make the string longer. The code is otherwise UB. – Hans Passant Apr 04 '11 at 12:24
  • @Hans Passant,can you elaborate why that "small local array" needs 16 bytes,not 8 bytes,if alignment is 8 bytes? – compile-fan Apr 04 '11 at 12:56
  • 1
    No idea, gcc often gobbles stack bytes. It also isn't making space for array by adjusting rsp. Try turning off the code optimizer to get something less RSA encrypted. What is the point of this? Are you trying to stomp the stack on purpose? – Hans Passant Apr 04 '11 at 13:08
  • @Hans Passant,it's already compiled with optimizer off ,`gcc -O0 xxx`. Yes,I'm trying to stomp the stack,but don't understand why `overme` is assigned 16 bytes... – compile-fan Apr 04 '11 at 13:13
  • I've suspected -fstack-protector, but code doesn't look like this – blaze Apr 04 '11 at 13:25