使用Clang编译内联intel语法汇编的C/C++项目
我们在编写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方式的内联汇编。
- 原文作者:Witton
- 原文链接:https://wittonbell.github.io/posts/2019/2019-12-09-使用Clang编译内联intel语法汇编的C_C++项目/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。