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内嵌汇编