为什么 AT&T 语法在 IN / OUT 指令中使用 DX 周围的括号,如 inb (%dx),%al

Why does AT&T syntax use parens around DX in IN / OUT instructions like inb (%dx),%al

7c6f:   ec   in     (%dx),%al

这里我的疑惑是由于()

我写代码的很多地方都可以使用 (%dx) 中的值并将其用作内存位置,并且值位于需要的值处。

但这里应该只是 in %dx,%al ;和 %dx 保持端口号 就像in 0x000,al

你的问题比较不清楚,我会尽力回答的。

使用 (%dx) 作为第一个操作数并不像您想象的那样工作; inout,
(%dx) 不是 内存操作数,这与其他指令的操作数使用相同语法的方式不同。

IN指令有两个操作数:

  1. 立即数 8 位值(如 [=16=]x42)或 DX 寄存器。

  2. ALAXEAX.

这意味着您不能为任一操作数使用内存位置。

此外,如@PeterCordes 的回答所示,使用 %dx 作为内存地址永远无效。

由于这两个原因,(%dx) 不能被解释为内存地址,因此您的汇编程序会忽略括号并将其单独解释为寄存器 %dx

也就是说in (%dx),%alin %dx,%al完全一样。

如果要从存储在内存中的端口号获取输入,必须先将值加载到 %dx 寄存器:

mov (%something),%dx
in %dx,%al

有关详细信息,请参阅 Intel IA-32 reference manual, or this reference page2A3-494 页。

in %dx, %al 汇编成相同的 0xEC 字节机器码,objdump -d 反汇编成 in (%dx),%al,如您所见。

llvm-objdump -d 确实使用了您期望的语法:inb %dx, %alinb 8, %al

AT&T 语法使用 (%dx) 作为 in / out 中的 IO 端口号是一种误导,因为它不是正常的寻址模式; DX 是唯一的选择。大概 想要表示您正在读取或写入 I/O 地址 space 的事实。但是他们做得不好,因为这与他们对直接端口号使用 in [=21=]x80, %al 不一致(与使用与绝对内存地址相同的语法的端口号 0x80 相反)。 GAS 和 LLVM 甚至不接受 in 0x80, %al,所以不,不是“就像 in 0x000,al”。

in/out指令访问IOspace,不是内存地址space。
IO space 中的“地址”称为端口号。
IOspace在现代PCI-express中仍然是一个东西,但是大多数现代设备在设备内存区域中只有MMIO寄存器,而不是IO端口,因为IO端口访问速度较慢。


objdump -drwC -Mintel 反汇编为英特尔在 their manual entry 中使用的相同语法,用于 in 的唯一形式,它在 DX 和字节 operand-size 中有一个端口。注意缺少 [dx] 括号。

   0:   ec                      in     al,dx
   1:   e4 80                   in     al,0x80

(%dx),因此特定寻址模式对任何其他指令都无效。但是,是的,(%reg) 例如 (%edx)(%bx) 是 AT&T addressing-mode 指令中内存操作数的语法,它允许正常的 reg/mem 操作数,例如 movadd.

另见