9

GCC 工具链默认使用 AT&T 汇编器语法,但可以通过.intel_syntax指令获得对 Intel 语法的支持。

此外,AT&T 和 Intel 语法在 aprefix和 anoprefix版本中都可用,它们的不同之处在于它们是否需要在寄存器名称前加上%sigil。

根据存在的指令,地址常量的格式会发生变化。

让我们考虑以下 C 代码

*(int *)0xdeadbeef = 0x1234;

使用objdump -d,我们发现它被编译成下面的汇编指令

movl $0x1234,0xdeadbeef

由于不涉及任何寄存器,因此这是 and 的正确语法.att_syntax prefix.att_syntax noprefix即。嵌入在 C 代码中,它们看起来像这样

__asm__(".att_syntax prefix");
__asm__("movl $0x1234,0xdeadbeef");

__asm__(".att_syntax noprefix");
__asm__("movl $0x1234,0xdeadbeef");

您可以选择用括号括住地址常量,即。

__asm__("movl $0x1234,(0xdeadbeef)");

也会起作用。

将印记添加到普通地址常量时,代码将无法复制

__asm__("movl $0x1234,$0xdeadbeef"); // won't compile

当用括号括起来这个表达式时,编译器将发出错误代码而不发出警告,即

__asm__("movl $0x1234,($0xdeadbeef)"); // doesn't warn, but doesn't work!

这将错误地发出指令

movl $0x1234,0x0

在 Intel 模式下,地址常量必须以段寄存器以及操作数大小和PTR标志为前缀(如果可能存在歧义)。在我的机器上(一台装有 Windows XP 和当前 MinGW 和 Cygwin GCC 版本的英特尔双核笔记本电脑),ds默认使用该寄存器。

常量周围的方括号是可选的。如果段寄存器被省略,但括号存在,地址常数也能被正确识别。不过,省略寄存器会在我的系统上发出警告。

prefix模式下,段寄存器必须以 为前缀%,但仅使用括号仍然有效。这些是生成正确指令的不同方法:

__asm__(".intel_syntax noprefix");
__asm__("mov DWORD PTR ds:0xdeadbeef,0x1234");
__asm__("mov DWORD PTR ds:[0xdeadbeef],0x1234");
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns!

__asm__(".intel_syntax prefix");
__asm__("mov DWORD PTR %ds:0xdeadbeef,0x1234");
__asm__("mov DWORD PTR %ds:[0xdeadbeef],0x1234");
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns!

省略段寄存器和括号将无法编译

__asm__("mov DWORD PTR 0xdeadbeef,0x1234"); // won't compile

我会将此问题标记为社区 wiki,因此如果您有任何有用的内容要添加,请随时添加。

4

2 回答 2

5

/指令仅控制寄存器是否需要前缀noprefix(*)(至少看起来是这样,这是文档提到的唯一区别)。值文字在 AT&T 语法中总是需要前缀,而在 Intel 语法中从不需要。所以以下工作:prefix%$

__asm__(".intel_syntax prefix");
__asm__("MOV [DWORD PTR 0xDEADBEEF], 0x1234");

如果您真的倾向于在使用 GCC 编译并使用 GAS 汇编的 C 代码中使用 Intel 语法内联汇编,请不要忘记在其后添加以下内容,以便汇编器可以了解由生成的其余(AT&T 语法)汇编海合会:

__asm__(".att_syntax prefix");

我看到前缀/无前缀区别的原因是,对于 AT&T 语法,%英特尔架构上的寄存器并不真正需要前缀,因为寄存器是命名的。但是为了统一起见,它可能存在,因为其他一些架构(即 SPARC)已经注册了编号,在这种情况下,单独指定一个低数字对于是否指的是内存地址或寄存器是模棱两可的。

于 2009-02-14T17:42:58.673 回答
1

这是我自己的结果:

*(int *)0xdeadbeaf = 0x1234; // reference implementation

// AT&T: addresses without sigil; parentheses are optional

__asm__(".att_syntax prefix");
__asm__("movl $0x1234,0xdeadbeaf");     // works
__asm__("movl $0x1234,(0xdeadbeaf)");   // works
__asm__("movl $0x1234,($0xdeadbeaf)");  // doesn't work, doesn't warn!
//__asm__("movl $0x1234,$0xdeadbeaf");  // doesn't compile
//__asm__("movl 0x1234,0xdeadbeaf");    // doesn't compile
//__asm__("movl 0x1234,(0xdeadbeaf)");  // doesn't compile

__asm__(".att_syntax noprefix");
// same as above: no registers used!

// Intel: addresses with square brackets or segment register prefix
// brackets without prefix will warn

__asm__(".intel_syntax noprefix");
__asm__("mov DWORD PTR ds:0xdeadbeaf,0x1234");      // works
__asm__("mov DWORD PTR ds:[0xdeadbeaf],0x1234");    // works
__asm__("mov DWORD PTR [0xdeadbeaf],0x1234");       // works, but warns!
//__asm__("mov DWORD PTR 0xdeadbeaf,0x1234");       // doesn't compile

// `prefix` will add % to register names

__asm__(".intel_syntax prefix");
__asm__("mov DWORD PTR %ds:0xdeadbeaf,0x1234");     // works
__asm__("mov DWORD PTR %ds:[0xdeadbeaf],0x1234");   // works
__asm__("mov DWORD PTR [0xdeadbeaf],0x1234");       // works, but warns!
//__asm__("mov DWORD PTR 0xdeadbeaf,0x1234");       // doesn't compile

__asm__(".att_syntax prefix");
于 2009-02-14T18:09:55.987 回答