「这是我参与11月更文挑战的第30天,活动详情查看:2021最后一次更文挑战」。
汇编语言和C语言交互
- 内嵌汇编
- 外链汇编
1.引入其他源文件函数
使用import
或者extern
伪指令
;使用import伪指令
AREA code, CODE
import fun1 ;导入其他源文件中名为fun1的函数
END
;使用extern伪指令
AREA code, CODE
extern fun1
END
两者区别:
import
:不管当前文件是否使用该引入的函数,该标签都会加入当前文件符号表,即为静态引用extern
:只有当前文件使用了该函数,才会将此标签加入符号表,即为动态引用
2.导出当前源文件中函数供其他文件访问
使用export
或者global
伪指令
;使用import伪指令
AREA code, CODE
export fun ;导出fun函数供其他源文件使用
fun
mov R0,#4
bx lr
END
3.外链汇编之C语言调汇编函数
第一步,在汇编原文件中将函数暴露出来给供外部调用,使用export
或者global
伪指令:
AREA code, CODE
export arm_strcpy ;或者使用global
arm_strcpy
loop
ldrb R4,[R0],#1 ;如果使用ldr 那么将偏移值改成4
cmp R4,#0
beq over
strb R4,[R1],#1
b loop
over
END
第二步,在C文件中引用汇编中的函数,C文件中只能使用extern
伪指令:
extern arm_strcpy(char *src,char*des);
int main2(){
char *a="hello pangshu";
char b[64];
arm_strcpy(a,b);
}
4.外链汇编之汇编调c语言函数
第一步,在C文件中编写好函数
int c_sum(int a,int b){
return a+b;
}
第二步, 在汇编文件中引入函数,使用import
或者extern
伪指令
AREA code, CODE
import c_sum
mov R0,#1 ;第一个参数
mov R1,#2 ;第二个参数
END
第三步, 使用BL指令调用函数
AREA code, CODE
import c_sum
mov R0,#1 ;第一个参数
mov R1,#2 ;第二个参数
BL c_sum
END
在ARM中函数参数使用R0~R3这四个寄存器来进行传递,最多传递4个参数,超过4个参数使用栈进行处理,函数返回值通过R0进行传递
由于keil软件的特殊性,我们可以通过以下方式进行互调测试
C文件中代码:
#include<stdio.h>
extern arm_strcpy(char *src,char*des);
int main2(){
char *a="hello pangshu" ;
char b[64];
arm_strcpy(a,b); //调汇编中函数
return 0;
}
int c_sum(int a,int b){
return a+b;
}
汇编文件中代码:
AREA code, CODE
import c_sum
export arm_strcpy
arm_strcpy
mov R0,#1 ;第一个参数
mov R1,#2 ;第二个参数
BL c_sum ;结果存放至R0中
END
5.内嵌汇编
在C语言中嵌入汇编代码,格式如下:
int main2(){
int a=4;
int b=4;
int c=4;
__asm__{ //使用__asm或者__asm__
mov R5,#0x00000005 //在大括号内部直接写入汇编代码即可
mov R6,#0x00000005
}
return 0;
}
内嵌汇编的注意事项:
- 不能直接给PC寄存器赋值,如果想改变pc值需要借助转移指令
- 由于R0 ~ R3用于存放函数参数和返回值,R12 ~ R15有特殊用途,因此我们能操作的寄存器只有R4~R11, 又因为编译器会优先将寄存器分配给函数中的局部变量,因此我们一般无法在内嵌汇编环境中准确地修改某个寄存器的值,比如我想修改R5寄存器的值,由于函数有个变量占用了R5这个寄存器,那么编译器会自动将你写的这个R5改成R6或者其他,所以,在内嵌汇编时我们需要把寄存器当作变量来看待,把局部变量也当成寄存器看待,就好理解了
void c_strcopy(char *src,char *des){
char ch
__asm__{
loop:
ldrb ch,[src],#1 //局部变量当成寄存器看待
strb ch,[des],#1
cmp,ch,#0
bne loop
}
}