GCC-3——gcc内联汇编
1. gcc内联汇编格式
__asm_- __volatile__(指令部: 输出部: 输入部: 损坏部)
gcc内联汇编在处理器变量和寄存器上提供了一个模板和一些约束条件:
(1) 在指令部(Assembler Template)中数字前加上%,如%0、%1等,表示需要使用寄存器的样板操作数。若指令部中用到几个不同的操作数,就说明有几个变量需要和寄存器结合。
(2) 输出部(Output Operands) 用于描述在指令部中可以修改的C语言变量以及约束条件。每个输出约束通常以"="或"+"号开头,"="号表示被修饰的操作数只有可写属性,"+"号表示被修饰的操作数具有可读可写属性。然后是一个字母(表示对操作数类型的说明),接着是关于变量结合的约束。输出部可以是空的。
(3) 输入部(Input Operands) 用来描述在指令部只读取的C语言变量及约束条件。输入部描述的参数只有只读属性,不要试图修改输入部参数的内容,因为gcc编译器假定输入部的参数内容在内嵌汇编之前和之后都是一致的。在输入部中不能使用"="号或者"+"号约束条件,否则就会编译报错。输入部可以是空的。
(4) 损坏部(Clobbers) 一般以"memory"结束。"memory"告诉gcc编译器,内联汇编代码改变了内存中的值,强迫编译器在执行该汇编代码前存储所有缓存的值,在执行完汇编代码之后重新加载该值,目的是防止编译乱序。"cc"表示内嵌代码修改了状态寄存器的相关标志位。
2. 例子
(1) 例1:
static inline unsigned long arch_local_irq_save(void) { unsigned long flags; asm volatile( "mrs %0, daif", //读取PSTAT寄存器中的DAIF域到flags变量 "msr daifset, #2", //关闭IRQ : "=r" (flags) : : "memory"); return flags; }
先看输出部,%0 操作数对应 "=r"(flags),即flags变量,其中"="表示被修饰的操作数的属性是只写。"r"表示使用一个通用寄存器。
接着看输入部,上例中输入部为空,没有指定参数。最后看损坏部,以"memory"结束。
该函数主要用于把PSTATE寄存器中的DAIF域保存到临时变量flags中,然后关闭IRQ。
在输出部和输入部使用"%"来表示参数序号,比"%0"表示第一个参数,"%1"表示第2个参数。
(2) 例2:
为了增强代码的可读性,可以使用汇编符号名字来替代%表示的操作数,如下面add函数:
int add(int i, int j) { int ret; asm volatile( "add %w[result], %w[input_i], %w[input_j]" : [result] "=r" (ret) : [input_i] "r" (i), [input_j] "r" (j) ); return ret; }
书上Demo编译验证不通过,报错:
$ gcc main.c -o pp main.c: Assembler messages: main.c:8: Error: number of operands mismatch for `add'
上述是个简单的gcc内联汇编的例子,主要功能是将i和j的值相加返回结果。先看输出部,表示只定义了一个操作数。"[result]"表示定义了一个汇编符号操作数,符号名为result,它对应"=r"(ret),使用函数中定义的ret变量。在汇编代码中对应%w[result],其中w表示ARM64中的32位通用寄存器。再看输入部,定义了两个操作数,同样使用汇编符号操作数的方式来定义。第一个汇编符号操作数是input_i对应形参i,第二个汇编符号操作数是input_j对应形参j。
3. gcc内联汇编操作符和修饰符
操作符/修饰符 说明 = 被修饰的操作数只写 + 被修饰的操作数具有可读可写属性 & 被修饰的操作数只能作为输出
4. ARM64特有操作符和修饰符
操作符/修饰符 说明 k SP寄存器 w 浮点寄存器、SIMD、SVE寄存器 Upl 使用P0到P7中任意一个SVE寄存器 Upa 使用P0到P15中任意一个SVE寄存器 Input 整数,常常用于ADD指令 J 整数,常常用于SUB指令 K 整数,常常用于32位逻辑指令 L 整数,常常用于64位逻辑指令 M 整数,常常用于32位的MOV指令 N 整数,常常用于64位的MOV指令 S 绝对符号地址或标签引用 Y 浮点数,其值为0 Z 整数,其值为0 Ush 表示一个符号的PC相对偏移量的高位部分(大于等于12bit的部分),这个PC相对偏移介于0-4GB Q 表示没有使用偏移量的单一寄存器的内存地址 Ump 一个适用于SI/DI/SF和DF模式下的加载-存储指令的内存地址。
参考:《奔跑吧Linux内核》第2版,此书不怎么样。
posted on 2022-06-05 18:23 Hello-World3 阅读(1173) 评论(0) 编辑 收藏 举报