我们在编写C/C++代码时,如果在有较高性能需求的时候,可以使用汇编代码来编写相应的函数,C/C++直接调用即可。汇编的语法格式有两种,一种是我们在Windows下常见的Intel的语法格式;另一种是GCC下使用的AT&T格式的语法,这种语法对我们经常使用Windows或者从Windows开始学习编程的开发人员来说会感觉很晦涩。
我们看看MS方式的内联汇编写法:
__asm
{
push rax
xor rax, rax
pop rax
}
再看看,AT&T的写法:
__asm("push %rax");
__asm("xor %rax, %rax");
__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中的
/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
/// this routine is called to collect the tokens for an MS asm statement.
///
/// [MS] ms-asm-statement:
/// ms-asm-block
/// ms-asm-block ms-asm-statement
///
/// [MS] ms-asm-block:
/// '__asm' ms-asm-line '\n'
/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
///
/// [MS] ms-asm-instruction-block
/// ms-asm-line
/// ms-asm-line '\n' ms-asm-instruction-block
///
StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
SourceManager &SrcMgr = PP.getSourceManager();
SourceLocation EndLoc = AsmLoc;
SmallVector<Token, 4> AsmToks;
clang默认是直接支持AT&T格式的内联汇编的,所以在加了上述参数后,也可以使用AT&T格式的汇编,即两种语法格式混合使用。
如:
int main(int argc, char *argv[])
{
__asm
{
push rax
xor rax, rax
pop rax
}
__asm("push %rax");
__asm("xor %rax, %rax");
__asm("pop %rax");
return 0;
}
一样可以通过clang编译,运行反汇编:

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

本文探讨了在C/C++中使用Intel与AT&T两种不同汇编语法格式的方法,以及如何在不同平台上(如Windows与Linux)进行内联汇编的编译。特别介绍了Clang编译器如何支持MS的内联汇编,以及如何通过特定参数实现跨平台编译。
432

被折叠的 条评论
为什么被折叠?



