GCC工具链默认使用AT&T汇编语法,但是可以通过
此外,AT&T和Intel语法都有一个带有前缀
根据存在哪些指令,地址常量的格式会发生变化。
让我们考虑以下C代码。
使用
由于没有寄存器涉及,这是
您可以选择使用括号将地址常量括起来,例如:
这会错误地发出指令。
在Intel模式下,如果可能存在歧义,一个地址常量必须附带一个段寄存器以及操作数大小和PTR标志。在我的机器上(一台安装有Windows XP和当前MinGW和Cygwin GCC版本的Intel双核笔记本电脑上),默认使用ds寄存器。
方括号可以省略。如果省略了段寄存器但保留了方括号,则地址常量也会被正确识别。但是,在我的系统上省略寄存器会发出警告。
在前缀模式下,段寄存器必须用%作为前缀,但仅使用方括号仍然有效。这些是生成正确指令的不同方式:
省略段寄存器和括号将无法编译。
.intel_syntax
指令支持Intel语法。此外,AT&T和Intel语法都有一个带有前缀
prefix
和不带前缀noprefix
的版本,它们之间的区别在于是否需要在寄存器名称前加上%
符号。根据存在哪些指令,地址常量的格式会发生变化。
让我们考虑以下C代码。
*(int *)0xdeadbeef = 0x1234;
使用
objdump -d
命令,我们发现它被编译为以下汇编指令。movl $0x1234,0xdeadbeef
由于没有寄存器涉及,这是
.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)");
加上符号后,普通地址常量的代码将无法编译。
同样适用于will work as well。
__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版本的Intel双核笔记本电脑上),默认使用ds寄存器。
方括号可以省略。如果省略了段寄存器但保留了方括号,则地址常量也会被正确识别。但是,在我的系统上省略寄存器会发出警告。
在前缀模式下,段寄存器必须用%作为前缀,但仅使用方括号仍然有效。这些是生成正确指令的不同方式:
__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
我将把这个问题标记为社区维基,因此如果你有任何有用的补充,请随意添加。
0xdeadbeaf
替换($0xdeadbeaf)
似乎可以解决问题;测试后我会编辑问题... - Christophgcc -S
产生了预期的结果。 - Christoph