GCC工具链默认使用AT&T汇编语法,但可通过该.intel_syntax指令获得对Intel语法的支持.
此外,AT和T以及英特尔语法都有a prefix和a noprefix版本,不同之处在于它们是否需要使用%sigil 为寄存器名称添加前缀.
根据存在的指令,地址常量的格式会发生变化.
我们考虑以下C代码
*(int *)0xdeadbeef = 0x1234;
Run Code Online (Sandbox Code Playgroud)
使用objdump -d,我们发现它被编译为以下汇编程序指令
movl $0x1234,0xdeadbeef
Run Code Online (Sandbox Code Playgroud)
由于没有涉及到寄存器,这对于正确的语法.att_syntax prefix和.att_syntax noprefix,即.嵌入在C代码中,它们看起来像这样
__asm__(".att_syntax prefix");
__asm__("movl $0x1234,0xdeadbeef");
__asm__(".att_syntax noprefix");
__asm__("movl $0x1234,0xdeadbeef");
Run Code Online (Sandbox Code Playgroud)
您可以选择用括号括起地址常量,即.
__asm__("movl $0x1234,(0xdeadbeef)");
Run Code Online (Sandbox Code Playgroud)
也会奏效.
将sigil添加到普通地址常量时,代码将无法复制
__asm__("movl $0x1234,$0xdeadbeef"); // won't compile
Run Code Online (Sandbox Code Playgroud)
当用paranthesis围绕这个表达式时,编译器将发出错误的代码而不发出警告,即
__asm__("movl $0x1234,($0xdeadbeef)"); // doesn't warn, but doesn't work!
Run Code Online (Sandbox Code Playgroud)
这将错误地发出指令
movl $0x1234,0x0
Run Code Online (Sandbox Code Playgroud)
在Intel模式下,PTR如果可能存在歧义,则地址常量必须以段寄存器为前缀,以及操作数大小和标志.在我的机器上(采用Windows XP和当前MinGW和Cygwin GCC版本的英特尔双核笔记本电脑),ds默认使用该寄存器.
常量周围的方括号是可选的.如果省略了段寄存器,但是括号存在,也可以正确识别地址常量.但是,忽略寄存器会在我的系统上发出警告.
在prefix模式中,段寄存器必须以前缀为前缀%,但仅使用括号仍然有效.这些是生成正确指令的不同方法:
__asm__(".intel_syntax noprefix");
__asm__("mov DWORD PTR ds:0xdeadbeef,0x1234");
__asm__("mov …Run Code Online (Sandbox Code Playgroud) gnu组件标签前的美元符号是什么意思?
例如,mov msg, %si和之间有什么区别mov $msg, %si
(有关更多上下文,我正在研究x86裸机示例:https : //github.com/cirosantilli/x86-bare-metal-examples/blob/master/bios_hello_world.S)
#include "common.h"
BEGIN
mov $msg, %si
mov $0x0e, %ah
loop:
lodsb
or %al, %al
jz halt
int $0x10
jmp loop
halt:
hlt
msg:
.asciz "hello world"
Run Code Online (Sandbox Code Playgroud)
(美元($)和百分号(%)在汇编英特尔x86中代表什么?讨论了寄存器前的%和常量前的$的一般用法;但是,我不认为它几乎可以说明带有标签的$的使用如以下答案所示)