核心内容摘要
桥本有菜t2u摄影集
第 2 章指令格式CHAPTER 2 — INSTRUCTION FORMAT本章描述所有 Intel 64 与 IA-32 处理器架构中的指令格式。
针对保护模式Protected Mode、实模式Real Mode以及虚拟 8086 模式Virtual-8086 Mode下的指令格式将在第
1 节中进行说明。
IA-32e 模式及其各个子模式所引入的指令格式扩展与变化将在第
2 节中进行说明。
1 保护模式、实模式与虚拟 8086 模式下的指令格式INSTRUCTION FORMAT FOR PROTECTED MODE, REAL MODE, AND VIRTUAL-8086 MODEIntel 64 与 IA-32 架构的指令编码都是图
所示指令格式的子集。
一条指令由以下部分组成是否出现取决于具体指令可选的指令前缀Instruction Prefixes顺序不限主操作码Primary Opcode最多 3 个字节寻址方式说明符Addressing-Form Specifier如果需要由ModR/M 字节构成在某些情况下还包括SIBScale-Index-Base字节偏移量Displacement如果需要立即数Immediate如果需要
2.
1 指令前缀Instruction Prefixes指令前缀被划分为四个组每一组都有各自允许使用的前缀编码。
对于任意一条指令而言每一组最多只需要使用一个前缀组
1、
2、
4 各最多一个。
来自第 1 组到第 4 组的前缀在编码时可以以任意顺序排列。
■ 第 1 组Group 1锁前缀与重复前缀Lock and Repeat PrefixesLOCK 前缀使用F0H编码。
REPNE / REPNZ 前缀使用F2H编码。
重复非零Repeat-Not-Zero前缀仅适用于字符串指令和输入/输出指令。
F2H 也被某些指令用作强制前缀mandatory prefix。
REP 或 REPE / REPZ 前缀使用F3H编码。
重复Repeat前缀仅适用于字符串指令和输入/输出指令。
F3H 也被某些指令用作强制前缀mandatory prefix。
■ 第 2 组Group 2段覆盖前缀Segment Override Prefixes2EH— CS 段覆盖前缀与任何分支指令一起使用是保留的36H— SS 段覆盖前缀与任何分支指令一起使用是保留的3EH— DS 段覆盖前缀与任何分支指令一起使用是保留的26H— ES 段覆盖前缀与任何分支指令一起使用是保留的64H— FS 段覆盖前缀与任何分支指令一起使用是保留的65H— GS 段覆盖前缀与任何分支指令一起使用是保留的分支预测提示前缀Branch Hints2EH— 分支不跳转Branch Not Taken仅用于 Jcc 指令3EH— 分支跳转Branch Taken仅用于 Jcc 指令■ 第 3 组Group 3操作数大小覆盖前缀Operand-Size Override Prefix使用66H编码。
66H 也被某些指令用作强制前缀。
■ 第 4 组Group 467H— 地址大小覆盖前缀Address-Size Override PrefixLOCK 前缀说明LOCK 前缀F0H用于在多处理器环境中强制某些操作对共享内存的独占访问。
关于该前缀的详细说明请参见第 3 章《指令集参考A–M》中的“LOCK—Assert LOCK# Signal Prefix”。
重复前缀说明REP / REPNE重复前缀F2H、F3H用于使指令对字符串中的每一个元素重复执行。
这些前缀只能用于字符串指令和 I/O 指令包括MOVSCMPSSCASLODSSTOSINSOUTS将重复前缀或未定义的操作码用于其他 Intel 64 或 IA-32 指令是保留行为此类用法可能导致不可预测的行为。
某些指令会将F2H 或 F3H用作强制前缀以表达不同的指令语义。
通常情况下强制前缀应当放置在其他可选前缀之后这一规则的例外情况在 **
2.
1 节《REX 前缀》**中说明。
分支预测提示前缀说明分支预测提示前缀2EH、3EH允许程序向处理器提示某个分支最可能执行的路径。
这些前缀只能与条件分支指令Jcc一起使用。
在其他指令中使用分支预测提示前缀或使用未定义的操作码均属于保留行为可能导致不可预测的行为。
操作数大小覆盖前缀66H操作数大小覆盖前缀允许程序在16 位与32 位操作数大小之间切换。
默认操作数大小由当前运行模式决定使用该前缀将选择非默认的操作数大小某些SSE2 / SSE3 / SSSE3 / SSE4 指令以及使用三字节主操作码序列的指令会将66H用作强制前缀以表示不同的功能。
通常情况下强制前缀应当放在其他可选前缀之后REX 前缀的特殊情况见
2.
1 节。
将66H用于其他未定义场景是保留行为此类用法可能导致不可预测的行为。
地址大小覆盖前缀67H地址大小覆盖前缀67H允许程序在16 位与32 位地址大小之间切换。
默认地址大小由当前运行模式决定使用该前缀将选择非默认的地址大小当指令的操作数不位于内存中时使用该前缀或其他未定义操作码属于保留行为可能导致不可预测的行为。
2.
2 操作码Opcodes主操作码Primary Opcode的长度可以是1 字节、2 字节或 3 字节。
在某些情况下还会在ModR/M 字节中编码一个额外的 3 位操作码字段。
此外主操作码内部还可能划分出更小的字段用于表示操作方向偏移量大小寄存器编码条件码符号扩展方式具体由哪些编码字段参与操作码的定义取决于该指令所属的操作类别。
双字节操作码格式Two-Byte Opcode Formats用于通用指令和SIMD 指令的双字节操作码格式包括以下两种形式之一以转义操作码字节 0FH作为主操作码后跟一个操作码字节或以强制前缀66H、F2H 或 F3H开头后跟转义操作码字节 0FH再跟一个操作码字节与上一种形式的操作码结构相同示例指令CVTDQ2PD的操作码字节序列如下F30FE6其中第一个字节F3H是强制前缀在此情形下它不被视为重复前缀三字节操作码格式Three-Byte Opcode Formats用于通用指令和SIMD 指令的三字节操作码格式包括以下两种形式之一以转义操作码字节 0FH作为主操作码后跟两个额外的操作码字节或以强制前缀66H、F2H 或 F3H开头后跟转义操作码字节 0FH再跟两个额外的操作码字节与上一种形式的操作码结构相同示例针对XMM 寄存器的PHADDW指令其操作码字节序列如下660F3801其中第一个字节66H是强制前缀操作码表达式的定义位置有效的操作码表达式定义在以下附录中附录 A附录 B
2.
3 ModR/M 与 SIB 字节ModR/M and SIB Bytes许多访问内存操作数的指令在主操作码之后都会跟随一个寻址方式说明符字节addressing-form specifier该字节称为ModR/M 字节。
ModR/M 字节包含三个信息字段mod 字段mod 字段与 r/m 字段组合后可以形成32 种不同的取值其中包括8 种寄存器形式和24 种内存寻址方式。
reg/opcode 字段reg/opcode 字段用于指定一个寄存器编号或额外的3 位操作码信息reg/opcode 字段的具体用途由主操作码决定。
r/m 字段r/m 字段可以直接指定一个寄存器作为操作数或与 mod 字段组合用于编码一种内存寻址方式在某些指令中mod 字段与 r/m 字段的特定组合还会被用来表示操作码相关的信息。
SIB 字节Scale-Index-Base ByteModR/M 字节的某些编码形式需要一个第二个寻址字节即SIBScale-Index-Base字节。
在32 位地址模式下以下寻址形式必须使用 SIB 字节基址 索引base index比例 × 索引scale × indexSIB 字节包含以下字段scale 字段用于指定比例因子scale factorindex 字段用于指定索引寄存器的寄存器编号base 字段用于指定基址寄存器的寄存器编号编码参考有关ModR/M 字节和SIB 字节的具体编码方式请参见第
2.
5 节。
2.
4 偏移量与立即数字节Displacement and Immediate Bytes某些寻址形式会在ModR/M 字节之后如果存在SIB 字节则在 SIB 字节之后紧跟一个偏移量displacement。
如果指令需要偏移量该偏移量的长度可以是1 字节2 字节4 字节如果一条指令指定了立即数操作数immediate operand该操作数始终位于所有偏移量字节之后。
立即数操作数的长度可以是1 字节2 字节4 字节
2.
5 ModR/M 与 SIB 字节的寻址方式编码Addressing-Mode Encoding of ModR/M and SIB BytesModR/M 字节与 SIB 字节的取值及其对应的寻址形式列于表
至 表
中表
由 ModR/M 字节指定的16 位寻址形式表
由 ModR/M 字节指定的32 位寻址形式表
由 SIB 字节指定的32 位寻址形式在ModR/M 字节的 reg/opcode 字段表示扩展操作码的情况下其有效编码列于附录 B中。
ModR/M 表中有效地址的含义在表
与表
中“Effective Address有效地址”一列列出了通过ModR/M 字节中的 Mod 与 R/M 字段可分配给指令第一个操作数的32 种有效地址形式。
前24 种形式用于指定内存位置后8 种形式Mod 11B用于指定通用寄存器MMX 技术寄存器XMM 寄存器Mod 与 R/M 字段的编码方式在表
与表
中Mod列与R/M列给出了为获得“Effective Address”列中所列地址形式而需要的Mod 字段与 R/M 字段的二进制编码值。
示例说明以Mod 11BR/M 000B所在的表项为例该表项对应的操作数可以是通用寄存器EAX、AX 或 ALMMX 技术寄存器MM0XMM 寄存器XMM0具体使用哪一种寄存器由操作码字节与操作数大小属性共同决定。
Reg/Opcode 字段作为第二操作数再看表中的第七行标记为“REG ”该行说明了当3 位 Reg/Opcode 字段用于指定第二个操作数的位置时的用法。
第二个操作数必须是通用寄存器或MMX 技术寄存器或XMM 寄存器表中第 1 至第 5 行列出了 Reg/Opcode 字段各取值所对应的寄存器同样实际使用的寄存器类型由操作码字节与操作数大小属性决定。
Reg/Opcode 字段作为操作码扩展如果指令不需要第二个操作数则Reg/Opcode 字段可以被用作操作码扩展opcode extension。
这种用法在表中由第六行表示标记为“/digit (Opcode)”。
需要注意的是第六行中的取值以十进制形式表示ModR/M 字节 256 种取值的表示方式表
与表
的主体部分位于“Value of ModR/M Byte (in Hexadecimal)”标题之下包含一个32 × 8 的矩阵以十六进制形式展示了ModR/M 字节全部 256 种可能取值。
在该矩阵中表格的列指定了第
3、
5 位表格的行指定了第
0、
2 位以及第
7 位下图展示了如何对表中的某一个取值进行解释。
注释NOTES当有效地址中包含 BP 作为索引寄存器时默认使用的段寄存器是SS对于其他有效地址默认使用的段寄存器是DS。
disp16表示一个16 位偏移量该偏移量紧随ModR/M 字节之后并被加到索引值中。
disp8表示一个8 位偏移量该偏移量紧随ModR/M 字节之后会先进行符号扩展sign-extended再被加到索引值中。
注释NOTES[--][--]这种记号表示在ModR/M 字节之后还会紧跟一个SIB 字节。
disp32表示一个32 位偏移量该偏移量紧随ModR/M 字节之后如果存在 SIB 字节则位于SIB 字节之后并被加到索引值中。
disp8表示一个8 位偏移量该偏移量紧随ModR/M 字节之后如果存在 SIB 字节则位于SIB 字节之后在参与计算前会进行符号扩展sign-extended然后再加到索引值中。
表
说明SIB 字节编码表
的组织方式用于展示SIB 字节全部 256 种可能取值以十六进制形式表示。
表格顶部列出了作为基址base使用的通用寄存器以及它们在SIB 字节的 base 字段中对应的取值。
表格主体中的各行用于表示索引寄存器由 SIB 字节的第
3、
5 位指定比例因子scaling factor由 SIB 字节的第
7 位确定注释NOTES[*]这种记号的含义如下当MOD 00B时[*]表示无基址寄存器仅使用一个32 位偏移量disp32。
否则[*]表示disp8 或 disp32 [EBP]。
由此可得到以下寻址方式MOD 位有效地址Effective Address00[scaled index] disp3201[scaled index] disp8 [EBP]10[scaled index] disp32 [EBP]
2 IA-32e 模式IA-32e ModeIA-32e 模式包含两个子模式分别是兼容模式Compatibility Mode允许64 位操作系统在不修改的情况下运行大多数传统的保护模式软件。
64 位模式64-Bit Mode允许64 位操作系统运行为访问 64 位地址空间而编写的应用程序。
2.
1 REX 前缀REX PrefixesREX 前缀是在64 位模式下使用的一类指令前缀字节其作用包括指定通用寄存器GPR和SSE 寄存器指定64 位操作数大小指定扩展的控制寄存器并非所有指令在 64 位模式下都需要使用 REX 前缀。
只有在以下情况下才必须使用 REX 前缀指令引用了扩展寄存器或指令使用了64 位操作数如果在指令中使用了没有语义意义的 REX 前缀该前缀会被忽略。
REX 前缀的使用规则每条指令最多只能包含一个 REX 前缀。
如果使用 REX 前缀REX 前缀字节必须紧邻操作码字节之前或者紧邻转义操作码字节0FH之前。
当 REX 前缀与包含强制前缀的指令一起使用时强制前缀必须位于 REX 前缀之前以保证 REX 前缀能够紧邻操作码字节或转义字节。
示例说明以带有 REX 前缀的CVTDQ2PD指令为例F3 REX0FE6在该指令中F3为强制前缀REX位于 F3 与0F E6之间其他位置放置 REX 前缀的情况都会被忽略。
指令长度限制即使使用了 REX 前缀指令长度仍然受 15 字节上限的限制。
有关 REX 前缀位置与格式的示意请参见图
。
2.
2.
1 编码方式Encoding在 Intel 64 与 IA-32 的指令格式中根据具体的编码形式最多可以通过3 位字段来指定三个寄存器具体如下使用 ModR/M 字节的指令通过ModR/M 字节中的 reg 字段与 r/m 字段来指定寄存器。
使用 ModR/M 与 SIB 字节的指令通过ModR/M 字节中的 reg 字段以及SIBscale, index, base字节中的 base 与 index 字段来指定寄存器。
不使用 ModR/M 字节的指令通过操作码中的 reg 字段来指定寄存器。
在64 位模式下上述指令编码格式本身并不会发生变化。
用于在64 位上下文中定义这些字段所需的额外位由REX 前缀的引入来提供。
2.
2.
2 关于 REX 前缀字段的进一步说明More on REX Prefix FieldsREX 前缀是一组16 个操作码它们在操作码映射表中占据同一行对应40H 到 4FH这一区间。
在IA-32 操作模式以及兼容模式Compatibility Mode下这些操作码表示的是有效指令INC 或 DEC。
而在64 位模式下同样的操作码被解释为REX 指令前缀不再被视为独立的指令。
单字节 INC / DEC 指令在 64 位模式下的情况单字节操作码形式的 INC / DEC 指令在64 位模式下不可用。
不过INC / DEC 的功能仍然可以通过这些指令的ModR/M 编码形式来实现FF /0→ INCFF /1→ DECREX 前缀格式与示例有关REX 前缀格式的汇总说明请参见表
。
图
到 图
展示了 REX 前缀字段在实际指令中的使用示例。
某些REX 前缀字段组合是无效的。
在这种情况下该 REX 前缀会被忽略。
REX 前缀字段的补充说明REX.W 位REX.W 可用于确定操作数大小但并不能单独决定最终的操作数位宽。
与66H 操作数大小覆盖前缀类似64 位操作数大小覆盖对字节级操作没有影响。
REX.W 与 66H 的关系非字节操作对于非字节操作如果同时使用66H 前缀并且REX.W 1则66H 前缀会被忽略。
如果同时使用66H 前缀与REX 前缀且REX.W 0则操作数大小为16 位。
REX.R 位REX.R 用于扩展ModR/M 字节中的 reg 字段当该字段用于编码以下寄存器时有效通用寄存器GPRSSE 寄存器控制寄存器调试寄存器当 ModR/M 字节用于指定其他类型的寄存器或用于定义扩展操作码时REX.R 位会被忽略。
REX.X 位REX.X 用于扩展SIB 字节中的 index 字段。
REX.B 位REX.B 的作用包括以下几种情况之一扩展ModR/M 字节中的 r/m 字段所指定的基址寄存器或扩展SIB 字节中的 base 字段或扩展操作码中的 reg 字段用于访问通用寄存器GPR。
在 IA-32 架构中字节寄存器AH、AL、BH、BL、CH、CL、DH 和 DL被编码为编号0 到 7的寄存器具体位置可以位于ModR/M 字节的 reg 字段ModR/M 字节的 r/m 字段操作码中的 reg 字段REX 前缀为字节寄存器提供了额外的寻址能力使得通用寄存器GPR中最低有效字节也可以用于字节级操作。
特殊寄存器编码情况在某些情况下ModR/M 字节与 SIB 字节中的字段组合对寄存器编码具有特殊含义。
对于其中的一些组合即使存在REX 前缀由 REX 前缀扩展的字段也不会被解码。
这些情况在表
中进行了详细说明。
注释NOTES无需关心 REX.B 的取值。
2.
2.
3 偏移量Displacement在64 位模式下内存寻址仍然使用现有的 32 位 ModR/M 与 SIB 编码形式。
ModR/M 与 SIB 所使用的偏移量大小不会发生变化仍然为8 位偏移量disp8或32 位偏移量disp32这些偏移量在 64 位模式下会被**符号扩展sign-extended**为64 位后参与地址计算。
2.
2.
4 直接内存偏移形式的 MOV 指令Direct Memory-Offset MOVs在64 位模式下MOV 指令的直接内存偏移形式被扩展为可以指定一个64 位的立即数绝对地址。
该地址被称为moffsetmemory offset。
指定该64 位内存偏移地址时不需要使用任何前缀。
对于这些 MOV 指令内存偏移量的大小遵循地址大小的默认值在 64 位模式下为64 位。
有关这些指令的编码形式请参见表
。
2.
2.
5 立即数Immediates在64 位模式下立即数操作数的常见大小仍然是32 位。
当指令的操作数大小为 64 位时处理器会在使用之前将所有立即数**符号扩展sign-extended**为64 位。
对64 位立即数操作数的支持是通过扩展现有的移动指令语义来实现的具体体现在MOV reg, imm16/32这类指令上。
这些指令操作码B8H–BFH会将16 位或 32 位的立即数数据取决于有效的操作数大小移动到一个 **通用寄存器GPR**中。
当有效操作数大小为 64 位时这些指令可以用于将一个立即数加载到 GPR 中。
此时需要使用REX 前缀以将默认的32 位操作数大小覆盖为64 位操作数大小。
示例48B88877665544332211对应的汇编指令为MOV RAX,1122334455667788H
2.
2.
6 RIP 相对寻址RIP-Relative Addressing在64 位模式下引入了一种新的寻址形式——RIP 相对寻址relative instruction-pointer addressing。
在该寻址方式中有效地址通过以下方式形成有效地址 下一条指令的 64 位 RIP 偏移量在IA-32 架构以及兼容模式下相对于指令指针的寻址仅适用于控制转移指令。
而在64 位模式下使用 ModR/M 寻址方式的指令也可以使用RIP 相对寻址。
如果不使用 RIP 相对寻址所有基于 ModR/M 的指令寻址方式都会将内存地址视为相对于 0 的地址。
RIP 相对寻址的偏移量范围RIP 相对寻址允许特定的ModR/M 编码形式使用一个有符号的 32 位偏移量disp32相对于64 位 RIP来访问内存。
这使得可访问的地址范围为RIP ± 2GB编码形式说明表
列出了RIP 相对寻址所使用的ModR/M 与 SIB 编码形式。
在当前的 ModR/M 与 SIB 编码中已经存在一些32 位偏移量寻址的冗余形式存在一种 ModR/M 编码形式以及若干种 SIB 编码形式RIP 相对寻址正是通过使用其中的一种冗余编码形式来实现的。
Disp32 编码在 64 位模式下的重新定义在64 位模式下ModR/M 的 Disp3232 位偏移量编码被重新定义为RIPDisp32而不再表示仅由偏移量构成的绝对地址。
有关该重新定义的具体细节请参见表
。
RIP 相对寻址所使用的ModR/M 编码并不依赖任何前缀的使用。
具体而言用于选择RIP 相对寻址的r/m 位字段编码 101B不会受到 REX 前缀的影响。
例如当REX.B 1且r/m 101B即试图选择 R13并且mod 00B此时编码结果仍然表示 RIP 相对寻址而不是以 R13 作为基址寄存器。
关于 R13 与 r/m 101B 的特殊情况REX.B 与 ModR/M 组合后的 4 位 r/m 字段不会被完整解码。
因此若软件希望在无偏移量的情况下访问R13必须将其编码为R130也就是说需要使用一个值为 0 的 1 字节偏移量disp8 0而不能使用mod 00B, r/m 101B的编码形式。
RIP 相对寻址与地址大小前缀的关系RIP 相对寻址的启用条件是64 位模式而不是64 位地址大小因此使用地址大小覆盖前缀不会禁用 RIP 相对寻址。
地址大小前缀的作用仅是将计算得到的有效地址截断为 32 位然后再对其进行零扩展zero-extend扩展为 64 位
2.
2.
7 默认的 64 位操作数大小Default 64-Bit Operand Size在64 位模式下有两类指令的默认操作数大小即为 64 位因此不需要使用 REX 前缀来指定 64 位操作数大小。
这两类指令是近跳转指令Near branches所有隐式引用 RSP 的指令不包括远跳转指令
2.
2 控制寄存器与调试寄存器的附加编码Additional Encodings for Control and Debug Registers在64 位模式下为控制寄存器Control Registers和调试寄存器Debug Registers提供了更多的编码方式。
当ModR/M 字节中的 reg 字段用于编码控制寄存器或调试寄存器时REX.R 位用于对该字段进行扩展参见表
。
这些扩展编码使处理器能够访问CR8–CR15DR8–DR15CR8 的引入在64 位模式下引入了一个新的控制寄存器 CR8。
CR8 被定义为任务优先级寄存器Task Priority RegisterTPR。
未实现寄存器的访问行为在IA-32e 模式的最初实现中CR9–CR15DR8–DR15尚未被实现。
任何尝试访问这些未实现寄存器的行为都会导致处理器产生一个无效操作码异常#UD。