在关于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
答案 0 :(得分:4)
表中有错误: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
(因此,B8-BF),带有操作数大小前缀,带有.W位设置的REX前缀),或者没有前缀。由于我们关注这个话题,值得一提的是mov r/m64, imm32
(符号扩展move-immediate)必须使用额外的字节来编码目标寄存器或有效地址,但是仍然比mov r64, imm64
短。在AT& T语法中,如果需要,必须使用movabs
助记符,否则汇编程序会将常量截断为32位。
注册号的实际二进制编码似乎在英特尔参考手册第2卷中的三个位置指定。(从x86 wiki链接)。
与此问题最相关(寄存器编码为操作码的最后3位),其中表3-1。注册代码与+ rb,+ rw,+ rd,+ ro 相关联,第3.1节:解释说明参考页。
编码与附录B.1.3中的编码相同,后者再次指出3位寄存器字段可以是操作码的最后3位。 (我猜所有使用+rb
/ +rd
的操作码都是8的倍数,所以加0-7 =设置最后3位)。对于16位和32位操作数大小(非64位模式),B.1.4.1具有为每个可能的3位值选择寄存器的表。
它是:
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
其他操作数大小和64位模式的表就在附近。 (具有REX前缀的指令通常不能解决AH / BH / CH / DH,只能解决16个GP寄存器的低字节。我想这是因为ch
的编码与{{1当与REX前缀一起使用时。)
在第2章中还有一个寄存器编码表(用于在mod / rm字段中使用)和表格。
还提到将dest寄存器编码到操作码中,在64位模式的部分中,在表之后。
第2.2.1.1节:编码(在IA-32e部分内):
Intel 64和IA-32指令格式最多可指定三个寄存器 通过在编码中使用3位字段,具体取决于格式:
- ModR / M:ModR / M字节的reg和r / m字段
- 带SIB的ModR / M:ModR / M字节的reg字段,SIB(scale,index,base)字节的基本和索引字段
- 没有ModR / M的说明:操作码的注册字段