目前编译器都比较智能,能将 C 代码转换为高效率的汇编指令,但是对于某些特殊指令(如 ldrex 、 strex 实现互斥访问)或特殊算法编译器则无法正常转换,此时则需要使用汇编来实现相应的功能,如果不想创建单独的汇编文件则需要采用在C语言中嵌入汇编指令的方式来实现。
如下是一段内联汇编代码的基本格式
__asm__ asm-qualifiers (
AssemblerTemplate
:OutputOperands
:InputOperands
:Clobbers
);
asm :固定格式,表示这是一段内联汇编代码
asm-qualifiers :限定符,通常是 volatile ,表示不对此段内联汇编代码进行优化
AssemblerTemplate :汇编指令列表,每条指令都用用双引号包含起来,并以\n结尾,如 “mov %0, %1\n”
OutputOperands :输出操作数,当有多个操作数时,用逗号进行隔开,单个操作数的格式如下:
[asmSymbolicName] “constraint” (cvariablename)
[asmSymbolicName] :符号名,与 C 代码中的变量名类似,在汇编中可以使用 %[asmSymbolicName] 来引用这个操作数,此部分是可以省略的,若省略后再汇编中则通过 %n 来引用此操作数(n=0~+∞,为操作数出现的顺序)
constraint :参数约束,采用的取值如下:
m :表示要传入有效的地址
r :使用通用寄存器来保存这个操作数
i :表示可以传入一个立即数
以上这些取值还可以加上下列修饰符:
无 :被修饰的操作符是只读的
= :被修饰的操作符只写
+ :被修饰的操作符可读写
& :被修饰的操作符只能作为输出,它会为此操作数分配一个单独的寄存器
cvariablename:操作数对应的C语言的变量名
InputOperands :输入操作数,当有多个操作数时,用逗号隔开,格式如下
[asmSymbolicName] “constraint” (cvariablename)
Clobbers :指明修改了那些寄存器或内存,常用的取值如下:
cc :表示修改了标志寄存器
memory :表示修改了内存
r0 ~ r15 :表示修改了相应的寄存器
如下是一个使用内联汇编实现的加法函数
#include
#include
void add1(int a1, int b1, int *sum1)
{
__asm__ volatile (
"add r4, %1, %2\n" //将a1+b1赋值到r4中,r4 = a1+b1
"ldr r3, %0\n" //将sum的值加载到如中,r3 = sum1
"str r4, [r3]\n" //把r3作为地址,并r4的值写入r3所指的内存,*r3 = r4
:"=&m"(sum1) //输出参数
:"r"(a1), "r"(b1) //输入参数
:"cc", "r3", "r4" //改变了内存、r3、r4
);
}
void add2(int a1, int b1, int *sum1)
{
__asm__ volatile (
"add r4, %1, %2\n" //将a1+b1赋值到r4中,r4 = a1+b1
"str r4, [%0]\n" //把sum1作为地址并把r4的值写入,*sum1 = r4
:"=&r"(sum1) //输出参数
:"r"(a1), "r"(b1) //输入参数
:"cc", "r4" //改变了内存、r4
);
}
//这个函数中使用了汇编符号名,汇编语句中通过%[符号名]的方式引用操作数
void add3(int a1, int b1, int *sum1, int a2, int b2, int *sum2)
{
__asm__ volatile (
"add %[s1], %[a1], %[b1] \n" //*sum1 = a1+b1
"add %[s2], %[a2], %[b2] \n" //*sum2 = a2+b2
:[s1]"=&r"(*sum1), [s2]"=&r"(*sum2) //输出参数
:[a1]"r"(a1), [b1]"r"(b1), [a2]"r"(a2), [b2]"r"(b2) //输入参数
:"cc" //改变了内存
);
}
int main(int argc, char *argv[])
{
int sum1;
int sum2;
add1(1, 3, &sum1);
printf("add1:%d + %d = %d\n", 1, 3, sum1);
add2(1, 3, &sum1);
printf("add2:%d + %d = %d\n", 1, 3, sum1);
add3(1, 3, &sum1, 4, 5, &sum2);
printf("add3:%d + %d = %d; %d + %d = %d\n", 1, 3, sum1, 4, 5, sum2);
return 0;
}