Article content: learn the mixed programming of C and assembly language of STM32 under Keil, involving the transfer of function parameters, and show specific examples.
1 function call between C language and assembly language
1.1 ATPCS
- The arm thumb procedure call follows the standard ATPCS (arm thumb procedure call standard)
- ATPCS standard is not only the function call rule used by ARM compiler, but also the writing rule for designing assembly functions that can be called by C program
- ATPCS mainly defines the transfer rules of parameters when calling functions and how to return parameters from functions
1.2 role of stack and register in function call
- Functions pass parameters and return function values through registers and stacks
- Formal parameters and return values should be defined in registers and stacks with temporary nature
1.3 ATPCS rules for stack and register usage
- For X86 platforms (whether win10 or Linux / Ubuntu)
① 32-bit programs use stack passing
② 64 bit program depends on the number of parameters. When there are 1 ~ 6 parameters, register is used to transfer; If there are more than 6 parameters, the extra parameters are passed by stack.
- For ARM platform
Parameter value transfer is stored in registers R0, R1, R2 and R3 in order, and more than four parameter values are transferred on the stack
2 ARM programming
2.1 create a new project
To set up a project in keil5, please refer to another blog: Create assembly language STM32 project based on MDK and analyze HEX file
2.2 writing c and assembling code
2.2.1 adding c files
- Right click Source Group 1 and click Add New Item to Group 'Source Group 1'
- In the new window: click C File (.s) to add the assembly file, then set the file name (preferably in English, here it is named main), and click Add to save
- Enter the following c code in the main.c box:
main.c:
# include<stdio.h> extern void Init_1(void); int main(){ Init_1(); return 0; }
2.2.2 add assembly file
- Right click Source Group 1 and click Add New Item to Group 'Source Group 1'
- In the new window: click Asm File (.s) to add the assembly file, then set the file name (preferably in English, named Func here), and click Add to save
- Enter the following assembly code in the Func.s box:
Func.s:
AREA MY_FUNCTION,CODE,READONLY EXPORT Init_1 ;With in c Defined in the file Init_1 Function Association ;The declaration and use of variables in high-level languages are actually the use of board registers, so we only need to use registers directly Init_1 MOV R1,#0 Set R1 register to i MOV R2,#0 ; Set R2 register to j LOOP ;Written on the far left is the segment name of the program segment, which is used when executing the jump program CMP R1,#ten ; Compare the sizes of R1 and 10 BHS LOOP_END ;If R1 Greater than or equal to 10, jump to LOOP_END On the contrary, ignore the statement and directly execute the following statement ADD R2,#1 ;j++ ADD R1,#1 ;i++ B LOOP ;loop LOOP_END NOP END ;You must write after a space END,Otherwise, it will be regarded as the segment name, indicating the end of the program
3 C language calls assembly language
3.1 no parameter call
- Click the magic wand to call up the Options for Target 'Target 1' interface, where click Debug;
- Select Use Simulator and Run to main(); Fill in DARMSTM.DLL in the following Dialog DLL: blank space and - pSTM32F103VE in the Parameter: blank space;
- Finally, click OK to finish the preparation
- Directly click the red dot in front of the code line and select the following five breakpoints:
- Click compile, and then click debug
The following view appears:
- Continuously click Run to debug and run
It will be found that the values of R1 and R2 are successfully increased from 0 to 10:
...
3.2 parameter call
- Modification code:
main.c:
# include<stdio.h> extern int Init_1(int x); int main(){ int xx = Init_1(10); printf("%d", xx); return 0; }
Func.s:
AREA MY_Function,CODE,READONLY EXPORT Init_1 ; With in c Defined in the file Init_1 Function Association ; The declaration and use of variables in high-level languages are actually the use of board registers, so we only need to use registers directly Init_1 ADD R0,#100 ; Add the passed in value + 100 MOV PC,LR ; return R0 LOOP ; Written on the far left is the segment name of the program segment, which is used when executing the jump program CMP R1,#ten ; Compare the sizes of R1 and 10 BHS LOOP_END ; If R1 Greater than or equal to 10, jump to LOOP_END On the contrary, ignore the statement and directly execute the following statement ADD R2,#1 ; j++ ADD R1,#1 ; i++ B LOOP ; loop LOOP_END NOP END ; You must write after a space END,Otherwise, it will be regarded as the segment name, indicating the end of the program
In ARM, the parameter values of sub functions are stored in R0, R1, R2 and R3 in order, and more than four parameter values are transferred and placed in the stack frame. So Init_1(10) the incoming 10 is placed in R0 and returned by MOV PC and LR to 110.
- Set the following breakpoints
- Click compile and debug, and click Run to run debugging
It can be found that at this time, the value of xx is 0x6E, that is, 110, and the call is successful.
4 assembly language calls C language
- On the basis of the above operations, modify the code
main.c:
# include<stdio.h> extern void Init_1(void); int get5(void); int main(){ printf("Begin...\n"); Init_1(); return 0; } int get5(){ return 5; }
Func.s:
AREA MY_Function,CODE,READONLY EXPORT Init_1 ; With in c Defined in the file Init_1 Function Association IMPORT get5 ; statement get5 Is an external reference
; The declaration and use of variables in high-level languages are actually the use of board registers, so we only need to use registers directly
Init_1 MOV R1,#0 Set R1 register to i MOV R2,#0 ; Set R2 register to j LOOP ; Written on the far left is the segment name of the program segment, which is used when executing the jump program CMP R1,#ten ; Compare the sizes of R1 and 10 BHS LOOP_END ; If R1 Greater than or equal to 10, jump to LOOP_END On the contrary, ignore the statement and directly execute the following statement ADD R2,#1 ; j++ ADD R1,#1 ; i++ BL get5 ; call get5,The returned value is passed in R0 B LOOP ; loop LOOP_END NOP END ; You must write after a space END,Otherwise, it will be regarded as the segment name, indicating the end of the program
- Set the following breakpoints
- Click compile and debug, and then click Run to run debugging
It can be seen that after multiple executions, R0 changes to 5, that is, the call is successful.
5 Summary
Mixed programming of C and assembly language of STM32 under Keil. Among them, we should first find out the function calls between C language and assembly language. In the first section of the article, the call rules are also summarized. If there are any differences, please correct them.
6 references
1,Function call between C language and assembly language
2,When C language calls a function, does the parameter use stack or register
3,Mixed programming of C language and assembly language under STM32