In my assembly function, there are 6 arguments. When I try to access the fourth and fifth arguments, they are wrong, here is my code on arm cortex-8a
push {r4-r8,lr}
ldr r6, [sp]
ldr r7, [sp, #4]
I have checked [sp] memory, r4-r8 have wrong value. But, if there are 3 or fewer arguments, [sp] gives correct r4-r8 value. Do I miss something?
Functions can define default argument values, functions can be called with keyword arguments, and functions can be written to accept any number of arguments.
C functions may pass parameters in registers and fixed memory locations. A maximum of 3 parameters may be passed in registers.
For 64-bit x86 Windows programs the arguments are passed in registers rcx , rdx , r8 and r9 . And for 64-bit x86 Linux programs the registers rdi , rsi , rcx , rdx , r8 and r9 are used.
Stack layout On the x86, each call's argument values and return address are stored on the stack. A callee's arguments are stored at the top of its caller's stack frame, with the first argument at the top, the second argument just below, and so on.
why not just try it?
unsigned int fun ( unsigned int, unsigned int, unsigned int, unsigned int, unsigned int );
unsigned int myfun ( void )
{
return(fun(1,2,3,4,5));
}
assemble then disassemble
> arm-none-eabi-gcc -O2 -c fun.c -o fun.o
> arm-none-eabi-objdump -D fun.o
assembly output contains
00000000 <myfun>:
0: e52de004 push {lr} ; (str lr, [sp, #-4]!)
4: e3a03005 mov r3, #5
8: e24dd00c sub sp, sp, #12
c: e58d3000 str r3, [sp]
10: e3a01002 mov r1, #2
14: e3a02003 mov r2, #3
18: e3a03004 mov r3, #4
1c: e3a00001 mov r0, #1
20: ebfffffe bl 0 <fun>
24: e28dd00c add sp, sp, #12
28: e49de004 pop {lr} ; (ldr lr, [sp], #4)
2c: e12fff1e bx lr
the first four operands are in registers r0-r3 as expected. the fifth operand though is placed on the stack. why the compiler allocates 12 bytes instead of 4 for the operand, that is a mystery...Perhaps seeing the function would make more sense:
unsigned int fun ( unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e )
{
return(a+b+c+d-e);
}
assemble and disassemble
arm-none-eabi-gcc -O2 -c fun.c -o fun.o
arm-none-eabi-objdump -D fun.o
00000000 <fun>:
0: e0811000 add r1, r1, r0
4: e0812002 add r2, r1, r2
8: e59d0000 ldr r0, [sp]
c: e0823003 add r3, r2, r3
10: e0600003 rsb r0, r0, r3
14: e12fff1e bx lr
so the callee simply knows the operand is the first thing on the stack and doesnt care about the stack frame created by the caller. so it is a mystery why the caller allocated 12 bytes instead of 4 in this case.
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
seeing the compiler actually implement the calling convention can make the reading of the calling convention itself more understandable. Or if you craft examples like this for the specific function prototype you are interested in on the compiler you are interested in you dont have to read the convention, you just make your caller or callee whichever you are interested in, match what the compiler is doing for itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With