基本格式
asm asm-qualifiers ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
对于ARMCC,使用
__asm
而不是asm
asm-qualfiers
asm-qualifiers | 说明 |
---|---|
volatile | 提示编译器不要对汇编代码进行优化(例如移动代码位置,甚至直接忽略掉代码) |
inline | 提示编译器估算汇编代码长度的方式(很少用) |
goto | 提示编译器此内联汇编可能会执行跳转到某些标号的操作(很少用)。 |
AssemeblerTemplate
这部分是传递给汇编器的汇编代码编写部分,可以使用任何合法的汇编指令。汇编指令的操作数可以设置为一般的寄存器、立即数、内存地址等,也可以设置为占位符,由后续OutputOperands以及InputOperands来决定。
%
(百分号)被用作特殊转义字符,因此%%
表示%
,{}
和|
被用作特殊字符,因此%{
表示{
,%}
表示}
,%|
表示|
。
在如下例子中,使用了寄存器eax
,以及占位符%0, %1
来作为操作数。
asm volatile (
"movl %%eax, %0\n\t"
"addl %0, %1"
: "=r" (variable1)
: "r" (variable2)
: "eax"
);
"=r" (variable1)
指定输出操作数,其表示第一个占位符变量%0
为C语言变量variable1
, 并且在汇编中使用寄存器(r
)的方式存储,且变量是只写的(r
之前的=
,只写表示不关心变量之间的值)。变量对应的占位符的名称可以自定义,例如[v_name] "=r (variable)"
就指定变量variable
对应的占位符名称为%[v_name]
,没有指定占位符名称的变量其占位符名称按照变量定义顺序依次为%0,%1,%2...
。
"r" (variable2)
指定输入操作数,其表示第二个占位符变量%1
为C语言变量variable2
, 并且在汇编中使用寄存器(r
)的方式存储,变量是只读的(读写变量需要在输出操作数中指定)。变量对应的占位符的名称可以自定义,例如[v_name] "=r (variable)"
就指定变量variable
对应的占位符名称为%[v_name]
,没有指定占位符名称的变量(从第一个变量开始,不分输出和输入操作数),其占位符名称按照变量定义顺序依次为%0,%1,%2...
。
"eax"
则表示汇编代码内部会修改eax
寄存器
OutputOperands
输出操作数位于AssemeblerTemplate
后,使用:
(分号)隔开,可以为空,也可以指定多个输出操作数,每一个操作数由如下三个部分来定义(第一部分asmSymbolicName
,也就是上文所提到的占位符变量名称可以省略),多个输出操作数之间通过,
逗号隔开。
[asmSymbolicName] constraint (cvariablename)
如下例子定义了三个输出操作数,对应c语言变量variable1, variable3
以及variable4
asm volatile (
"movl %%eax, %0\n\t"
"addl %0, %1"
: [v1] "=r" (variable1), "+r" (variable3), [v4] "=r" (variable4)
: "r" (variable2)
: "eax"
);
constraint
主要由两部分,第一部分表示读写操作限制,第二部分为变量存储的方式限制,读写限制只能指定一种,存储限制可以指定多种让编译器选择最合适的方式,例如"=rmi"
。
读写限制 | 说明 |
---|---|
+ | 该变量即被读取也被写入 |
= | 该变量仅被写入(即不关心变量之前的值) |
存储限制 | 说明 |
---|---|
r | 使用寄存器保存 |
m | 使用内存保存 |
i | 使用立即数保存 |
InputOperands
InputOerands
位于OutputOperands
之后,使用:
(分号)隔开,其格式同OutputOperands
一致,唯一的区别是InputOerands
变量默认是只读的,并且无法使用读写限制符号进行控制(即constraint
中无法使用+
和=
),因此同时需要读写的变量只能写在OutputOperands
中
[asmSymbolicName] constraint (cvariablename)
asm volatile (
"movl %%eax, %0\n\t"
"addl %0, %1"
: [v1] "=r" (variable1), "+r" (variable3), [v4] "=r" (variable4)
: "r" (variable2)
: "eax"
);
Clobbers
Clobbers
描述汇编代码对寄存器和内存的修改情况(除开InputOperands
和OutputOperands
中指定的变量之外),位于InputOerands
之后,使用:
分号隔开, 如果需要修改多个寄存器,使用,
隔开,通过指针修改内存则需要加入"memory"
。
: ”eax“, "ebx", "memory"
例子
使用内联汇编实现字节序转换
// x86
#define BSWAP4(des, src) asm ( "movl %1, %0\n"\
"bswap %0" \
: "=r"(des) \
: "r"(src))
// arm
#define BSWAP4(des, src) asm ("rev %0, %1" \
: "=r"(des) \
: "r"(src))