why
当你的项目的主要语言是C/C++的时候,你需要进行极致的优化或者想实现的代码需要高度的硬件定制性时,就需要使用到内连汇编。
how
我们通过使用asm
关键字,语法如下:
1 | asm ( assembler template |
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 | int a = 5; |
最后,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 |
|
其中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 | void testCmpxchg(int compareValue,int exchangeValue,int dest){ |
输入参数是4,5,4,则输出4,4,5,5。输入参数是4,5,5,输出5,4,5,5。