MOV 操作码规范

Alp*_*_Pi 0 assembly masm machine-code x86-16

在我可以找到的关于 MOV 助记符的操作码的所有文档中,每个操作码都没有单独记录。操作码B8h+记录为将 16 位或 32 位数据移动到 16 位或 32 位注册表。究竟关注什么注册表,取决于B8h操作码高出多远。也就是说,要获得B8h类型为 MOV 指令的操作码,您需要B8h将寄存器的编号相加。问题是,我没有找到有关每个注册表数量的任何信息。以下是我的猜测,但我不确定。

目的地登记处。操作码。

AX  B8

CX  B9

DX  BA

BX  BB

EAX BC

ECX BD

EDX BE

EBX BF
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 6

您的表中有错误:16 位和 32 位操作数大小具有相同的操作码,并通过操作数大小前缀字节区分,以使用当前不是默认操作数大小的字节。(所以 16 位指令在 32 位和 64 位模式下需要一个额外的字节。)这适用于所有操作码,而不仅仅是mov.

您可以自己使用汇编器和反汇编器进行检查,该反汇编器在输出中包含指令编码的十六进制字节。

对于大多数指令,8 和 16/32/64 有单独的操作码,但我想当从 16 位扩展到 32 位时,没有足够的操作码空间来添加另一个版本的所有内容。

  • mov r8, imm8使用操作码B0+rb(所以,B0-B7)。
  • mov r16/32/64, imm16/32/64使用操作码B8+rw/rd(so,B8-BF),带有操作数大小前缀,带有 .W 位设置的 REX 前缀)或不带前缀。

既然我们在讨论这个话题,值得一提的是mov r/m64, imm32(sign-extended move-immediate) 必须使用一个额外的字节来编码目标寄存器或有效地址,但仍然比mov r64, imm64. 在 AT&T 语法中,如果需要,您必须使用movabs助记符,否则汇编程序会将您的常量截断为 32 位。


寄存器编号的实际二进制编码似乎在英特尔参考手册第 2 卷的三个地方指定。(链接自 wiki)。

与这个问题最相关(寄存器编码为操作码的最后 3 位),有表 3-1。与 +rb, +rw, +rd, +ro 相关的寄存器代码,在第 3.1 节:解释指令参考页中

编码与附录 B.1.3 中的相同,它再次指出 3 位寄存器字段可以是操作码的最后 3 位。(我猜所有使用+rb/的操作码+rd都是 8 的倍数,所以添加 0-7 = 设置最后 3 位)。B.1.4.1 有表格,其中寄存器每个可能的 3 位值选择,用于 16 位和 32 位操作数大小(在非 64 位模式下)。

它是:

encoding | 8bit reg | 32bit reg 
000  |       AL   |      EAX
001  |       CL   |      ECX
010  |       DL   |      EDX
011  |       BL   |      EBX
100  |       AH   |      ESP
101  |       CH   |      EBP
110  |       DH   |      ESI
111  |       BH   |      EDI
Run Code Online (Sandbox Code Playgroud)

其他操作数大小和 64 位模式的表就在附近。(带有 REX 前缀的指令通常不能寻址 AH/BH/CH/DH,只能寻址 16 个 GP 寄存器的低字节。我猜这是因为当与 REX 前缀ch一起使用时bpl,编码与 发生冲突。)


第 2 章中还有一个寄存器编码表(用于在 mod/rm 字段中使用),并附有表格。

在表之后的 64 位模式部分还提到将 dest 寄存器编码到操作码中。

第 2.2.1.1 章:编码(在 IA-32e 部分内):

Intel 64 和 IA-32 指令格式通过在编码中使用 3 位字段指定最多三个寄存器,具体取决于格式:

  • ModR/M:ModR/M 字节的 reg 和 r/m 字段
  • ModR/M with SIB:ModR/M字节的reg字段,SIB(scale,index,base)字节的base和index字段
  • 不带 ModR/M 的指令:操作码的 reg 字段