混合编程-C语言和GNU ARM汇编互相调用
C语言嵌入汇编
__asm 是C/C++中的一个关键字,用于嵌入汇编代码到C/C++程序中。它通常用于需要直接操作底层硬件或者需要特定的汇编指令来实现的场景。
在使用 __asm 关键字时,可以直接在C/C++代码中编写汇编指令。这样的话,编译器会将这部分汇编代码嵌入到生成的可执行文件中。
格式
__asm [volatitle]{[instruction]}
示例
int main() {
int a = 5;
int b = 10;
int result;
// 要避免直接使用这些物理寄存器,这里只是示例
__asm {
MOV R0, a ; 将变量a的值加载到R0寄存器中
ADD R0, R0, b ; 将变量b的值加到R0寄存器中
MOV result, R0 ; 将R0寄存器的值保存到result变量中
}
return 0;
}
void my_strcpy(char *srt,char *dest){
char ch;
__asm {
loop:
LDRB ch,[src],#1
STRB ch,[dest],#1
CMP ch,#0
BNE loop
}
}
限制条件
- 不能直接向PC寄存器赋值,程序跳转要使用B或BL指令;
- 在使用物理寄存器时,不要使用过于复杂的C表达式,避免物理寄存器冲突;
- R12和R13可能被编译器用来存放中间编译结果,计算表达式值可能 R0~R3、R12及R14用于子程序调用,因此要避免直接使用这些物理寄存器。
C语言调用汇编
步骤
- 汇编
.global
- C语言定义
extern function
- C语言使用
.global add
add:
ADD r0, r0, r1 @ 将第一个参数(r0)和第二个参数(r1)相加,并将结果存储在r0中
B lr @ 返回
#include <stdio.h>
extern int add(int a, int b); // 声明外部的add函数
int main() {
int result = add(10, 20);
printf("Result: %d\n", result);
return 0;
}
as -o add.o add.s
gcc -o main main.c add.o
注意
C语言和汇编语言之间的参数传递是通过 R0~R3来进行传递的,即R0传递第一个参数,R1传递第二个参数,R2传递第三个参数,多于4个时借助栈来实现,函数的返回值通过R0来传递,这个规定叫 ATPCS(ARM Thumb Procedure Call Standard),具体见ATPCS规范
汇编调用C语言
步骤
- C语言实现函数
- 汇编声明C语言函数
- BL 函数名
// add.c
int add(int a, int b) {
return a + b;
}
.section .text
.global main
; 声明外部的C语言函数
.extern add
main:
MOV R0, #5 @ 将参数 a 加载到寄存器 R0 中
MOV R1, #10 @ 将参数 b 加载到寄存器 R1 中
BL add @ 调用C语言函数 add
MOV R2, R0 @ 将返回值存储到寄存器 R2 中
; 在这里可以使用返回值 R2,比如打印输出
; ...
; 函数返回
MOV R7, #1 @ 将退出系统调用号加载到 R7 中
SWI 0 @ 执行退出系统调用