In embedded software programming, function calls are often used. When I learned how to embed assembly in C language, I learned that the parameter call before C language is to use registers R0 to pass the first parameter, r1 passed to second .. until R3 passes the fourth parameter. but in fact, sometimes there may be a lot of parameters passed, more than 8, or there are floating point and so on in the parameter, the parameter will also exceed 4 registers, for the excess part does not use R4, instead, we use the stack method, but the specific method is that many websites will not have the following content.
For the arm system, the mix CILS between functions written in different languages follows the atpcs (ARM-thumb procedure call standard ), atpcs mainly defines the transmission rules of parameters during function calls and how to return parameters from functions. For details about atpcs, see section 2.1 of ads1.2 online books -- developer guide. This document describes how to pass parameters in the assembly code for Calling C functions and how to return correct results from C functions.
Unlike x86 parameter passing rules, atpcs recommends that the function have no more than four parameters. If the number of parameters is less than or equal to 4, the parameter is composed of r0, R1, R2, r3 registers are passed. If the number of parameters is greater than 4, the parts greater than 4 must be passed through the stack.
We will first discuss the situation where the number of parameters is 4.
Instance 1:
Test_asm_args.asm
//---------------------------
Import test_c_args; declare the test_c_args Function
Area test_asm, code, readonly
Export test_asm_args
Test_asm_args
Str lr, [Sp, #-4]! ; Save the current lR
LDR r0, = 0x10; parameter 1
LDR R1, = 0x20; parameter 2
LDR R2, = 0 × 30; parameter 3
LDR R3, = 0x40; parameter 4
BL test_c_args; call the c Function
Ldr pc, [Sp], #4; load LR into PC (return the main function)
End
Test_c_args.c
//---------------------------
Void test_c_args (int A, int B, int C, int D)
{
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 runs from the main function. Main calls test_asm_args, test_asm_args calls test_c_args, and returns main from test_asm_args.
The Code uses assembly and C to define two functions, test_asm_args and test_c_args. test_asm_args calls test_c_args, and the parameter passing method is to R0 ~ R3 writes the parameter values respectively, and then uses the BL statement to call test_c_args. Note that the statement marked in red is used. Before test_asm_args calls test_c_args, the current LR must be put into the stack. After test_c_args is called, The LR saved in the stack is written back to the PC, in this way, it can be returned to the main function.
What if test_c_args has eight parameters? In this case, how should we PASS Parameters in test_asm_args?
Instance 2:
Test_asm_args.asm
//---------------------------
Import test_c_args; declare the test_c_args Function
Area test_asm, code, readonly
Export test_asm_args
Test_asm_args
Str lr, [Sp, #-4]! ; Save the current lR
LDR r0, = 0x1; parameter 1
LDR R1, = 0 × 2; parameter 2
LDR R2, = 0x3; parameter 3
LDR R3, = 0x4; parameter 4
LDR R4, = 0x8
STR R4, [Sp, #-4]! ; Parameter 8 into the stack
LDR R4, = 0 × 7
STR R4, [Sp, #-4]! ; Parameter 7
LDR R4, = 0 × 6
STR R4, [Sp, #-4]! ; Parameter 6
LDR R4, = 0 × 5
STR R4, [Sp, #-4]! ; Parameter 5 into the stack
BL test_c_args_lots
Add SP, SP, #4; clear parameter 5 in the stack. After this statement is executed, SP points to parameter 6.
Add SP, SP, #4; clear parameter 6 in the stack. After this statement is executed, SP points to parameter 7.
Add SP, SP, #4; clear parameter 7 in stack. After this statement is executed, SP points to parameter 8.
Add SP, SP, #4; clear parameter 8 in the stack. After this statement is executed, SP points to lR
Ldr pc, [Sp], #4; load LR into PC (return the 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 (;;);
}
Most of the Code in this part is the same as the code in instance 1. The difference is the number of parameters in test_c_args and the parameter passing method in test_asm_args.
In test_asm_args, parameter 1 ~ Parameter 4 still goes through R0 ~ R3 is passed, and the parameters are 5 ~ Parameter 8 is passed by pushing it into the stack. However, pay attention to the order of the four parameters in the stack, it is written to the stack in the order of parameter 8-> parameter 7-> parameter 6-> parameter 5.
Until test_c_args is called, The stack content is as follows:
SP-> + ---- +
| Parameter 5 |
+ ---- +
| Parameter 6 |
+ ---- +
| Parameter 7 |
+ ---- +
| Parameter 8 |
+ ---- +
| LR |
+ ---- +
After test_c_args returns the result, it sets sp, clears the parameters of the previous stack, loads LR into the PC, and returns the main function. After executing ldr pc, [Sp], #4 the stack content before the command is as follows:
+ ---- +
| Parameter 5 |
+ ---- +
| Parameter 6 |
+ ---- +
| Parameter 7 |
+ ---- +
| Parameter 8 |
SP-> + ---- +
| LR |
+ ---- +
Above is transferred from http://lionwq.spaces.eepw.com.cn/articles/article/item/17475/
But in fact, different compilers may use different processing methods. In the compiler we use, we can write a simple code that calls 10 parameter functions, then it is upgraded to assembly, and then we can see how it is processed, so that we can perform special Optimization Based on the compiler.