原创翻译再创作,原文章地址:https://www.intel.cn/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-2a-manual.pdf 第二章2.1/ 2.2
翻译若有勘误,请在下方评论或联系
chenbanghao37@163.com
文章目录
2.1 保护模式、实模式和虚拟8086模式的指令格式
Intel 64 and IA-32 架构指令格式编码如图所示,完整指令由任意顺序的前缀、最多三字节的操作码字节、寻址形式说明符(ModR/M或SIB)、位移及立即数组成(详情见图)
指令前缀
指令前缀分为四组,每组中只能选一个前缀,各组所选前缀可以任意顺序排列
第一组
- 锁定前缀
0xF0
(强制在多处理器情况下独占并使用共享内存) - 重复前缀(可用于字符串和I/O指令以重复指令或作为一些指令的强制前缀以区分不同的功能)
- REPNE/REPNZ 前缀
0xF2
(当CPUID.(EAX=07H, ECX=0):EBX.MPX[bit 14]
、BNDCFGU.EN and/or IA32_BNDCFGS.EN
被设置或在near
近调用之前时可使用此前缀以编码绑定前缀) - REP及REPE/REPZ前缀
0xF3
(可作为POPCNT/LZCNT/ADOX的强制前缀)
- REPNE/REPNZ 前缀
- 锁定前缀
第二组
- 段覆盖前缀(与其他任何分支指令一起使用)
- 2EH-CS 段覆盖前缀
- 36H-SS 段覆盖前缀
- 3EH-DS 段覆盖前缀
- 26H-ES 段覆盖前缀
- 64H-FS 段覆盖前缀
- 65H-GS 段覆盖前缀
- 分支提示前缀(
0x2E
表示未采用分支,0x3E
表示采用分支)
- 段覆盖前缀(与其他任何分支指令一起使用)
第三组
- 操作数大小覆盖前缀
0x66
(若操作系统为32位,则操作数大小为16位;操作系统为64位,则操作数大小为32位或SSE2/SSE3/SSSE3/SSE4类指令和占用操作码三个字节的指令可使用此作为强制前缀以区分不同的功能)
- 操作数大小覆盖前缀
第四组
- 地址大小覆盖前缀
0x67
(若操作系统为32位,则模拟寻址空间为16位;操作系统为64位,则模拟寻址空间为32位)
- 地址大小覆盖前缀
操作码
操作码长1~3个字节,可以在操作码中定义较小的字段。通用指令和SIMD指令的长两字节的操作码由一个转义操作码字节0x0F
和一个操作码字节组成,长三字节的操作码由一个转义操作码字节0x0F
和两个操作码字节组成。
ModR/M 和 SIB 字节
ModR/M于操作码之后,用于引用内存的指令,为助于寻址的说明字节,共有三个字段:
- mod字段:为00b,则使用间接寻址方式;01b及10b,则使用disp寻址模式,在原地址的基础上增加1, 2, 4个字节的偏移量,且偏移量必须在寻址形式说明符(ModR/M或SIB)之后;11b为直接寻址模式。
- reg字段:其值由主操作码指定,可为寄存器编号或三位扩展操作码信息
- r/m字段:将寄存器作为操作数或与mod字段组合以编码寻址方式或表示操作码信息
base-plus-index
和32位scale-plus-index
需要使用SIB字节,其共包含三个字段:index和base字段用于指定index和base寄存器,scala字段用于指定比例因子
寻址模式编码
ModR/M 16位寻址模式,disp8和disp16分别指在所得地址之上添加8位及16位位移,于其右上角的小型数字为原文注释的标注
ModR/M 32位寻址模式,
[--][--]
表示SIB于ModR/M之后,与其一起使用;disp32表示在所得地址之上添加32位位移
于前两图中,mod及r/m字段列中的二进制编码组合表示出32个有效地址以此分配给指令中的第一个操作数(r/m),任意表的1-5行列出对应于表中ModR/M值的寄存器,寄存器的十进制和二进制编码分别于第6行和第7行,第二个操作数使用此寄存器表示位置或用于操作码扩展。
ModR/M的二进制值由Mod/REG/RM组成
该表第一行和第二三行分别指base字段指定的寄存器和相应的值,SS列指定比例因子,index列指定寄存器。
[*] 表示法:
Mod字节 有效地址 00 [scaled index] + disp32 01 [scaled index] + disp8 + [EBP] 10 [scaled index] + disp32 + [EBP]
2.2 IA-32E 模式
IA-32E有两个子模式,分别是使64位操作系统无修改的兼容大多数旧版保护模式下软件的兼容模式和专用于64位操作系统的64位模式。
REX 前缀
REX前缀只能使用于64位模式下,每条指令只能使用一个REX前缀,于转移码前缀(0x0F)或操作码之前,强制前缀之后,扩展操作数和寄存器为64位,并指定GPR和SSE寄存器。
REX前缀共由五部分组成:0100/W/R/X/B, 0100
为固定搭配,W是扩展操作数大小的开关,R/X分别是ModR/M reg
字段和SIB index
字段的扩展,B为ModR/M r/m
、SIB base
及不足一个字节大小的操作码之后的寄存器的扩展。
R/ X/ B位与操作码、ModR/M、SIB中的寄存器码相连以扩展出更大的寄存器寻址空间(>7)
在IA-32模式下REX前缀与不足一位的操作码可以合并在一起视为一个单独的指令(0x40-0x4F),而在64位模式下操作码必须配合ModR/M才能实现相同功能。当REX与0x66前缀一起使用时,REX前缀优先,且二者都不能操作特定字节。
某些ModR/M或SIB字节字段(的组合)具有特殊意义,会影响REX(与REX.B字节无关):
字段编码 | 普通情况含义 | 兼容模式特殊操作 | 操作的含义 |
---|---|---|---|
mod不等于0b11 & r/m=0b100(ESP) | REX.B字段失效,基于R12和ESP的寻址需要SIB字节 | 使用SIB字节 | SIB字节的寻址基于ESP |
mod=0 & r/m=0b101(EBP) | REX.B字段失效,没有位移的RBP/R13也必须要设置mod=0b10 & disp = 0 | 未使用base寄存器 | 没有位移的EBP也必须设置mod=0b01 & disp=0 |
SIB.index = 0b0100 | REX.B生效,可扩展SIB.index字节为R12(0b1000) | 未使用SIB.index寄存器 | ESP不能作为index寄存器 |
SIB.index = 0b0101(EBP) | REX.B失效(无法解码),需要使用位移 | 若mod=0,则SIB.index字节失效 | SIB.index取决于mod值 |
编码
寄存器
指令可以拥有三种寄存器搭配方式(无论任何模式):只使用ModR/M字段的经典reg+r/m
组合、使用三个寄存器的reg+SIB.base+SIB.index
组合和指令二进制码不足一个字节于操作码字节内reg
字段。
控制和调试寄存器为CR8-15
和DR8-15
,在64位模式下CR8为附加控制寄存器和任务优先级寄存器(TPR)。
在IA-32E的初版中未实现
CR8-15
和DR8-15
,访问其则引发无效操作码异常(#UD)
操作数
在64位模式下,操作数中立即数的大小默认为32位,扩展为64位以使用,而靠近分支或隐式引用RSP的指令和使用带有REX前缀的MOV reg, imm16/32
类的指令(0xB8-0xBF)可以实现原生64位立即数。
偏移
在64位模式下,由ModR/M或SIB操控的8或32位的偏移将扩展为64位以支持64位空间的寻址,MOV指令使用64位立即数代替原来的直接偏移形式进行绝对寻址(moffset)
相对寻址(RIP)
RIP-relative,相对于指令指针的寻址(mod=0b00),64位模式下特有的寻址方式,不受地址大小前缀的影响,通过在reg字段指定的寄存器的值之上添加32位有符号位移得到有效地址,使得位移不再基于0寻址(IA-32架构和兼容模式RIP只适用于控制传输指令)
以下为相对寻址的编码方式:
编码方式 | 兼容模式下结果 | 64位模式下结果 |
---|---|---|
mod = 0b00 & r/m = 0b101(标志) | Disp32 | RIP + Disp32,若使用SIB则其base字段必须为0 |
SIB.base = 101 & index = 100(标志)& scale = 0, 1, 2, 4 | 当mod=0b00时,才使用Disp32 | 与往常一样 |
只有使用为0的一字节位移才可以使用REX.B扩展为0b101时的r/m字段