why

当你的项目的主要语言是C/C++的时候,你需要进行极致的优化或者想实现的代码需要高度的硬件定制性时,就需要使用到内连汇编。

how

我们通过使用asm关键字,语法如下:

1
2
3
4
5
asm ( assembler template
: output operands (optional)
: input operands (optional)
: clobbered registers list (optional)
);

assembler template::汇编语言,比如”movl %%eax, %%ebx” ,这句话的意思是将eax寄存器的值拷贝到ebx寄存器中。

output operands::为assembler template中的汇编代码提供输出参数(指定assembler template中汇编代码输出到C/C++的哪个变量),并且指定这个变量存在哪个寄存器中,比如”=a”(b),表示将结果写到b这个变量中(当然需要先声明变量b),该变量存储在eax寄存器。=表示该操作数是只写的,之前的数据被抛弃。注意,如果你在assembler template中对eax寄存器赋值,那么也就修改了b变量的值。举个例子:

1
2
3
4
5
int a = 5;
asm ("movl $6,%0; movl $9,%%eax;"
:"=a"(a)
:
:);

最后,a的值为9,而不是6。

input operands:为assembler template中的汇编代码提供输入参数(指定assembler template中汇编代码需要使用到C/C++的哪个变量),并且指定该变量存储在哪个寄存器中,比如”a”(a),表示将a变量的值存储在eax寄存器。此时在assembler template中访问eax寄存器,也就是访问a变量

clobbered registers list:告诉gcc,asm里的汇编代码会使用到这些寄存器,所以gcc不能使用这里面的寄存器。当然在input或者output列出的寄存器不需要在这里重复列出,如果asm里的汇编代码会以不可预知的方式修改内存,那么还需要将”m”加到clobbered registers list。

看完了语法之后,下面以例子开始说明:

先举一个简单的例子,即将变量a的值赋值给b:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>

using namespace std;
int main() {
int b,a=10;
asm("movl %1, %%eax; movl %%eax, %0;"
:"=r"(b) /* output */
:"r"(a) /* input */
: /* clobbered register */
);
cout << "a := " << a << endl;
cout << "b := " << b << endl;
return 0;
}

其中0%表示参数b,%1表示参数a,如果是output operands中有多个参数,那么%index就会顺延,比如如果output operands是:”=r”(b),”=r”(c) 而input operands是”r(a), r(b)”,那么%0表示b,%1表示c,%2表示a,%3表示b。

写下一个例子之前,我们先了解一下cmpxchgl指令,根据文档解释,cmpxchgl有两个参数,分别是source_operand和dest。cmpxchgl会比较eax寄存器和dest中的值,如果相等,就将source_operand的值赋给dest,否则,就把dest的值赋值给eax寄存器。还有一个需要注意的是,如果在assembler template中加了lock,那么dest就必须存储在memory中。下面我们以例子说明:

1
2
3
4
5
6
7
8
9
void testCmpxchg(int compareValue,int exchangeValue,int dest){
int result = 0;
__asm__ __volatile__("lock;\n"
"cmpxchg %1, %3;\n"
:"=a"(result)
:"r"(exchangeValue),"a"(compareValue),"m"(dest)
:"memory","cc");
std::cout<<"result ="<<result<<"compareValue="<<compareValue<<"exchangeValue="<<exchangeValue<<"dest="<<dest<<std::endl;
}

输入参数是4,5,4,则输出4,4,5,5。输入参数是4,5,5,输出5,4,5,5。