我可以将 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 指令的位置是不是重要
AT&T 语法中的 3 或 4 参数 x86 程序集[重复]
x86 程序集:“subl”命令如何在 AT&T 语法中工作