1、C语言内嵌汇编的作用
(1)优化:对于特别重要代码进行优化,出于性能的考虑;
(2)C语言需要借助汇编指令来实现特殊功能。比如:C语言中访问系统寄存器就需要借助CSR指令;
2、基础内嵌汇编
2.1、基础内嵌汇编格式
asm asm-qualifiers(AssemblerInstructions)
关键字 | 含义 |
---|---|
asm | 这是内嵌汇编的关键字,表明这是一个GNU扩展 |
asm-qualifiers | 修饰词,比如:volatile、inline |
AssemblerInstructions | 要内嵌的汇编语句,如果是多条汇编语句指令,需要使用”\n\t”来换行 |
(1)基础内嵌汇编指令支持带参数;
(2)gcc编译器不会去解析内嵌汇编指令,当做一个字符串处理;
2.2、基础内嵌汇编举例
#同时内嵌多条汇编指令asm( "pushl %eax\n\t" "movl $0,%eax\n\t""popl %eax");# 也可以将多条的内嵌汇编语句拆开写,效果一样asm("movl %eax,%ebx");asm("xorl %ebx,%edx");asm("movl $0,_booga);
3、扩展内嵌汇编
3.1、扩展内嵌汇编的格式
3.1.1、格式说明
asm关键字 修饰词(指令部:输出部:输入部:损坏部:GotoLables(goto修饰时才有该部))
关键字 | 含义 |
---|---|
asm关键字 | 扩展汇编指令的关键字:__asm__ |
指令部 | 要内嵌的汇编指令,可以是一条或者多条 |
输出部 | 用于描述在指令部中可以被修改的C语言变量以及约束条件 |
输入部 | 用于描述在指令部中只能被读取访问的C语言变量以及约束条件 |
损坏部 | 告诉编译器内嵌汇编可能带来的影响 |
3.1.2、修饰词
修饰词 | 含义 |
---|---|
volatile | 用于关闭gcc优化,可参考博客:《C语言中volatile关键字详解以及常见的面试问题》 |
inline | 用于内联,gcc会把汇编代码编译成尽可能短的代码 |
goto | 用于在汇编代码里跳转到C语言的标签处 |
3.1.3、内嵌汇编操作符号/修饰符
操作符/修饰符 | 含义 |
---|---|
= | 被修饰的操作数是只写属性 |
+ | 被修饰的操作数具有可读可写属性 |
& | 被修饰的操作数只能作为输出,这个操作数在输入参数的指令执行完成之后才能写入 |
输出部通常用“=”或者“+”修饰符;输入部分则不能用“=”或者“+”约束条件,否则编译器会报错,因为输入部是用来描述只能读取的C语言变量,不能具有写属性;
3.1.4、操作数约束符
操作符/修饰符 | 含义 |
---|---|
p | 内存地址 |
m | 内存变量 |
r | 通用寄存器 |
o | 内存地址,基地址寻址 |
i | 立即数 |
V | 内存变量,不允许偏移的内存操作数 |
n | 立即数 |
f | 表示浮点数寄存器 |
I | 表示12位有符号的立即数 |
J | 表示值为0的整数 |
A | 表示存储到通用寄存器中的一个地址 |
K | 表示5位无符号的立即数,用于CSR访问指令 |
3.1.5、损坏部介绍
关键字 | 含义 |
---|---|
memory | 告诉编译器,内嵌汇编代码改变了内存中的值,执行完汇编代码后重新加载该值 |
cc | 告诉编译器,内嵌汇编代码修改了状态寄存器的相关标志位 |
3.1.6、指令部的参数表示
3.1.6.1 、用”前缀% + 数字”表示变量
asm volatile("add %0, %1, %2" : "=r"(res): "r"(i), "r"(j));
(1)%0对于”=r”(res),%1对应”r”(i),%2对应”r”(j),内嵌汇编的功能:把i+j的结果写到res中;
(2)”r”修饰词,表示该变量需要使用一个通用寄存器;
总结:用%+数字来引用后面输入部和输出部的参数;
3.1.6.2 、用汇编符号来表示变量
asm volatile("add %[result], %[input_i], %[input_j]" : [result] "=r"(res): [input_i] "r"(i), [input_j] "r"(j));
在输出部和输入部定义变量时就绑定符号,然后在指令部就可以通过符号来引用变量,提高代码的可读性;
3.1.7、goto修饰词介绍
asm goto("addi %0, %0, -1\n""beqz %0, %1[label]\n":: "r"(a): "memory": label);return 0;label:printf("11111\n");
(1)输出部必须是空的。goto是用于跳转功能,在满足某个条件下进行跳转,没有输出数据的必要;
(2)相较于其他情况,goto修饰的情况下多了标签部,表明最后要跳转的标签处;
(3)上面内嵌汇编的功能:当变量a是1时,则跳转到标签label处;
3.2、扩展汇编实例分析
//读取csr寄存器的宏#define read_csr(csr)\({\register unsigned long __v;\__asm__ __volatile__ ("csrr %0, " #csr\: "=r" (__v) :\: "memory");\__v;\})unsigned long val;val = read_csr(mstatus);//将上面的代码按宏定义展开val = ({ register unsigned long __v; \__asm__ __volatile__ ("csrr %0, " "mstatus" : "=r" (__v) : : "memory");\ __v; });
3.3、内嵌汇编和宏结合
//用ATOMIC_OP宏定义内嵌汇编的函数,摘抄自linux源码#define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix)\static __always_inline\void arch_atomic##prefix##_##op(c_type i, atomic##prefix##_t *v)\{\__asm__ __volatile__ (\"amo" #asm_op "." #asm_type " zero, %1, %0"\: "+A" (v->counter)\: "r" (I)\: "memory");\}#define ATOMIC_OPS(op, asm_op, I)\ATOMIC_OP (op, asm_op, I, w, int, )\ATOMIC_OP (op, asm_op, I, d, s64, 64)ATOMIC_OPS(add, add,i)//将上面的宏展开static __always_inline void arch_atomic_add(int i, atomic_t *v){__asm__ __volatile__ ( "amoadd.w " zero, %1, %0" : "+A" (v->counter) : "r" (i) : "memory"); }