如何通过Opcodes判断是否需要ModR/M?

How to determine if ModR/M is needed through Opcodes?

我在看ia-32指令格式,发现如果需要的话ModR/M就是一个字节,但是如何判断是否需要,有人说是由Opcode决定的,但如何?我想知道细节,有没有有用的权威文件解释细节?

Intel 的第 2 卷手册详细介绍了每条指令的每种形式的操作数编码。例如仅采用著名的 add 指令的 8 位操作数大小版本,该指令具有 2 reg,rm 形式; rm,直接形式; add al, imm8

的 no-ModRM 2 字节缩写
Opcode    Instruction    | Op/En |  64-bit Mode | Compat/Leg Mode |  Description
04 ib     ADD AL, imm8   |  I    |   Valid           Valid         Add imm8 to AL.
80 /0 ib  ADD r/m8, imm8 |  MI   |   Valid           Valid         Add imm8 to r/m8.
00 /r     ADD r/m8, r8   |  MR   |   Valid           Valid         Add r8 to r/m8.
02 /r     ADD r8, r/m8   |  RM   |   Valid           Valid         Add r/m8 to r8.

在其下方,指令操作数编码¶ table 详细说明了上面 Op/En(操作数编码)列中的那些 I / MI / MR / RM 代码的含义:

Op/En   | Operand 1        | Operand 2     | Operand 3  Operand 4
RM      | ModRM:reg (r, w) | ModRM:r/m (r) |  NA        NA
MR      | ModRM:r/m (r, w) | ModRM:reg (r) |  NA        NA
MI      | ModRM:r/m (r, w) | imm8/16/32    |  NA        NA
I       | AL/AX/EAX/RAX    | imm8/16/32    |  NA        NA

请注意,“I”操作数形式没有提到 ModRM,因此没有。但是 MI 确实有。 (/r 字段由操作码 table 中 80 /0 中的 /0 填充: full explanation83 /0 add r/m64, imm8 为例。 )

请注意,RM 和 MR 的区别仅在于 r/m 操作数(可以是内存)是目标还是源。


大多数 x86 ALU 指令 有四个 reg,r/m 操作码,one for each direction(MR 与 RM)每个 8 位和非8 位(大小由 66 操作数大小前缀决定,在 16 和 32 之间翻转,或 REX.W 64 位,或 none 默认操作数大小(模式下为 32 16 位除外)。

加上标准直接形式:

  • r/m8 位立即数(共享一个操作码字节 overloaded via /digit
  • r/m 16/32/64 位,带 8 位符号扩展立即数(共享通过 /digit 重载的操作码字节)
  • r/m 16/32/64 位和 16/32/sign_extended_32 位立即数(共享一个通过 /digit 重载的操作码字节)
  • AL 没有带 8 位立即数的 modrm(整个操作码字节本身)
  • AX/EAX/RAX 没有 modrm,imm16 / imm32 / sign_extended_imm32(整个操​​作码字节本身)

每个助记符都有很多操作码,这就是为什么 8086 没有足够的空间来遵循与通常指令相同的模式。 (Why are there no NAND, NOR and XNOR instructions in X86?)

另请参阅 https://wiki.osdev.org/X86-64_Instruction_Encoding,它涵盖的内容比 Intel 的手册更简洁。另请注意,您可以通过使用 NASM 或 GAS 之类的汇编器组装一些东西并查看机器代码来检查您的理解。或者只是查看现有程序的反汇编 objdump -drwC -Mintel /bin/ls | less

一些反汇编程序甚至将每条指令的机器代码中的字节分组在一起,例如将 4 字节立即数作为一个组与操作码和 modrm 分开。 (Agner Fog's objconv是这样的。)