我们在编写C/C++代码时,如果在有较高性能需求的时候,可以使用汇编代码来编写相应的函数,C/C++直接调用即可。汇编的语法格式有两种,一种是我们在Windows下常见的Intel的语法格式;另一种是GCC下使用的AT&T格式的语法,这种语法对我们经常使用Windows或者从Windows开始学习编程的开发人员来说会感觉很晦涩。 我们看看MS方式的内联汇编写法:

1	__asm
2	{
3		push rax
4		xor rax, rax
5		pop rax
6	}

再看看,AT&T的写法:

1__asm("push %rax");
2__asm("xor %rax, %rax");
3__asm("pop %rax");

C/C++提供了外联与内联两种方式来与汇编代码进行交互,不过内联的方式需要编译器的支持。在X86下,微软的C/C++编译器是支持内联Intel语法格式的汇编代码的,但是在X64下就不再支持了。GCC是在X86与X64下都支持内联AT&T语法格式的汇编代码。

如果我们要把Windows下的带有内联Intel语法格式的汇编在Linux下使用GCC进行编译,就需要把内联汇编的格式改为AT&T的语法格式,这是一件很痛苦的事情,目前还不清楚是否有编译参数可以不修改任何代码支持Intel的语法格式。而Clang编译器可以做到,可以直接加参数:

-fms-extensions

或者

-fasm-blocks

即可编译,不需要任何代码修改。如果只需要支持MS的内联汇编功能,建议使用-fasm-blocks参数,如果还需要其它MS的扩展功能才使用-fms-extensions。-fms-extensions参数在命令行帮助中有列出,而-fasm-blocks参数未列出,是看源码得知的,参见:ParseStmtAsm.cpp中的

 1/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
 2/// this routine is called to collect the tokens for an MS asm statement.
 3///
 4/// [MS]  ms-asm-statement:
 5///         ms-asm-block
 6///         ms-asm-block ms-asm-statement
 7///
 8/// [MS]  ms-asm-block:
 9///         '__asm' ms-asm-line '\n'
10///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
11///
12/// [MS]  ms-asm-instruction-block
13///         ms-asm-line
14///         ms-asm-line '\n' ms-asm-instruction-block
15///
16StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
17  SourceManager &SrcMgr = PP.getSourceManager();
18  SourceLocation EndLoc = AsmLoc;
19  SmallVector<Token, 4> AsmToks;

clang默认是直接支持AT&T格式的内联汇编的,所以在加了上述参数后,也可以使用AT&T格式的汇编,即两种语法格式混合使用。 如:

 1int main(int argc, char *argv[])
 2{
 3	__asm
 4	{
 5		push rax
 6		xor rax, rax
 7		pop rax
 8	}
 9
10	__asm("push %rax");
11	__asm("xor %rax, %rax");
12	__asm("pop %rax");
13
14	return 0;
15}

一样可以通过clang编译,运行反汇编:

该方法在LLVM Clang的Windows版本即clang-cl、Mingw下的clang以及Linux下的clang下编译通过,clang-cl本身就是兼容MS的cl的,所以不添加任何参数,直接支持MS方式的内联汇编。