gpt4 book ai didi

gcc - 如何设置 gcc 以永久使用 intel 语法?

转载 作者:行者123 更新时间:2023-12-04 05:27:27 44 4
gpt4 key购买 nike

我有以下代码可以使用 gcc 命令很好地编译 gcc ./example.c .程序本身调用函数“add_two”,它只是将两个整数相加。要在扩展汇编指令中使用 intel 语法,我需要首先切换到 intel,然后再切换回 AT&T。根据 gcc 文档,可以使用 gcc -masm=intel ./exmaple 完全切换到 intel 语法。 .

每当我尝试使用开关编译它时 -masm=intel它不会编译,我不明白为什么?我已经尝试删除指令 .intel_syntax但它仍然无法编译。

#include <stdio.h>

int add_two(int, int);

int main(){
int src = 3;
int dst = 5;
printf("summe = %d \n", add_two(src, dst));
return 0;
}

int add_two(int src, int dst){

int sum;

asm (
".intel_syntax;" //switch to intel syntax
"mov %0, %1;"
"add %0, %2;"

".att_syntax;" //switch to at&t syntax
: "=r" (sum) //output
: "r" (src), "r" (dst) //input
);

return sum;
}

gcc -masm=intel ./example.c编译上述程序的错误信息是:
tmp/ccEQGI4U.s: Assembler messages:
/tmp/ccEQGI4U.s:55: Error: junk `PTR [rbp-4]' after expression
/tmp/ccEQGI4U.s:55: Error: too many memory references for `mov'
/tmp/ccEQGI4U.s:56: Error: too many memory references for `mov'

最佳答案

使用 -masm=intel并且不要使用任何 .att_syntax内联汇编中的指令。 这适用于 GCC,我认为适用于 ICC,以及您使用的任何约束。其他方法没有。

我认为 Clang 不支持 Intel 语法 GNU C inline asm . Clang 的使用 Intel 语法 asm 的选项( -masm=intel 或等效的 -mllvm --x86-asm-syntax=intel )仅控制它如何打印 asm,而不是它如何组装输入 inline-asm。例如https://godbolt.org/z/8BCzp-显示 clang -masm=intel口译add %0, 1add dword ptr [1], eax .

Clang 确实支持 MSVC 样式的 asm 块内的 Intel 语法,但这很糟糕(没有限制,因此输入/输出必须通过内存。

如果您使用 clang 对寄存器名称进行硬编码,-masm=intel会可用。但它噎住了 mov %eax, 5在 Intel 语法模式下,您不能让 %0扩展为 AT&T 语法寄存器名称。
-masm=intel使编译器使用 .intel_syntax noprefix在它的 asm 输出文件的顶部,并在你的 inline-asm 语句之外从 C 生成 asm 时使用 Intel 语法。 使用 .att_syntax在 asm 模板的底部破坏了编译器的 asm ,因此会出现类似 PTR [rbp-4] 的错误消息对汇编程序来说看起来像垃圾(期待 AT&T 语法)。

“mov 的操作数过多”是因为在 AT&T 语法中,mov eax, ebxmov从内存操作数(符号名称 eax )到内存操作数(符号名称 ebx )

有人建议使用 .intel_syntax noprefix.att_syntax prefix围绕你的 asm 模板。这有时可以工作,但这是有问题的。并且与-masm=intel的首选方法不兼容.

“三明治”方法的问题:

当编译器将操作数替换到你的 asm 模板中时,它会根据 -masm= 这样做。 . 对于内存操作数 这将始终中断(寻址模式语法完全不同)。

即使对于寄存器,它也会与 clang 中断。 Clang 的内置汇编器不接受 %eax作为 Intel 语法模式下的寄存器名称,并且不接受 .intel_syntax prefix (与通常与 Intel 语法一起使用的 noprefix 相反)。

考虑这个函数:

int foo(int x) {
asm(".intel_syntax noprefix \n\t"
"add %0, 1 \n\t"
".att_syntax"
: "+r"(x)
);
return x;
}

它使用 GCC ( Godbolt ) 组装如下:
        movl    %edi, %eax
.intel_syntax noprefix
add %eax, 1 # AT&T register name in Intel syntax
.att_syntax

夹心法取决于接受 GAS %eax即使在 Intel 语法模式下也可以作为寄存器名称。来自 GNU Binutils 的 GAS 可以,但 clang 的内置汇编器不能。

在 Mac 上,即使使用真正的 GCC,asm 输出也必须与 as 组合在一起。那是基于 clang,而不是 GNU Binutils。

在该源代码上使用 clang 会提示:
<source>:2:35: error: unknown token in expression
asm(".intel_syntax noprefix \n\t"
^
<inline asm>:2:6: note: instantiated into assembly here
add %eax, 1
^

(错误消息的第一行没有很好地处理多行字符串文字。如果你使用 ; 而不是 \n\t 并将所有内容放在一行上,clang 错误消息效果更好,但源是一团糟.)

我没有检查 "ri" 会发生什么|编译器选择立即数时的约束;它仍然会用 $ 装饰它但是 IDK 如果 GAS 在 Intel 语法模式下也默默地忽略了这一点。

PS:你的 asm 语句有一个错误:你忘记了输出操作数上的早期破坏,所以没有什么能阻止编译器为 %0 选择相同的寄存器输出和 %2直到第二条指令才阅读的输入。然后 mov将破坏输入。

但是使用 mov因为 asm-template 的第一条或最后一条指令通常也是一个错过优化的错误。在这种情况下,您可以而且应该使用 lea %0, [%1 + %2]让编译器将结果非破坏性地写入第三个寄存器。或者只是包装 add指令(使用 "+r" 操作数和 "r" ,让编译器担心数据移动。)如果无论如何必须从内存加载值,它可以将它放在正确的寄存器中,所以没有 mov需要。

PS:可以编写适用于 -masm=intel 的内联 asm或 att , 使用 GNU C inline asm dialect alternatives .例如
void atomic_inc(int *p) {
asm( "lock add{l $1, %0 | %0, 1}"
: "+m" (*p)
:: "memory"
);
}

compiles with gcc -O2 ( -masm=att 是默认值)到
atomic_inc(int*):
lock addl $1, (%rdi)
ret

或与 -masm=intel到:
atomic_inc(int*):
lock add DWORD PTR [rdi], 1
ret

请注意 l AT&T 需要后缀, dword ptr英特尔需要,因为内存,立即数并不意味着操作数大小。并且编译器为这两种情况填充了有效的寻址模式语法。

这适用于 clang,但只有 AT&T 版本被使用过。

关于gcc - 如何设置 gcc 以永久使用 intel 语法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38953951/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com