The C standard (and C ++) does not define the order of arguments passed or how they should be organized in memory. A compiler developer (usually in collaboration with OS developers) should come up with something that works in a particular processor architecture.
In MOST architectures, the stack (and registers) is used to pass arguments to the function, and, again, for MOST architectures, the stack grows from βhigh to lowβ addresses, and in most C implementations, the order of the arguments is passed βlast to the left,β so if we have a function
void test( int a, int b, int c )
then the arguments are passed in the following order:
c, b, a
to function.
However, which complicates this, when the value of the arguments is passed to the registers, and the code using the arguments takes the address of these arguments - the registers have no addresses, so you can not take the address of the register variable. Therefore, the compiler will generate some code to store the address on the stack [from where we can get the address of the value] locally for the function. It totally depends on the decision of the compiler, which orders that it does, and I am sure that this is what you see.
If you take your code and pass it through clang, we see:
define void @test(i32 %a, i32 %b, i32 %c)
Although this may not be entirely trivial to read, you can see that the first few lines of the test function:
%a.addr = alloca i32, align 4 %b.addr = alloca i32, align 4 %c.addr = alloca i32, align 4 store i32 %a, i32* %a.addr, align 4 store i32 %b, i32* %b.addr, align 4 store i32 %c, i32* %c.addr, align 4
This essentially creates space on the stack ( %alloca ) and stores the variables a , b and c in these places.
The assembler code generated by gcc is even less readable, but you can see a similar thing happening here:
subq $16, %rsp ; <-- "alloca" for 4 integers. movl %edi, -4(%rbp) ; Store a, b and c. movl %esi, -8(%rbp) movl %edx, -12(%rbp) leaq -12(%rbp), %rcx ; Take address of ... leaq -8(%rbp), %rdx leaq -4(%rbp), %rax movq %rax, %rsi movl $.LC0, %edi movl $0, %eax call printf ; Call printf.
You may wonder why it allocates space for 4 integers - this is because the stack should always be aligned with 16 bytes in x86-64.