如何使用地址常量GCC x86的内联汇编 [英] How to use address constants in GCC x86 inline assembly
问题描述
GCC的工具链使用AT&放大器;通过缺省值T汇编语法,但对于Intel语法的支持是通过 .intel_syntax
指令提供
The GCC toolchain uses AT&T assembler syntax by default, but support for Intel syntax is available via the .intel_syntax
directive.
此外,无论是AT& T公司和Intel的语法是在 preFIX
和没有preFIX $ C可$ C>的版本,这在他们是否不要求与
%
印记preFIX寄存器名称不同。
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.
根据该指令是present,对于地址格式常数的变化。
Depending on which directives are present, the format for address constants changes.
让我们考虑下面的C code
Let's consider the following C code
*(int *)0xdeadbeef = 0x1234;
使用 objdump的-d
,我们发现它的编译下面的汇编指令
Using objdump -d
, we find that it's compiled to the following assembler instruction
movl $0x1234,0xdeadbeef
由于没有涉及到寄存器,这对于正确的语法 .att_syntax preFIX
和 .att_syntax没有preFIX
,即得。嵌入C code,它们看起来像这样
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
__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)");
将正常工作。
在添加印记,以一个普通地址不变,code将无法完成copile
When adding a sigil to a plain address constant, the code will fail to copile
__asm__("movl $0x1234,$0xdeadbeef"); // won't compile
在围绕这个前pression与paranthesis,编译器会发出错误的code没有警告,即
When surrounding this expression with paranthesis, the compiler will emit wrong code without warning, ie
__asm__("movl $0x1234,($0xdeadbeef)"); // doesn't warn, but doesn't work!
这将发出错误指令
movl $0x1234,0x0
在英特尔模式下,地址常量必须与段寄存器以及操作数的大小和是否歧义是尽可能 PTR
标志pfixed $ P $。在我的机器(英特尔双核笔记本电脑与Windows XP和当前的MinGW和Cygwin版本的GCC),寄存器 DS
默认情况下使用。
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.
方括号是可选的。地址常量也正确识别如果省略段寄存器,但是肘present。省略寄存器发出我的系统上警告,虽然。
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.
在 preFIX
模式下,段寄存器是prefixed与%
,但只能用括号仍然可以工作。这些都是不同的方法来产生正确的指令:
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.
推荐答案
的没有preFIX
/ preFIX
指令只控制寄存器是否需要%
preFIX(*)(至少看起来如此,这就是文档中提到的唯一区别)。值的文字总是需要一个 $
$ P $在AT&放PFIX; T语法和从未在Intel语法。所以下面的工作:
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:
__asm__(".intel_syntax prefix");
__asm__("MOV [DWORD PTR 0xDEADBEEF], 0x1234");
如果你真的倾向于到C code编译GCC和GAS组装中使用Intel语法内联汇编,不要忘了还添加以下后,使汇编程序可以神交的其余部分( AT& T公司语法)装配通过GCC生成的:
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:
__asm__(".att_syntax prefix");
我看到了preFIX的理由/没有preFIX区别是,对于AT& T公司语法中,%
preFIX不真正需要的基于英特尔架构寄存器,因为寄存器被命名。但是,对于均匀性也可以是有,因为一些其他架构(即SPARC)有编号登记,在这种情况下,单独指定一个低的数字将是不明确的,是否一个内存地址或寄存器中的意思。
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.
这篇关于如何使用地址常量GCC x86的内联汇编的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!