4.2.4 汇编代码中调用C函数
汇编代码中调用C函数,关键是解决参数传递和函数返回问题。
1. 参数传递问题
如果所传递的参数少于四个,则直接使用R0~R3来进行传递,如果参数多于四个,则必须使用栈来传递多余的参数。
2. 函数返回问题
因为在编译C函数的时候,编译器会自动在函数入口的地方加上现场保护的代码(如部分寄存器入栈,返回地址入栈等),在函数出口的地方加入现场恢复的代码(即出栈代码)。
下面是来看汇编代码调用C函数中两个参数个数不同的例子。
例1. 参数个数为四个
asm_test1.asm代码如下:
- IMPORT c_test1 ;声明c_test1函数
- AREA TEST_ASM, CODE, READONLY ;定义代码段TEST_ASM,属性只读
- EXPORT asm_test1
- 1
- str lr, [sp, #-4]! ;保存当前lr
- ldr r0,=0x01 ;第一个参数r0
- ldr r1,=0x02 ;第二个参数r1
- ldr r2,=0x03 ;第三个参数r2
- ldr r3,=0x04 ;第四个参数r3
- bl c_test1 ;调用C函数
- LDR pc, [sp], #4 ;将lr装进pc,返回main函数
- END
c_test1.c代码如下:
- void c_test1(int a,int b,int c,int d)
- {
- printk("c_test1:\n"); //输出结果到内核缓冲区
- printk("%0x %0x %0x %0x\n",a,b,c,d);
- }
-
- main.c中的代码如下:
- int main()
- {
- asm_test1(); //调用汇编程序
- for(;;);
- }
程序说明:
程序从main函数开始执行,main调用了asm_test1,asm_test1调用了c_test1,最后从asm_test1返回main。这里面有两个函数:一个是用ARM汇编语言写的arm_test1.asm程序;另一个是用C语言写的c_test1.c程序。其中汇编程序asm_test1.asm调用了C函数c_test1.c。这里的参数个数没有超过四个,所以只用了R0~R3四个寄存器进行传递。这里请注意asm_test1.asm中"asm_test1"标记下第一行代码,在调用c_test1之前必须把当前的lr保存到堆栈。在调用完c_test1之后再把刚才保存在堆栈中的lr写入到pc中去,这样才能返回到main函数中。
例2. 参数个数大于四个
arm_test2.asm代码如下:
- IMPORT c_test2 ;声明c_test2函数
- AREA TEST_ASM, CODE, READONLY
- EXPORT arm_test2
- t2
- str lr, [sp, #-4]! ;保存当前lr
- ldr r0,=0x01 ;第一个参数r0
- ldr r1,=0x02 ;第二个参数r1
- ldr r2,=0x03 ;第三个参数r2
- ldr r3,=0x04 ;第四个参数r3
- ldr r4,=0x08
- str r4,[sp,#-4]! ;第八个参数,压入堆栈
- ldr r4,=0x07
- str r4,[sp,#-4]! ;第七个参数,压入堆栈
- ldr r4,=0x06
- str r4,[sp,#-4]! ;第六个参数,压入堆栈
- ldr r4,=0x05
- str r4,[sp,#-4]! ;第五个参数,压入堆栈
- bl c_test2 ;调用C函数
- add sp, sp, #4 ;清除栈中第五个参数,
执行完后sp指向第六个参数 - add sp, sp, #4 ;清除栈中第六个参数
,执行完后sp指向第七个参数 - add sp, sp, #4 ;清除栈中第七个参数,
执行完后sp指向第八个参数 - add sp, sp, #4 ;清除栈中第八个参数,
执行完后sp指向lr - ldr pc, [sp],#4 ;将lr装进pc,返回main函数
- END
c_test2.c代码如下:
- void c_test2(int a,int b,int c,int d,int e,int f,int g,int h)
- {
- printk("c_test2_lots:\n"); //输出结果到内核缓冲区
- printk("%0x %0x %0x %0x %0x %0x %0x %0x\n",
- a,b,c,d,e,f,g,h);
- }
main.c代码如下:
- int main()
- {
- arm_test2(); //调用汇编程序
- for(;;);
- }
程序说明:
这部分的代码和例1的代码大部分是相同的,主要区别在于参数的个数不同。这里的参数个数大于四个,需要使用堆栈来进行参数传递。第一个到第四个参数还是通过R0~R3四个寄存器进行传递的。第五个到第八个参数则是通过把其压入堆栈的方式进行传递,不过要注意第五个到第八个这四个入栈参数的入栈顺序,是以第八个参数、第七个参数、第六个参数、第五个参数的顺序入栈,出栈的顺序正好相反,依次为第五个参数、第六个参数、第七个参数、第八个参数。这里同样要注意调用汇编语言的开头保存好lr,以便在最后恢复pc,返回到main函数。