我可以将 x86 程序集的 Intel 语法与 GCC 一起使用吗?

Posted

技术标签:

【中文标题】我可以将 x86 程序集的 Intel 语法与 GCC 一起使用吗?【英文标题】:Can I use Intel syntax of x86 assembly with GCC? 【发布时间】:2012-03-10 00:19:04 【问题描述】:

我想写一个小的低级程序。对于其中的某些部分,我需要使用汇编语言,但其余代码将使用 C/C++ 编写。

那么,如果我将使用 GCC 将 C/C++ 与汇编代码混合使用,我需要使用 AT&T 语法还是可以 我使用英特尔语法?或者你如何以其他方式混合 C/C++ 和 asm(intel 语法)?

我意识到也许我别无选择,必须使用 AT&T 语法,但我想确定..

如果没有选择,我在哪里可以找到有关 AT&T 语法的完整/官方文档?

谢谢!

【问题讨论】:

如果你用 asm 写一些完整的函数,它们可以在一个单独编译的文件中。如果您不介意对 YASM 或 NASM 的构建依赖,那么使用您喜欢的任何语法都很容易。 (但是你的 asm 必须处理 Windows 和 Linux 的不同 ABI,可能使用汇编宏。)@​​987654321@,通常也与 gcc/binutils 一起安装。 (info as)。 谨慎使用 Intel 语法,因为 Clang 的集成汇编器会阻塞它。另见LLVM Issue 24232: Inline assembly operands don't work with .intel_syntax。错误报告显示 Clang 无法处理简单的否定。 【参考方案1】:

如果您使用单独的程序集文件,gas 有一个指令来支持 Intel 语法:

.intel_syntax noprefix      # not recommended for inline asm

它使用 Intel 语法,不需要在寄存器名称前加上 % 前缀。

(您也可以运行 as-msyntax=intel -mnaked-reg 以将其作为默认值而不是 att,以防您不想将 .intel_syntax noprefix 放在文件顶部。)


内联汇编:使用-masm=intel 编译

对于内联汇编,您可以使用 gcc -masm=intel 编译您的 C/C++ 源代码(有关详细信息,请参阅 How to set gcc to use intel syntax permanently?。)编译器自己的 asm 输出(插入内联 asm)将使用 Intel 语法,它会使用 Intel 语法(如 [rdi + 8] 而不是 8(%rdi))将操作数替换为 asm 模板字符串。

这适用于 GCC 本身和 ICC,但仅适用于 clang clang 14 and later。 (尚未发布,但补丁在当前主干中。)


在内联汇编的开头使用.intel_syntax noprefix,然后用.att_syntax 切换回来可以工作,但是如果您使用任何m 约束,会中断。内存引用仍将在 AT&T 语法中生成。它恰好适用于寄存器,因为 GAS 接受 %eax 作为寄存器名称,即使在 intel-noprefix 模式下也是如此。

asm() 语句末尾使用.att_syntax 也会破坏-masm=intel 的编译;在这种情况下,您的模板之后(和之前)的 GCC 自己的 asm 将采用 Intel 语法。 (Clang 没有那个“问题”;每个 asm 模板字符串都是本地的,不像 GCC,模板字符串真正成为 GCC 发送到 as 以单独组装的文本文件的一部分。)

相关:

GCC manual: asm dialect alternatives:在模板中使用att | intel 编写asm 语句,以便在使用-masm=att -masm=intel 编译时工作。使用lock cmpxchg 见an example。 https://***.com/tags/inline-assembly/info 了解更多关于一般内联汇编的信息;确保您准确地向编译器描述您的 asm 非常重要,因此它知道读取/写入的寄存器和内存。 AT&T 语法:https://***.com/tags/att/info 英特尔语法:https://***.com/tags/intel-syntax/info x86 tag wiki 包含指向手册、优化指南和教程的链接。

【讨论】:

@ugoren: -masm=intel 使编译器生成 Intel 语法。内联汇编确实需要它,否则"m" 内存限制将不起作用。 .att_syntax noprefix 需要撤消 .intel_syntax noprefix。我很确定您也可以将 "m" 与 AT&T 语法一起使用。这只是方便的问题,AFAIK。 @ugoren: 如果你使用.intel_syntax 而不使用-masm=intel"m" 将在 AT&T 语法中给出内存引用。如果您使用-masm=intel,则不需要(也不应该)返回 AT&T,因为编译器会输出 Intel 语法。 我认为混合它们听起来是个坏主意。要么接受 AT&T 语法(这很奇怪,但你可以学会接受),或者一直使用 Intel 语法。 @ugoren 请考虑删除您之前的 cmets。在 inline asm 语句中使用 intel_syntax noprefix.att_syntax 通常是个坏主意。仅在独立的 .S 文件中使用它们。在命令行上使用 -masm=intel 会好很多,并且会让 GCC 正确填写 asm 模板(例如,使用 RDI 而不是 %RDI,或者更重要的是使用 [rdi+8] 而不是 8(%rdi) 对于 "m" 操作数)。如果您希望代码无论命令行选项如何都能正常工作,请使用方言替代方案:"mov %1, %0 | %0, %1"【参考方案2】:

您可以像 ninjalj 所写的那样使用带有 -masm=intel 的内联汇编,但是当您使用内联汇编包含 C/C++ 标头时,它可能会导致错误。这是在 Cygwin 上重现错误的代码。

sample.cpp:
#include <cstdint>
#include <iostream>
#include <boost/thread/future.hpp>

int main(int argc, char* argv[]) 
    using Value = uint32_t;
    Value value = 0;
    asm volatile (
        "mov  %0, 1\n\t"   // Intel syntax
//      "movl $1, %0\n\t"  // AT&T  syntax
        :"=r"(value)::);

    auto expr = [](void) -> Value  return 20; ;
    boost::unique_future<Value> func  boost::async(boost::launch::async, expr) ;
    std::cout << (value + func.get());
    return 0;

当我构建此代码时,我收到以下错误消息。

g++ -E -std=c++11 -Wall -o sample.s sample.cpp
g++ -std=c++11 -Wall -masm=intel -o sample sample.cpp -lboost_system -lboost_thread
/tmp/ccuw1Qz5.s: Assembler messages:
/tmp/ccuw1Qz5.s:1022: Error: operand size mismatch for `xadd'
/tmp/ccuw1Qz5.s:1049: Error: no such instruction: `incl DWORD PTR [rax]'
/tmp/ccuw1Qz5.s:1075: Error: no such instruction: `movl DWORD PTR [rcx],%eax'
/tmp/ccuw1Qz5.s:1079: Error: no such instruction: `movl %eax,edx'
/tmp/ccuw1Qz5.s:1080: Error: no such instruction: `incl edx'
/tmp/ccuw1Qz5.s:1082: Error: no such instruction: `cmpxchgl edx,DWORD PTR [rcx]'

为了避免这些错误,它需要将内联汇编(代码的上半部分)与需要 boost::future 等的 C/C++ 代码(下半部分)分开。 -masm=intel 选项用于编译包含 Intel 语法内联汇编的 .cpp 文件,而不是其他 .cpp 文件。

sample.hpp:
#include <cstdint>
using Value = uint32_t;
extern Value GetValue(void);

sample1.cpp: compile with -masm=intel
#include <iostream>
#include "sample.hpp"
int main(int argc, char* argv[]) 
    Value value = 0;
    asm volatile (
        "mov  %0, 1\n\t"   // Intel syntax
        :"=r"(value)::);
    std::cout << (value + GetValue());
    return 0;


sample2.cpp: compile without -masm=intel
#include <boost/thread/future.hpp>
#include "sample.hpp"
Value GetValue(void) 
    auto expr = [](void) -> Value  return 20; ;
    boost::unique_future<Value> func  boost::async(boost::launch::async, expr) ;
    return func.get();

【讨论】:

质量标头将使用方言替代方案,因此它们可以使用-masm=intel 或不使用。

以上是关于我可以将 x86 程序集的 Intel 语法与 GCC 一起使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 x86 程序集的过程中调用 ret 指令的位置是不是重要

Intel x86组件用于比较和重置内存

AT&T 语法中的 3 或 4 参数 x86 程序集[重复]

x86 程序集:“subl”命令如何在 AT&T 语法中工作

Intel X86 仿真器加速器(HAXM 安装程序)VT/NX 未启用

在 Linux 服务器上编译 C++ 程序时 Intel 编译器的语法