The GCC toolchain uses AT&T assembler syntax by default, but support for Intel syntax is available via the .intel_syntax
directive.
GCC工具链默认使用AT&T汇编语法,但可通过.intel_syntax指令获得对Intel语法的支持。
Additionally, both AT&T and Intel syntax are available in a prefix
and a noprefix
version, which differ in whether or not they require to prefix register names with a %
sigil.
此外,AT&T和Intel语法都有前缀和noprefix版本,不同之处在于它们是否需要使用%sigil为寄存器名称添加前缀。
Depending on which directives are present, the format for address constants changes.
根据存在的指令,地址常量的格式会发生变化。
Let's consider the following C code
我们考虑以下C代码
*(int *)0xdeadbeef = 0x1234;
Using objdump -d
, we find that it's compiled to the following assembler instruction
使用objdump -d,我们发现它被编译为以下汇编程序指令
movl $0x1234,0xdeadbeef
As there are no registers involved, this is the correct syntax for both .att_syntax prefix
and .att_syntax noprefix
, ie. embedded in C code, they look like this
由于没有涉及寄存器,这是.att_syntax前缀和.att_syntax noprefix的正确语法,即。嵌入在C代码中,它们看起来像这样
__asm__(".att_syntax prefix");
__asm__("movl $0x1234,0xdeadbeef");
__asm__(".att_syntax noprefix");
__asm__("movl $0x1234,0xdeadbeef");
You can optionally surround the address constant with parentheses, ie.
您可以选择用括号括起地址常量,即。
__asm__("movl $0x1234,(0xdeadbeef)");
will work as well.
也会奏效。
When adding a sigil to a plain address constant, the code will fail to copile
将sigil添加到普通地址常量时,代码将无法复制
__asm__("movl $0x1234,$0xdeadbeef"); // won't compile
When surrounding this expression with paranthesis, the compiler will emit wrong code without warning, ie
当用paranthesis围绕这个表达式时,编译器会在没有警告的情况下发出错误的代码,即
__asm__("movl $0x1234,($0xdeadbeef)"); // doesn't warn, but doesn't work!
This will incorrectly emit the instruction
这将错误地发出指令
movl $0x1234,0x0
In Intel mode, an address constant has to be prefixed with a segment register as well as the operand size and the PTR
flag if ambiguity is possible. On my machine (an Intel dual core laptop with Windows XP and current MinGW and Cygwin GCC versions), the register ds
is used by default.
在Intel模式下,如果可能存在歧义,则地址常量必须以段寄存器为前缀,并且必须以操作数大小和PTR标志为前缀。在我的机器上(采用Windows XP和当前MinGW和Cygwin GCC版本的英特尔双核笔记本电脑),默认情况下使用寄存器ds。
Square brackets around the constant are optional. The address constant is also correctly recognized if the segment register is omitted, but the brackets are present. Omitting the register emits a warning on my system, though.
常量周围的方括号是可选的。如果省略段寄存器但是括号存在,则也可以正确识别地址常量。但是,忽略寄存器会在我的系统上发出警告。
In prefix
mode, the segment register has to be prefixed with %
, but only using brackets will still work. These are the different ways to generate the correct instruction:
在前缀模式中,段寄存器必须以%为前缀,但仅使用括号仍然有效。这些是生成正确指令的不同方法:
__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!
Omitting both segment register and brackets will fail to compile
省略段寄存器和括号将无法编译
__asm__("mov DWORD PTR 0xdeadbeef,0x1234"); // won't compile
I'll mark this question as community wiki, so if you have anything useful to add, feel free to do so.
我将此问题标记为社区维基,所以如果你有任何有用的东西可以添加,请随意这样做。
2 个解决方案
#1
The noprefix
/prefix
directives only control whether registers require a %
prefix(*) (at least it seems so and that's the only difference the documentation mentions). Value literals always need a $
prefix in AT&T syntax and never in Intel syntax. So the following works:
noprefix / prefix指令仅控制寄存器是否需要%前缀(*)(至少看起来如此,这是文档提到的唯一区别)。值文字在AT&T语法中始终需要$前缀,而在Intel语法中从不需要。以下是有效的:
__asm__(".intel_syntax prefix");
__asm__("MOV [DWORD PTR 0xDEADBEEF], 0x1234");
If you are really inclined to use Intel syntax inline assembly within C code compiled with GCC and assembled with GAS, do not forget to also add the following after it, so that the assembler can grok the rest of the (AT&T syntax) assembly generated by GCC:
如果您真的倾向于在使用GCC编译的C代码中使用Intel语法内联汇编并与GAS汇编,请不要忘记在它之后添加以下内容,以便汇编器可以查看由(AT&T语法)生成的其余部分。 GCC:
__asm__(".att_syntax prefix");
The reasoning I see for the prefix/noprefix distinction is, that for AT&T syntax, the %
prefix is not really needed for registers on Intel architecture, because registers are named. But for uniformity it can be there because some other architectures (i.e. SPARC) have numbered registered, in which case specifying a low number alone would be ambiguous as to whether a memory address or register was meant.
我看到前缀/ noprefix区别的原因是,对于AT&T语法,英特尔架构上的寄存器并不真正需要%前缀,因为寄存器是命名的。但是为了统一,它可以存在,因为一些其他体系结构(即SPARC)已经编号注册,在这种情况下,单独指定一个低数字对于是否意味着存储器地址或寄存器是不明确的。
#2
Here are my own results:
这是我自己的结果:
*(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");
#1
The noprefix
/prefix
directives only control whether registers require a %
prefix(*) (at least it seems so and that's the only difference the documentation mentions). Value literals always need a $
prefix in AT&T syntax and never in Intel syntax. So the following works:
noprefix / prefix指令仅控制寄存器是否需要%前缀(*)(至少看起来如此,这是文档提到的唯一区别)。值文字在AT&T语法中始终需要$前缀,而在Intel语法中从不需要。以下是有效的:
__asm__(".intel_syntax prefix");
__asm__("MOV [DWORD PTR 0xDEADBEEF], 0x1234");
If you are really inclined to use Intel syntax inline assembly within C code compiled with GCC and assembled with GAS, do not forget to also add the following after it, so that the assembler can grok the rest of the (AT&T syntax) assembly generated by GCC:
如果您真的倾向于在使用GCC编译的C代码中使用Intel语法内联汇编并与GAS汇编,请不要忘记在它之后添加以下内容,以便汇编器可以查看由(AT&T语法)生成的其余部分。 GCC:
__asm__(".att_syntax prefix");
The reasoning I see for the prefix/noprefix distinction is, that for AT&T syntax, the %
prefix is not really needed for registers on Intel architecture, because registers are named. But for uniformity it can be there because some other architectures (i.e. SPARC) have numbered registered, in which case specifying a low number alone would be ambiguous as to whether a memory address or register was meant.
我看到前缀/ noprefix区别的原因是,对于AT&T语法,英特尔架构上的寄存器并不真正需要%前缀,因为寄存器是命名的。但是为了统一,它可以存在,因为一些其他体系结构(即SPARC)已经编号注册,在这种情况下,单独指定一个低数字对于是否意味着存储器地址或寄存器是不明确的。
#2
Here are my own results:
这是我自己的结果:
*(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");