In embedded software programming, the function call is often used, before learning how to embed the assembly in C language, there is a parameter call before the C language is used to pass the first parameter with register R0, R1 pass to the second one. Pass the fourth argument to R3. But in fact, sometimes it can pass a lot of parameters, more than 8, or there are floating-point numbers in the parameters, the parameters will be more than 4 registers, for the excess part does not use R4, but the way to use the stack, but the specific way many sites are not below.
For the ARM system, calls between functions written in different languages (mix calls) follow the Atpcs (Arm-thumb procedurecall Standard), and atpcs mainly defines the pass rules for the parameters of the function call and how to return from the function. For more information on ATPCS, see Section 2.1 of the ADS1.2 Online books--developer Guide. This document is about how the parameters are passed in the assembly code for the C function call and how to return correctly from the C function
Unlike the x86 parameter transfer rules, Atpcs suggests that the formal parameters of the function are not more than 4, and if the number of formal parameters is less than or equal to 4, the parameters are passed by the R0,R1,R2,R3 four registers; If the number of formal parameters is greater than 4, parts greater than 4 must be passed through the stack.
Let's talk about 4 of the parameters.
Instance 1:
Test_asm_args.asm
//—————————————————————————— –
IMPORT Test_c_args declare test_c_args function
Area Test_asm, CODE, READONLY
EXPORT test_asm_args
Test_asm_args
STR lr, [sp, #-4]!; Save current LR
Ldr r0,=0x10; parameter 1< br> LDR r1,=0x20 parameter 2
LDR r2,=0x30; parameters 3
Ldr r3,=0x40; parameters 4
BL Test_c_args; call c function
Ldr pc, [sp], #4; PC (return main function)
End
TEST_C_ARGS.C
//—————————————————————————— –
void Test_c_args (int a,int b,int c,int D) br> {
PRINTK ("test_c_args:\n");
Printk ("%0x%0x%0x%0x\n", a,b,c,d);
}
MAIN.C
//—————————————————————————— –
Int main ()
{
Test_asm_args ();
for (;;);
}
The program starts with the main function, main calls the Test_asm_args,test_asm_args call Test_c_args, and finally returns main from Test_asm_args.
The code uses the assembly and C to define two functions, Test_asm_args and Test_c_args,test_asm_args call Test_c_args, and their arguments are passed to R0~R3 write the parameter values, and then use the BL statement to test _c_args the call. The noteworthy place is marked with a red statement, Test_asm_args before the call Test_c_args must put the current LR into the stack, after the call after the Test_c_args and then save the LR in the stack back to the PC, so as to return to the main function.
If the Test_c_args parameter is 8. This situation Test_asm_args how the parameters should be passed.
Example 2:
Test_asm_args.asm
——————————————————————————–
IMPORT Test_c_args; Declare Test_c_args function
Area test_asm, CODE, READONLY
EXPORT Test_asm_args
Test_asm_args
STR LR, [sp, #-4]!; Save current LR
LDR r0,=0x1; parameter 1
LDR r1,=0x2; parameter 2
LDR r2,=0x3; parameter 3
LDR r3,=0x4; parameter 4
LDR r4,=0x8
STR r4,[sp,#-4]!; parameter 8 into stack
LDR r4,=0x7
STR r4,[sp,#-4]!; parameter 7 into stack
LDR r4,=0x6
STR r4,[sp,#-4]!; parameter 6 into stack
LDR r4,=0x5
STR r4,[sp,#-4]!; parameter 5 into stack
BL Test_c_args_lots
ADD sp, SP, #4; Clear the stack of parameter 5, the SP points to parameter 6 after this statement is done
ADD sp, SP, #4; Clear the stack of parameter 6, the SP points to parameter 7 after this statement is done
ADD sp, SP, #4; Clear the stack of parameter 7, the SP points to parameter 8 after this statement is done
ADD sp, SP, #4; Clear the stack of parameter 8, after this statement the SP points to LR
LDR pc, [sp], #4; load LR into PC (return main function)
End
Test_c_args.c
——————————————————————————–
void Test_c_args (int a,int b,int c,int d,int e,int f,int g,int h)
{
PRINTK ("test_c_args_lots:\n");
PRINTK ("%0x%0x%0x%0x%0x%0x%0x%0x\n")
A,B,C,D,E,F,G,H);
}
Main.c
——————————————————————————–
int main ()
{
Test_asm_args ();
for (;;);
}
This part of the code and instance 1 of the code is mostly the same, the difference is the number of Test_c_args parameters and the Test_asm_args of the parameter transfer.
In Test_asm_args, parameter 1~ parameter 4 is passed by R0~R3, and parameter 5~ parameter 8 is passed by pressing it into the stack, but note that the sequence of the four stack parameters is in the order of parameter 8-> parameter 7-> parameters 6-> The order of parameter 5 into the stack.
The stack contents are as follows until the Test_c_args is called:
sp->+ ———-+
| Parameter 5 |
+ ———-+
| Parameter 6 |
+ ———-+
| Parameter 7 |
+ ———-+
| Parameter 8 |
+ ———-+
| LR |
+ ———-+
Test_c_args execution returns, the SP is set, the parameters of the previous stack are cleared, and the LR is loaded into the PC to return the main function, before the LDR pc, [sp], #4 instructions stack contents are as follows:
+ ———-+
| Parameter 5 |
+ ———-+
| Parameter 6 |
+ ———-+
| Parameter 7 |
+ ———-+
| Parameter 8 |
sp->+ ———-+
| LR |
+ ———-+
It's http://lionwq.spaces.eepw.com.cn/articles/article/item/17475/from the top.
But it may actually be that different compilers may be using different processes, and in the compiler we use we can write a simple code, call a function of 10 parameters, and then go to the assembly and see how it is handled, so that special optimizations are made according to the compiler.