I am trying to understand how function calling works at machine level. For that I created a dummy C function like this :
int func(int a[], int n) {
char arr[n];
arr[n - 99] = 100; //to prevent compiler from optimizing my function to noop
return arr[12]; //to prevent compiler from optimizing my function to noop
}
And, I got following assembly when compiling with x86-64 clang 13.0.1
push rbp
mov rbp, rsp
mov eax, esi
mov rcx, rsp
add rax, 15 // Instruction 1
and rax, -16 // Instruction. 2
mov rdx, rcx
sub rdx, rax
mov rsp, rdx
movsxd rsi, esi
mov byte ptr [rsi rdx - 99], 100
neg rax
movsx eax, byte ptr [rcx rax 12]
mov rsp, rbp
pop rbp
ret
Instructions 1 and 2 are calculating size of array arr from variable n. The calculated size is next largest multiple of 16 than n. For example, even if n = 1, clang is allocating 16 bytes of memory. I am confused as to why would clang try to make array sizes as multiple of 16 bytes?
I checked with different data types for arr but all have same behavior. So, I don't think this is for alignment purposes as different data type would have different alignment size.
I checked with different compilers as well. All are allocating arrays of sizes multiple of 16. There is something fundamental that I am missing.
Here is the link as reference.
CodePudding user response:
The System V psABI for x86-64 requires sufficiently large arrays and variable-length arrays to be aligned to at least 16 bytes so that they are correctly aligned for SSE operations.
As @PeterCordes explains under this answer, there are also further reasons to keep the stack aligned to 16, although that wouldn't matter for the specific function you are giving as an example.
Note however that variable-length arrays are only supported in C as compiler-specific extension in the first place. They are not allowed in standard ISO C , but are supported in C since C99.
For reference you can find links to the ABI specification (draft) here. The requirement is given in section 3.1.2 under the heading "Aggregates and Unions".