内联汇编 格式:
__asm__ __volatile__(
"Instruction List"
:Output Operand List
:Input Operand List
:Clobber/Modify List
);
内嵌汇编 举例:
#include <stdio.h>
int main(int argc, char **argv)
{
int in = 100;
int out;
__asm__ __volatile__(
"mov r0, %[input]\n"
"mov %[output], r0\n"
:[output]"=r"(out)
:[input]"r"(in)
:"r0"
);
printf("out = %d\n", out);
return 0;
}
__asm__ 是 GCC 关键字 asm 的宏定义。
__asm__或asm用来声明一个内联汇编表达式,所以任何一个内联汇编表达式都是以它开头的,是必不可少的。#define __asm__ asm
__volatile__是GCC 关键字 volatile 的宏定义。
__volatile__或 volatile 是可选的。如果用了它,则是向 GCC 声明不允许对该内联汇编优化,否则当使用了优化选项(-O)进行编译时,GCC 将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉。#define __volatile__ volatile
“Instruction List”是指令列表。每条指令都必须被双引号括起来;两条指令必须用换行”\n”或分号”;”分开。
Output Operand List用来指定当前内联汇编语句的输出操作符列表。每一个输出操作符都由3个部分组成:方括号[]中的符号名,限制字符串”=r”,圆括号()中的C表达式构成。输出操作符之间用逗号”,”分割。
即:[out1]”=r”(value1), [out2]”=r”(value2), … [outn]”=r”(valuen)Input Operand List用来指定当前内联汇编语句的输入操作符列表。表示方法同上。
即:[in1]”=r”(value1), [in2]”=r”(value2), … [inn]”=r”(valuen)。Clobber/Modify List通知GCC当前内联汇编语句可能会对某些寄存器或内存进行修改,希望GCC在编译时能够将这一点考虑进去。这种情况一般发生在一个寄存器出现在”Instruction List”,但却不是由Input/Output操作表达式所指定的,也不是在一些Input/Output操作表达式使用”r”约束时由GCC为其选择的,同时此寄存器被”Instruction List”中的指令修改,而这个寄存器只是供当前内联汇编临时使用的情况。
如果一个内联汇编语句的Clobber/Modify域存在”memory”,那么GCC会保证在此内联汇编之前,如果某个内存的内容被装入了寄存器,那么在这个内联汇编之后,如果需要使用这个内存处的内容,就会直接到这个内存处重新读取,而不是使用被存放在寄存器中的拷贝。因为这个时候寄存器中的拷贝已经很可能和内存处的内容不一致了。
综合上述讲述,普通的内嵌汇编可以如下表示:
__asm__ __volatile__(
"Instruction 1\n"
"Instruction 2\n"
...
"Instruction n\n"
:[out1]"=r"(value1), [out2]"=r"(value2), ... [outn]"=r"(valuen)
:[in1]"=r"(value1), [in2]"=r"(value2), ... [inn]"=r"(valuen)
:"r0", "r1", ... "rn"
);
输入/输出操作符列表中的组成部分之一是限制性字符串。对于ARM处理器,GCC4提供了以下限制:
Constraint | Usage in ARM state | Usage in Thumb state |
---|---|---|
f | Floating point registers f0 .. f7 | Not available |
h | Not available | Registers r8..r15 |
G | Immediate floating point constant | Not available |
H | Same a G, but negated | Not available |
I | Immediate value in data processing instructions e.g. ORR R0, R0, #operand |
Constant in the range 0 .. 255 e.g. SWI operand |
J | Indexing constants -4095 .. 4095 e.g. LDR R1, [PC, #operand] |
Constant in the range -255 .. -1 e.g. SUB R0, R0, #operand |
K | Same as I, but inverted | Same as I, but shifted |
L | Same as I, but negated | Constant in the range -7 .. 7 e.g. SUB R0, R1, #operand |
l | Same as r | Registers r0..r7 e.g. PUSH operand |
M | Constant in the range of 0 .. 32 or a power of 2 e.g. MOV R2, R1, ROR #operand |
Constant that is a multiple of 4 in the range of 0 .. 1020 e.g. ADD R0, SP, #operand |
m | Any valid memory address | |
N | Not available | Constant in the range of 0 .. 31 e.g. LSL R0, R1, #operand |
O | Not available | Constant that is a multiple of 4 in the range of -508 .. 508 e.g. ADD SP, #operand |
r | General register r0 .. r15 e.g. SUB operand1, operand2, operand3 |
Not available |
w | Vector floating point registers s0 .. s31 | Not available |
X | Any operand |
限制字符可能要单个修饰符指示。要是没有修饰符指示的默认为只读操作符。
操作符 | 说明 |
---|---|
= | 只写操作,通常用于所有的输出操作符 |
+ | 读写操作符,必须用于输出操作符 |
& | 只能用于输出的寄存器,不能使用与输入操作数相同的寄存器 |