APCs Full name: arm Process calling standard if you want to write the assembly code used to connect to compiled C, you must use APCs.
The ultimate goal of today's course is to write Hello world and write container_of macros using an assembly conforming to the APCs standard. The derivation process is complex and leaping. In conclusion, we need to remember two knowledge points. 1. When writing an assembly function, we need to protect the corresponding registers. To protect code, remember to use it every time you write a function. 2. container_of provides the function of getting a pointer to the entire struct Variable Based on the pointer of a domain member variable in a struct variable. In the future, you need to understand the meaning of the Linux kernel code and the derivation process.
The final code is hard to understand. So I also posted the previous derived code.
1 # include <stdio. h> 2 3 _ ASM _ (4 5 "sum: \ n" // protection register, sp pc 6 "sub sp, SP, #8 \ n "7" str LR, [Sp, #4] \ n "8" str FP, [Sp] \ n "9" add FP, SP, #4 \ n "10 11" mov LR, PC \ n "12" B Hello \ n "13 14" sub sp, FP, #4 \ n "15" LDR FP, [Sp] \ n "16" ldr lr, [SP + 4] \ n "17" add SP, SP, #8 \ n "18" mov PC, LR \ n "19); 20 _ ASM _ (21" Hello: \ n "22" mov PC, LR \ n "23 24); 25 int main () 26 {27 _ ASM _ volatile _ (28: 29: 30: "R0", "R1", "Memory" 31 ); 32 printf ("Welcome Back \ n"); 33 34}
There are many new knowledge points in the above functions. Here I will list what I think is important. As mentioned above, there are R0 to R15 registers in the Assembly. The 16 registers have another naming method.
A1 ~ A4 corresponds to R0 ~ R3 serves as the input parameter of the function. R0 is the return value. V1 ~ V6 for the corresponding R4 ~ R9, used as a local variable. FP corresponds to R11 initialization frame pointer register IP corresponding to R12 internal process call register, SP corresponds to R13 Stack pointer. LR corresponds to R14, And the link register PC corresponds to R15 program counters.
The entire code is the rollback process for Stack creation. There are four stack cases: whether the stack is up or down. The pointer at the top of the stack is not saved. APCs has a lot of content and will be used later. Remember these knowledge points first.
If the above Code is directly written in a sink, the Zui name after the file is. s or. S. The simplified version is as follows. Remember to add the compilation function to the 3 ~ 5 rows and the last 11 ~ 12 rows.
1 .global main 2 main: 3 mov ip,sp 4 stmfd sp! ,{fp,ip,lr} 5 sub fp,ip,#4 6 7 ldr r0,=he 8 mov lr,pc 9 b printf10 11 sub sp,fp,#812 ldmfd sp,{fp,sp,pc}13 14 he:15 .asciz "hello world\n"16 .align 2
Container_of is used in Linux kernel. I cannot help but sigh when I see this macro. The code is too artistic.
1 #include<stdio.h> 2 3 struct person{ 4 int age; 5 }; 6 struct man{ 7 int len; 8 int h; 9 char a;10 struct person p;11 int s;12 int q;13 };14 int main()15 {16 struct man tom;17 tom.p.age = 20;18 tom.len = 12;19 struct person *head = &tom.p;20 struct man tmp;21 int x = 0;22 x = (unsigned long)&tmp.p - (unsigned long)&tmp;23 struct man *m = (struct man *)((unsigned long)head - x);24 printf("tom‘s len is %d\n",m->len);25 }
The above code can be used to obtain the pointer to the entire struct Variable Based on the pointer of a domain member variable in a struct variable. But the final code is more subtle:
1 #include<stdio.h> 2 #define container_of(ptr,type,mem) (type*)((unsigned long)ptr - (unsigned long)&((type *)0)->mem) 3 struct person{ 4 int age; 5 }; 6 struct man{ 7 int len; 8 int h; 9 char a;10 struct person p;11 int s;12 int q;13 };14 int main()15 {16 struct man tom;17 tom.p.age = 20;18 tom.len = 12;19 struct person *head = &tom.p;20 struct man *m =container_of(head,struct man,p);21 printf("tom‘s len is %d\n",m->len);22 }
17th days: APCs and container_of macro