读懂X86的OpCode码表(机翻)

Intel 64和IA-32架构软件开发者手册2021年6月版合订本2647页至2652页,附录A:操作码映射表(OpCode Map)。AMD64架构开发者手册2021年3月合订本1205页开始也是相似内容。

使用本章中的操作码表解释IA-32和Intel 64体系结构目标代码。指令分为编码组:
1字节、2字节和3字节操作码编码用于编码整数、系统、MMX技术、SSE/SSE2/SSE3/SSE3/SSE4和VMX指令。表A-2至表A-6给出了这些指令的映射。
转义操作码(格式:ESC字符、操作码、ModR/M字节)用于浮点指令。表A-7至表A-22中提供了这些指令的映射。
注意:操作码映射中的所有空白都是保留的,不得使用。不要依赖于未定义或空白操作码的操作。

A.1 使用操作码表
本附录中的表格列出了指令的操作码(包括所需的指令前缀、相关ModR/M字节中的操作码扩展)。表中的空白单元格表示保留或未定义的操作码。标记为“Reserved-NOP”的单元格也是保留的,但在某些处理器上可能表现为NOP。软件不应使用操作码对应的空白单元格或标记为“Reserved-NOP”的单元格,也不应依赖于这些操作码的当前行为。
操作码映射表由操作码字节高低4位的十六进制值组织。对于1字节编码(表A-2),使用操作码的高4位来索引操作码表的一行;使用低4位对表中的一列进行索引。对于以0FH开头的2字节操作码(表A-3),跳过任何指令前缀、0FH字节(0FH前面可能有66H、F2H或F3H),并使用下一个操作码字节的上下4位值来索引表行和列。类似地,对于以0F38H或0F3AH开头的3字节操作码(表A-4),跳过任何指令前缀0F38H或0F3AH,并使用第三个操作码字节的上下4位值索引表行和列。参见第A.2.4节“操作码查找单字节、双字节和三字节操作码示例”。
当ModR/M字节提供操作码扩展时,此信息限定操作码执行。有关ModR/M字节中的操作码扩展如何修改表A-2和表A-3中的操作码映射的信息,请参见第A.4节。
浮点指令的转义(ESC)操作码表在每一页的顶部识别操作码的八个高位。见A.5节。如果伴随的ModR/M字节在00H-BFH范围内,则位3-5(每页第三个表的顶行)以及ModR/M的reg位确定操作码。00H-BFH范围之外的ModR/M字节由该节每页的底部两个表映射。

A.2 缩略语的关键
操作数由Zz形式的两字符代码标识。第一个字符(大写字母)指定寻址方法;第二个字符(小写字母)指定操作数的类型。

A.2.1 寻址方法代码
以下缩写用于记录寻址方法:
A:直接寻址:指令没有ModR/M字节;操作数的地址在指令中编码。不能应用基址寄存器、索引寄存器或比例因子(例如,far JMP(EA))。
B: VEX前缀的VEX.vvvv字段选择通用寄存器。
C: ModR/M字节的reg字段选择一个控制寄存器(例如,MOV(0F20,0F22))。
D: ModR/M字节的reg字段选择调试寄存器(例如,MOV(0F21,0F23))。
E: ModR/M字节跟随操作码并指定操作数。操作数是通用寄存器或内存地址。如果是内存地址,则根据段寄存器和以下任意值计算地址:基址寄存器、索引寄存器、比例因子、位移。
F: EFLAGS/RFLAGS寄存器。
G: ModR/M字节的reg字段选择一个通用寄存器(例如,AX(000))。
H: VEX前缀的VEX.VVV字段选择由操作数类型确定的128位XMM寄存器或256位YMM寄存器。对于传统SSE编码,此操作数不存在,将指令更改为破坏性形式。
I: 即时数据:操作数值在指令的后续字节中编码。
J: 指令包含要添加到指令指针寄存器的相对偏移量(例如,JMP(0E9),LOOP)。
L: 8位立即数的高4位选择128位XMM寄存器或256位YMM寄存器,由操作数类型决定(在32位模式下忽略MSB,即最高有效位)。
M: ModR/M字节可能仅指内存(例如,BOUND、LES、LDS、LSS、LFS、LGS、CMPXCHG8B)。
N: ModR/M字节的R/M字段选择压缩四字MMX技术寄存器。
O: 指令没有ModR/M字节。操作数的偏移量在指令中编码为一个字或双字(取决于地址大小属性)。不能应用基址寄存器、索引寄存器或比例因子(例如,MOV(A0–A3))。
P: ModR/M字节的reg字段选择压缩四字MMX技术寄存器。
Q: ModR/M字节跟随操作码并指定操作数。操作数是MMX技术寄存器或内存地址。如果是内存地址,则根据段寄存器和以下任意值计算地址:基址寄存器、索引寄存器、比例因子和位移。
R: ModR/M字节的R/M字段可能仅指通用寄存器(例如,MOV(0F20-0F23))。
S: ModR/M字节的reg字段选择一个段寄存器(例如,MOV(8C,8E))。
U: ModR/M字节的R/M字段选择由操作数类型确定的128位XMM寄存器或256位YMM寄存器。
V: ModR/M字节的reg字段选择由操作数类型确定的128位XMM寄存器或256位YMM寄存器。
W: ModR/M字节跟随操作码并指定操作数。操作数是128位XMM寄存器、256位YMM寄存器(由操作数类型确定)或内存地址。如果是内存地址,则根据段寄存器和以下任意值计算地址:基址寄存器、索引寄存器、比例因子和位移。
X: 由DS:rSI寄存器对寻址的内存(例如,MOVS、CMPS、OUTS或LODS)。
Y: 由ES:rDI寄存器对寻址的内存(例如,MOVS、CMPS、INS、STOS或SCAS)。

A.2.2 操作数类型码
以下缩写用于记录操作数类型:
a:内存中的两个单字操作数或内存中的两个双字操作数,具体取决于操作数大小属性(仅由BOUND指令使用)。
b:字节,与操作数大小属性无关。
c:字节或字,取决于操作数大小属性。
d:双字,与操作数大小属性无关。
dq: 双四字,与操作数大小属性无关。
p: 32位、48位或80位指针,具体取决于操作数大小属性。
pd: 128位或256位压缩双精度浮点数据。
pi: 四字MMX技术寄存器(例如:mm0)。
ps: 128位或256位压缩单精度浮点数据。
q: 四字,与操作数大小属性无关。
qq: 四元四字(256位),与操作数大小属性无关。
s: 6字节或10字节伪描述符。
sd: 128位双精度浮点数据的标量元素。
ss: 128位单精度浮点数据的标量元素。
si: 双字整数寄存器(例如:eax)。
v: 字、双字或四字(在64位模式下),具体取决于操作数大小属性。
w: 字,与操作数大小属性无关。
x: 基于操作数大小属性的dq或qq。
y: 双字或四字(在64位模式下),具体取决于操作数大小属性。
z: 字表示16位操作数大小,双字表示32位或64位操作数大小。

A.2.3 寄存器码
当一个操作码需要一个特定的寄存器作为操作数时,该寄存器由名称标识(例如,AX、CL或ESI)。该名称指示寄存器是64、32、16还是8位宽。
当寄存器宽度取决于操作数大小属性时,使用eXX或rXX形式的寄存器标识符。eXX用于16位或32位大小的情况;rXX用于16、32或64位大小的情况。例如:eAX表示在操作数大小属性为16时使用AX寄存器,在操作数大小属性为32时使用eAX寄存器。rAX可以表示AX、EAX或rAX。
当REX.B位用于修改操作码reg字段中指定的寄存器时,可通过在寄存器名称中添加“/x”来表示这一事实,以表示其他可能性。例如,rCX/r9用于指示寄存器可以是rCX或r9。请注意,在这种情况下,r9的大小由操作数大小属性决定(与rCX一样)。

A.2.4 操作码查找单字节、双字节和三字节操作码示例
本节提供了演示如何使用操作码映射的示例。

A.2.4.1 单字节操作码指令
1字节操作码的操作码映射如表A-2所示。1字节操作码的操作码映射按行(十六进制值的最低有效4位)和列(十六进制值的最高有效4位)排列。表中的每个条目都列出了以下操作码类型之一:
使用第A.2节中列出的符号的指令助记符和操作数类型
用作指令前缀的操作码
对于操作码映射中与指令对应的每个条目,解释主操作码后字节的规则属于以下情况之一:
需要ModR/M字节,并根据《Intel 64和IA-32架构软件开发人员手册》第2A卷第A.1节和第2章“指令格式”中列出的缩写进行解释。操作数类型根据第A.2节中列出的符号列出。
需要ModR/M字节,并在ModR/M字节的reg字段中包含操作码扩展。解释ModR/M字节时使用表A-6。
ModR/M字节的使用是保留的或未定义的。这适用于表示指令前缀的条目或不带使用ModR/M操作数的指令的条目(例如:60H,PUSHA;06H,PUSH ES)。

例A-1. 查找1字节操作码示例
ADD指令的操作码030500000000H使用1字节操作码映射(表A-2)解释如下:
操作码的第一位数字(0)表示表行,第二位数字(3)表示表列。这将查找带有两个操作数的加法操作码。
第一个操作数(Gv类型)表示一个通用寄存器,它是一个字或双字,具体取决于操作数大小属性。第二个操作数(Ev类型)表示后面的ModR/M字节,指定操作数是字还是双字通用寄存器或内存地址。
此指令的ModR/M字节为05H,表示随后出现32位位移(00000000 h)。ModR/M字节(位3-5)的reg/opcode部分为000,表示EAX寄存器。
此操作码的指令为ADD EAX、mem_op,mem_op的偏移量为00000000 h。
一些1字节和2字节的操作码指向组号(操作码映射表中的阴影项)。组号表示指令使用ModR/M字节中的reg/opcode位作为操作码扩展(参考A.4节)。

A.2.4.2 双字节操作码指令
表A-3中所示的双字节操作码映射包括长度为两字节或三字节的主操作码。长度为2字节的主操作码以转义操作码0FH开头。第二个操作码字节的上下四位用于索引表a-3中的特定行和列。
长度为3字节的两字节操作码以一个强制前缀(66H、F2H或F3H)和转义操作码(0FH)开头。第三个字节的上下四位用于索引表a-3中的特定行和列(第二个操作码字节为3字节转义操作码38H或3AH时除外;在这种情况下,请参阅第a.2.4.3节)。
对于操作码映射中的每个条目,解释主操作码后面字节的规则属于以下情况之一:
需要ModR/M字节,并根据《英特尔64和IA-32体系结构软件开发人员手册》第2A卷第A.1节和第2章“指令格式”中列出的缩写进行解释。操作数类型根据第A.2节中列出的符号列出。
需要ModR/M字节,并在ModR/M字节的reg字段中包含操作码扩展。解释ModR/M字节时使用表A-6。
ModR/M字节的使用是保留的或未定义的。这适用于表示没有使用ModR/M编码的操作数的指令的条目(例如:0F77H,EMMS)。

例A-2. 查找2字节操作码示例
使用表a-3查找SHLD指令的操作码0FA4050000000003H。
操作码位于A行第4列。该位置指示具有操作数Ev、Gv和Ib的SHLD指令。请按如下方式解释操作数:
-Ev: ModR/M字节跟在操作码后面,用于指定一个字或双字操作数。
-Gv: ModR/M字节的reg字段选择通用寄存器。
-Ib: 是后续指令的编码字节。
第三个字节是ModR/M字节(05H)。ModR/M的mod和opcode/reg字段表示32位位移用于定位内存中的第一个操作数,eAX作为第二个操作数。
操作码的下一部分是目标内存操作数(00000000 h)的32位位移。最后一个字节存储提供移位计数(03H)的立即字节。

通过这个分解,可以看出这个操作码代表指令:SHLD DS:00000000 h,EAX,3。

A.2.4.3三字节操作码指令
表A-4和表A-5中所示的三字节操作码映射包括长度为3或4字节的主操作码。长度为3字节的主操作码以两个转义字节0F38H或0F3A开头。第三个操作码字节的上下四位用于索引表a-4或表a-5中的特定行和列。
长度为4字节的三字节操作码以强制前缀(66H、F2H或F3H)和两个转义字节(0F38H或0F3AH)开头。第四字节的上下四位用于索引表a-4或表a-5中的特定行和列。
对于操作码映射中的每个条目,解释主操作码后字节的规则分为以下几种情况:
需要ModR/M字节,并根据《英特尔64和IA-32体系结构软件开发人员手册》第2A卷A.1和第2章“指令格式”中列出的缩写进行解释。操作数类型根据第A.2节中列出的符号列出。

例A-3. 查找3字节操作码示例
使用表a-5查找操作码660F3A0FC108H的PALIGNR指令。
66H为前缀,0F3AH表示使用表a-5。操作码位于第0行第F列,表示使用操作数Vdq、Wdq和Ib的PALIGNR指令。操作数解释如下:
-Vdq: ModR/M字节的reg字段选择128位XMM寄存器。
-Wdq: ModR/M字节的R/M字段选择128位XMM寄存器或内存位置。
-Ib: 是后续指令的编码字节。
下一个字节是ModR/M字节(C1H)。reg字段指示第一个操作数为XMM0。mod显示R/M字段指定一个寄存器,R/M表示第二个操作数是XMM1。
最后一个字节是立即字节(08H)。
通过这一细分,可以看出这个操作码代表指令:PALIGNR XMM0,XMM1,8。

A.2.4.4 VEX前缀说明
包含VEX前缀的指令分别基于隐含的0F、0F38H和0F3AH的VEX.mmmmm字段编码,相对于2字节和3字节操作码映射进行组织。VEX编码指令的操作码映射中的每个条目都基于操作码字节的值,类似于非VEX编码指令。
VEX前缀包括几个位字段,这些位字段编码隐含的66H、F2H、F3H前缀功能(VEX.pp)和操作数大小/操作码信息(VEX.L)。详见第4章。
操作码表A2-A6包括带VEX前缀的指令和不带VEX前缀的指令。许多条目只生成一次,但同时表示指令的凸形式和非凸形式。如果存在VEX前缀,则所有操作数都有效,助记符的前缀通常为“v”。如果VEX前缀不存在,则VEX.VV操作数不可用,并且从助记符中删除前缀“v”。
少数指令仅以VEX形式存在,并标有上标“v”。
VEX前缀指令的操作数大小可由操作数类型代码确定。128位向量由“dq”表示,256位向量由“qq”表示,操作数支持128位或256位的指令由VEX.L确定,由“x”表示。例如,条目“VMOVUPD Vx,Wx”表示支持VEX.L=0和VEX.L=1。

A.2.5 操作码表中使用的上标
表A-1包含关于特定编码的注释。这些注释在以下操作码图中用上标表示。灰色单元格表示指令分组。

表A-1. 操作码表中使用的上标

上标符号 符号含义
1A 用作操作码扩展的ModR/M字节的第5、4和3位(请参阅第A.4节“单字节和双字节操作码的操作码扩展”)。
1B 有意尝试生成无效操作码异常(#UD)时,请使用0F0B操作码(UD2指令)、0FB9H操作码(UD1指令)或0FFFH操作码(UD0指令)。
1C 有些指令使用相同的双字节操作码。如果指令有变化,或操作码代表不同的指令,则ModR/M字节将用于区分指令。有关解码指令所需的ModR/M字节值,请参见表A-6。
i64 指令无效或在64位模式下不可编码。在64位模式下,40到4F(单字节INC和DEC)是REX前缀组合(使用FE/FF Grp 4和5表示INC和DEC)。
o64 指令仅在64位模式下可用。
d64 在64位模式下,指令默认为64位操作数大小,不能对32位操作数大小进行编码。
f64 在64位模式下,操作数大小强制为64位操作数大小(在64位模式下,此指令忽略更改操作数大小的前缀)。
v 只存在VEX形式。该指令没有遗留的SSE形式。对于整数GPR指令,它意味着需要VEX前缀。
v1 当无法从数据大小推断时,VEX128和SSE表格仅存在(无VEX256)。

A.3 单字节、双字节和三字节操作码映射
见下表A-2至表A-5。这些表格是多页的演示文稿。具有顺序关系的行和列被放置在面对面的页面上,以使查找任务更容易。请注意,并非每页都有表格脚注。各表的脚注见表的最后一页。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章