GCC内嵌汇编(mips)
以MIPS架构的汇编为主进行说明
1 | __asm__ __volatile__( |
- 基本形式:
__asm__ __volatile__("ssnop\n\t");
ssnop
: 空指令
汇编扩展以__asm__
开头表示后面部分为汇编,__volatile__
严禁将此处的汇编语句和其他语句进行重组优化,就是希望gcc不要修改我们这个部分。
构成
主要由四部分构成,之间以:
分隔:
instruction指令
:每条指令之后最好使用"\n\t"
结尾,这样在gcc产生汇编格式比较好.output operand输出
:每个输出部分使用,分隔.”=”作为修饰符,”m”表示存放位置/约束符
,()里面表示对应C程序值.input operand输入
:这个部分和输出是一样的.clobber(装备)
:这个部分是告诉gcc在这条指令里面我们会修改什么值.
约束符
束符影响的内容包括:
whether an operand may be in a register
which kinds of register
whether the operand can be a memory reference
which kinds of address
whether the operand may be an immediate constant
which possible values it may have
约束符包括:
- p 内存地址
- m 内存变量
- o 内存变量,但是寻址方式必须是偏移量的,就是基址寻址或者是基址变址寻址.
- V 内存变量,但是寻址方式是非偏移量的.
- r general寄存器操作数
- i 立即操作数,内容在编译器可以确定.
- n 立即操作数.有些系统不支持字(双字节)以外的立即操作数,这些操作数以n非i来表示.
- E/F 浮点常数
- g 内存操作数,整数常数,非genernal寄存器操作数
- X 任何操作数
- 0,1,2…9 和编号指定操作数匹配的操作数束符影响的内容包括
修饰符
修饰符包括:
=
操作数是write only的+
操作数是可读可写的&
常用于输出限定符,表示某个寄存器不会被输入所使用.
1 | __asm__ __volatile__( |
实例
读取CP0 25号硬件计数寄存器的值
1 | int get_counter() |
“=r” 中,’=’ 为修饰符,表示该操作对象只写,一般用于修饰输出参数列表中。’r’ 表示任意一个通用寄存器
设置CP0 24号硬件计数寄存器的值
1 | unsigned int op = 0x80f; |
重设后,读取CP0 24号寄存器的值
1 | unsigned int rst; |
输入输出参数列表,按先后顺序,从0开始编号, %0, %1。
解读开头汇编代码
读写锁中读锁上锁的汇编实现:
1 | __asm__ __volatile__( |
"=m" (rw->lock)
: 只写内存操作"=&r" (tmp)
: 只写的输出变量,使用一个通用寄存器"memory"
: 告诉gcc编译,该指令会修改内存中的值
- 通过原子操作
ll
,将rw->lock
读到tmp
- 加一:
tmp = tmp + 1
- 通过原子操作
sc
,将tmp
写入rw->lock
barrier
内存屏障:保证前后指令的执行顺序
1 |
file: include/linux/compiler-gcc.h
"memory"
作为clobber部分另外一个作用是可以让在这条指令之后的指令,告诉gcc应该刷新内存状态.内存的状态可能发生修改,如果需要操作的话,需要重新把内存内容载入寄存器
参考
- MIPS GCC 嵌入式汇编
- GCC内嵌汇编