在嵌入式开发中,汇编和C和混合编程是有必要的,比如在如下场景:
- 在boot阶段没有C的运行环境,需要编写汇编代码配置基本的硬件环境和C的运行环境;
- 添加新的系统调用;
- 需要用汇编加速部分对延时高要求的地方;
- 一些特权寄存器的操作,无法用C语言实现,只能采用汇编;
- 触发中断时,需要从中断向量处的汇编代码过渡到C实现的中断服务函数;
- 。。。。。。
本文以AArch64为例,示例是计算2个int型数的加减法。 编译器使用aarch64-linux-gnu-gcc。
1. C调用汇编
1.1 汇编和C写在同一个.c文件中
// 源文件test_c_asm.c
#include <stdio.h>
asm(
".text\n"
".global Add\n"
".type Add, %function\n"
"Add:\n"
"add w0, w0, w1\n"
"ret"
);
extern int Add(int, int);
int main(int argc,char** argv)
{
int b=1,c=2;
int a = Add(b,c);
printf("res = %d\n", a);
return 0;
}
编译:
aarch64-linux-gnu-gcc test_c_asm.c -o test
运行:
./test
输出:
res = 3
1.2 汇编和.c写到不同的文件
汇编代码写到.S文件中,C代码写到.c文件中。
汇编代码add.S:
.text
.global Add
.type Add, %function
Add:
add w0, w0, w1
ret
C代码test.c:
// 源文件test.c
#include <stdio.h>
extern int Add(int, int);
int main(int argc,char** argv)
{
int b=1,c=2;
int a = Add(b,c);
printf("res = %d\n", a);
return 0;
}
编译:
aarch64-linux-gnu-gcc test.c add.S -o test
运行:
./test
输出:
res = 3
1.3 C内嵌汇编
1.3.1 不指定变量使用的寄存器
C源文件test_c_embeded_asm.c
#include <stdio.h>
int Add(int a, int b)
{
int res = 0;
asm(
"add %w[result], %w[i], %w[j]"
: [result] "=r"(res)
: [i] "r"(a), [j] "r"(b)
);
}
extern int Add(int, int);
int main(int argc,char** argv)
{
int b=1,c=2;
int a = Add(b,c);
printf("res = %d\n", a);
return 0;
}
编译:
aarch64-linux-gnu-gcc test_c_embeded_asm.c -o test
运行:
./test
输出:
res = 3
1.3.2 指定变量使用的寄存器
#include <stdio.h>
int Sub(int a, int b)
{
int res = 0;
asm(
"sub %w0, %w1, %w2"
: "=r"(res)
: "r"(a), "r"(b)
: "memory"
);
}
int main(int argc,char** argv)
{
register int b asm("w1") =1;
register int c asm("w2") =2;
int a = Sub(b,c);
printf("res = %d\n", a);
return 0;
}
编译:
aarch64-linux-gnu-gcc test_c_embeded_asm2.c -o test
运行:
./test
输出:
res = -1
2. 汇编调用C
下面是一个综合性示例中,调用关系如图:
将汇编和C写到一个文件中test_asm_call_c.c :
#include <stdio.h>
int Sub(int a, int b)
{
return a-b;
}
asm(
".section .text\n"
".global SubASM\n"
".type SubASM, %function\n"
"SubASM:\n"
"stp x29, x30, [sp, -32]!\n" /* 压栈X29,X30, X29是帧指针寄存器(FP)。
X30是链接寄存器(LR)。*/
"bl Sub\n" // 调用C语言实现的Sub函数
"ldp x29, x30, [sp], 32\n" // 出栈X29,X30
"ret\n"
);
extern int SubASM(int, int);
int main(int argc,char** argv)
{
int b=1,c=2;
int a = SubASM(b,c); // 调用汇编函数
printf("res = %d\n", a);
return 0;
}
编译:
aarch64-linux-gnu-gcc test_asm_call_c.c -o test
运行:
./test
输出:
res = -1