1

I am learning C along with intel x86 assembly. I used this simple C code.

#include <stdio.h> 
void function(){
 char c[1];
}
int main(){
 function();
 return 0;
}

I compiled it with the following command to get assembly.

gcc -S -o code.s code.c

and the expected output assembly of the function is as below:

pushl %ebp
movl %esp, %ebp
subl $24, %esp

What I have understood is that 1 char is 1 byte and 1-word size in intel x86 is 4 bytes and because we do allocation in word sizes so a total of 4 bytes of memory should be allocated on the stack for the char array of length 1. But why the above assembly is showing 24 bytes of allocation.

After playing around I have found that if char array length remains in rang 1-12 then assembly code shows 24 bytes of allocation but if it is more than 12 lets's say it is 13 then it shows 40 bytes.

Quite confusing for me..

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • In this case it's just because you did not enable optimization (which would then remove the entire function, so...). In the general case it's because alignment of stack pointer and the data itself. – Jester May 14 '21 at 13:32
  • Can you please refer me to any article or link because I am still not getting it – Zubair Khalid May 14 '21 at 13:39
  • https://gcc.gnu.org/onlinedocs/gcc-5.5.0/gcc/Structure-Packing-Pragmas.html – fpiette May 14 '21 at 14:43
  • @Jester: GCC's 16 extra bytes of stack allocation doesn't always go away with optimization, e.g. [Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment?](https://stackoverflow.com/q/63009070). https://godbolt.org/z/nhrdGv7zb shows that GCC `-O3` does `sub $28, %esp` (if you make the array `volatile` so it doesn't disappear). It seems `-fstack-protector-strong` was part of the querent's default GCC options, so that's needed on Godbolt to reproduce the `24` with `-O0`. – Peter Cordes May 15 '21 at 01:16

1 Answers1

2

The original System V Unix ABI for IA-32 (Intel386) required the stack pointer to be aligned on a 4 byte boundary.1 The (unpublished) Linux ABI for IA-32 was based on the original System V Unix ABI, but in February 2015 an updated Linux IA-32 ABI Version 1.0 was published that required the stack pointer to be aligned to a 16 (32 if __m256 is passed on stack) byte boundary when calling a function.2 (This ABI was updated to Version 1.1 in December 2015,3 which as far as I know is the latest at the time of writing.)

The compiler's preamble code for the function call usually assumes that the stack is already aligned on entry. It assumes that %esp+4 (the +4 accounts for the return address on the stack) is aligned to a 16 (or 32) byte boundary, and it ensures that the stack pointer is decreased by a multiple of 16 (and aligned to a multiple of 32 if necessary) when calling another function. It does that even if the called function does not call another function.

For the preamble below:

pushl %ebp
movl %esp, %ebp
subl $24, %esp

Before the first instruction (pushl %ebp), %esp+4 is aligned to a 16 byte boundary. After the first instruction, %esp+4+4 is aligned to a 16 byte boundary. After the third instruction (subl $24, %esp), %esp+4+4+24 is aligned to a 16 byte boundary, and since 4+4+24 is a multiple of 16, %esp is aligned to a 16 byte boundary.

The compiler could have replaced subl $24, %esp with subl $8, %esp and still kept the stack aligned to a 16 byte boundary. I do not know the reason for allocating the extra 16 bytes.

The GCC compiler for Linux had already been assuming the stack was already aligned to a 16 byte boundary for a number of years before the version 1.0 of the amended ABI was published. This caused GCC 4.4 to break several binaries. The "fix" was to change the ABI, breaking existing old code rather than fixing the compiler to be compatible with existing code.4


Footnotes:

  1. System V Application Binary Interface, Intel386™ Architecture Processor Supplement Fourth Edition —Figure 3-15: Standard Stack Frame.
  2. System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.0 — 2.2.2 The Stack Frame.
  3. System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.1
  4. Bug 40838 - gcc shouldn't assume that the stack is alignedComment 86 by H.J.Lu (2011-01-18 21:07:26 UTC):

    I am in the process of updating i386 psABI to specify 16byte stack alignment.

Ian Abbott
  • 15,083
  • 19
  • 33
  • 1
    [Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment?](https://stackoverflow.com/q/63009070) - the extra 16 bytes is a common GCC bug; someone should report it... Note that this is a leaf function, and the array is smaller than 16 bytes, so nothing mandates any alignment. (`clang -O3` with `volatile` to stop the array optimizing away actually does an insane `sub $1, %esp`; that's probably not a good thing. https://godbolt.org/z/Gcnqx8931) – Peter Cordes May 15 '21 at 01:24