如何通过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 explanation 以 83 /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
是这样的。)
我在看ia-32
指令格式,发现如果需要的话ModR/M
就是一个字节,但是如何判断是否需要,有人说是由Opcode
决定的,但如何?我想知道细节,有没有有用的权威文件解释细节?
Intel 的第 2 卷手册详细介绍了每条指令的每种形式的操作数编码。例如仅采用著名的 add
指令的 8 位操作数大小版本,该指令具有 2 reg,rm 形式; rm,直接形式; add al, imm8
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 explanation 以 83 /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
是这样的。)