I have 2 functions in C:
void func1(unsigned char x)
{
unsigned char a[10][5];
a[0][0] = 1;
a[9][4] = 2;
}
void func2(unsigned char x)
{
unsigned char a[10][5];
a[0][0] = 1;
a[9][4] = 2;
unsigned char b[10];
b[0] = 4;
b[9] = 5;
}
Compiling with:
gcc 7.3 x86-64
-O0 -g
OS:
16.04.1-Ubuntu x86-64
Produced intel assembly of functions:
func1(unsigned char):
pushq %rbp
movq %rsp, %rbp
movl %edi, %eax
movb %al, -68(%rbp)
movb $1, -64(%rbp)
movb $2, -15(%rbp)
nop
popq %rbp
ret
func2(unsigned char):
pushq %rbp
movq %rsp, %rbp
movl %edi, %eax
movb %al, -84(%rbp)
movb $1, -64(%rbp)
movb $2, -15(%rbp)
movb $4, -74(%rbp)
movb $5, -65(%rbp)
nop
popq %rbp
ret
I can see that for 50 bytes array 64 bytes were allocated. It seems that it's allocating stack on 16 bytes boundary, since for 10 bytes - 16 bytes were allocated.
My questions:
1) Is there some standard of stack alignment on 16 byte boundary for arrays? Cause variables like int, long int, etc. clearly aren't allocated on 16 byte boundary.
2) Why arrays allocated in such a weird way? We can see for array a, 14 bytes that were added as alignment padding right after our payload of 50 bytes, but for array b, 6 alignment bytes are allocated before our payload of 10 bytes. Am i missing something?
3) Why function argument passed in EDI (unsigned char x), placed on stack 4 bytes away from our arrays memory beginning(including padding). So byte variables(AL register) are also padded or something? Why 4 bytes?
-O0means "Just generate the code as quickly as possible. Don't waste any time considering options to improve the code." And the code sure looks like it could use some improvements...rspitself is maintained, so if a function needs that much alignment for anything (e.g. loading/storing an SSE vector) it can get it for free. Why does System V / AMD64 ABI mandate a 16 byte stack alignment?. That of course doesn't imply that every object on the stack is 16-byte aligned. GCC does this even in leaf functions (that don't make any function calls), just as an implementation detail.