4. ModRM 寻址模式
Opcode 对指令提供操作码,ModRM 最主要作用是对指令的 operands 提供寻址,另一个作用是对 Opcode 进行补充,而 SIB 则是对 ModRM 进行补充寻址。
有两种情况下是无需用 ModRM 提供寻址的:
(1)一部分操作数是寄存器的,它直接嵌入 Opcode 中。
(2)一部分操作数是立即数的,它直接嵌入指令编码中。
以上图为例:
(1)C7 这个 Opcode 是 Group 属性,需要 ModRM.reg 来配合定位。
(2)ModRM.mod = 10 以提供 [SIB + disp32] 的寻址
(3)ModRM.reg = 000 表明 Opcode 是个 mov Ev, Iz
(4)SIB 由 ModRM.r/m = 100 来引导出
(5)REX.W = 1 使用 64 位的 operand
1.1、 ModRM.mod 寻址模式。
2 位组成 4 种寻址模式,总的来说,只有两种寻址模式,就是:内存寻址模式和寄存器寻址模式。 如下表所示:
ModRM.mod | 寻址模式 | 描述 |
---|---|---|
00 | [base] | 提供 [base] 形式的 memory 寻址 |
01 | [base + disp8] | 提供 [base + disp8] 形式的 memory 寻址 |
10 | [base + disp32] | 提供 [base + disp32] 形式的 memory 寻址 |
11 | register | 提供 register 寻址。 |
1.2、 ModRM.reg 寻址 register
3 位组成 8 个寄存器 ID 值,从 000 ~ 111,对应于 RAX、RCX、RDX、RBX、RSP、RBP、RSI 以及 RDI。
这个 ID 值可以被 REX.R 扩展为 4 位: 0000 ~ 1111
1.3、ModRM.r/m 寻址 register 或 memory
r/m 意即:registers/memory,提供对 register 或 memory 的寻址,它与 ModRM.mod 是密切相关的。如下表:
ModRM.mod | ModRM.r/m | ModRM.r/m 寻址 | |
---|---|---|---|
REX.B = 0 | REX.B = 1 | ||
00 | 000 | [rax] | [r8] |
001 | [rcx] | [r9] | |
010 | [rdx] | [r10] | |
011 | [rbx] | [r11] | |
100 | [SIB] | [SIB] | |
101 | [disp32] 或 [rip + disp32] | [disp32] 或 [rip + disp32] | |
110 | [rsi] | [r14] | |
111 | [rdi] | [r15] | |
01 | 000 | [rax + disp8] | [r8 + disp8] |
001 | [rcx + disp8] | [r9 + disp8] | |
010 | [rdx + disp8] | [r10 + disp8] | |
011 | [rbx + disp8] | [r11 + disp8] | |
100 | [SIB + disp8] | [SIB + disp8] | |
101 | [rbp + disp8] | [r13 + disp8] | |
110 | [rsi + disp8] | [r14 + disp8] | |
111 | [rdi + disp8] | [r15 + disp8] | |
10 | 000 | [rax + disp32] | [r8 + disp32] |
001 | [rcx + disp32] | [r9 + disp32] | |
010 | [rdx + disp32] | [r10 + disp32] | |
011 | [rbx + disp32] | [r11 + disp32] | |
100 | [SIB + disp32] | [SIB + disp32] | |
101 | [rbp + disp32] | [r13 + disp32] | |
110 | [rsi + disp32] | [r14 + disp32] | |
111 | [rdi + disp32] | [r15 + disp32] | |
11 | 000 | rax | r8 |
001 | rcx | r9 | |
010 | rdx | r10 | |
011 | rbx | r11 | |
100 | rsp | r12 | |
101 | rbp | r13 | |
110 | rsi | r14 | |
111 | rdi | r15 |
总结一下就是:
-
ModRM.r/m = 0100 或 1100 时,它寻址的是 SIB 字节,引导出 SIB 字节,交由 SIB 进行补充寻址。
- ModRM.mod = 00 & ModRM.r/m = 0101 或 1101 时,在 32 位下它是 32 位的 displacment 值,在 64 位下它是 [rip + disp32] 寻址。
- REX.B 可以扩展 ModRM.r/m 为 4 位: 0000 ~ 1111
4.1 Opcode和ModRM 结合确定一条指令
4.1.1 一个操作数的 Opcode 定位
操作数要么就是 registers,要么就是 memory,要么就是 Immediate 值。如果指令只有一个操作数。
(1)operand 是 register 的情况下
在只有 1 个寄存器操作数的情况下,非 Group 属性的 Opcode,则 ModRM 无用武之处。所以,在这种情冲下,寄存器操作数绝大部分是嵌在 Opcode 里面,它由 Opcode 的寄存器域指出。如常见的 inc ecx、dec ecx、push eax 等。除了上述嵌入 Opcode 情况外,如果 ModRM 用于寻址 1 个操作数,这条指令的 Opcode 必定是:Group 属性。 (2)如它是 Immediate 的话,它绝对是无 ModRM。直接将 Immediate 值嵌入指令编码里。
(3)如它是 memory 的话,它绝对是 Group 属性,需要 ModRM.reg 来配合定位。那为什么不能是直接 offset 呢,直接 offset 寻址留给最常用的,最有用的 Opcode,以免 Opcode 占位,浪费资源。
4.1.2 两个操作数的 Opcode 定位**
两个操作数大部分都需 ModRM 配合定位寻址。ModRM 提供的 2 个操作数寻址大有用武之地。
(1)2 个操作数中,其中 1 个是寄存器,另1个不是立即数的这种情况最直接简单,由 ModRM 的 reg 及 r/m 提供寻址。 若其中 1 个是 GPRs 另 1 个是 immediate 或 displacement 的情形下更简单,GPRs 则直接由 Opcode 提供寻址。 (2)2 个操作数中,没有寄存器的情形下,也就是要么是 memory,要么是 Immediate,它必然是个 Group 属性,reg 域提供 Opcode 的定位,r/m 提供内存寻址。Immediate 直接嵌入指令编码中。
4.1.2 三个操作数的 Opcode 定位**
三个操作数中有一个必定是 Immediate,在 AMD 的 SSE5 指令集推出之前,x86 平台是无法提供第 3 个非 Immediate 操作数的定位。 直至 AMD 的 SSE5 通过增加另一个描述操作数的字节来寻址第 3 个操作数。
5. SIB 补充寻址
SIB 是对 ModRM 寻址的一个补充:
-
ModRM 提供的是 registers 寻址、[register] 寻址(寄存器间接寻址)以及 [register + displacement](寄存器基址寻址)。
-
SIB 提供的是 [base + index * scale] 这种形式的寻址。即:基址 + 变址
同样,SIB 是可选的,前面已经介绍:SIB 字节由 ModRM.r/m = 100 引导出来,指令中命名用了 [base + index] 这种地址形式时,必须使用 SIB 进行编码。
回到前面举的这个例子:
(1)C7 这个 Opcode 是 Group 属性,需要 ModRM.reg 来配合定位。
(2)ModRM.mod = 10 以提供 [SIB + disp32] 的寻址
(3)ModRM.reg = 000 表明 Opcode 是个 mov Ev, Iz
(4)SIB 由 ModRM.r/m = 100 来引导出
(5)REX.W = 1 使用 64 位的 operand
5.1 SIB 的结构
表1: SIB 结构表
– | 位 | 描述 |
---|---|---|
SIB.scale | [7:6] | 提供 scale: 00 = 1, 01 = 2, 10 = 4, 11 = 8 |
SIB.index | [5:3] | 提供 index 寄存器 |
SIB.base | [2:0] | 提供 base 寄存器 |
上表所示 SIB 字节的组成部分为:scale-index-base 三个部分,按 2-3-3 的比例组成,在这整篇文档中的写法是:SIB.scale、SIB.index 以及 SIB.base
- SIB.scale 提供 index 寄存器乘数因子 scale
- SIB.index 提供 index 寄存器寻址。
- SIB.base 提供 base 寄存器寻址。
1.1、 用 SIB.index 寻址 index 寄存器
SIB.index 用来寻址 index 寄存器,可以使用 REX.X 进行扩展为 4 位编码
表2:SIB.index 寻址表
SIB.scale | SIB.index | 寻址模式 | |
---|---|---|---|
REX.X = 0 | REX.X = 1 | ||
00 | 000 | [rax + base] | [r8 + base] |
001 | [rcx + base] | [r9 + base] | |
010 | [rdx + base] | [r10 + base] | |
011 | [rbx + base] | [r11 + base] | |
100 | [base] | [r12 + base] | |
101 | [rbp + base] | [r13 + base] | |
110 | [rsi + base] | [r14 + base] | |
111 | [rdi + base] | [r15 + base] | |
01 | 000 | [rax * 2 + base] | [r8 * 2 + base] |
001 | [rcx * 2 + base] | [r9 * 2 + base] | |
010 | [rdx * 2 + base] | [r10 * 2 + base] | |
011 | [rbx * 2 + base] | [r11 * 2 + base] | |
100 | [base] | [r12 * 2 + base] | |
101 | [rbp * 2 + base] | [r13 * 2 + base] | |
110 | [rsi * 2 + base] | [r14 * 2 + base] | |
111 | [rdi * 2 + base] | [r15 * 2 + base] | |
10 | 000 | [rax * 4 + base] | [r8 * 4 + base] |
001 | [rcx * 4 + base] | [r9 * 4 + base] | |
010 | [rdx * 4 + base] | [r10 * 4 + base] | |
011 | [rbx * 4 + base] | [r11 * 4 + base] | |
100 | [base] | [r12 * 4 + base] | |
101 | [rbp * 4 + base] | [r13 * 4 + base] | |
110 | [rsi * 4 + base] | [r14 * 4 + base] | |
111 | [rdi * 4 + base] | [r15 * 4 + base] | |
11 | 000 | [rax * 8 + base] | [r8 * 8 + base] |
001 | [rcx * 8 + base] | [r9 * 8 + base] | |
010 | [rdx * 8 + base] | [r10 * 8 + base] | |
011 | [rbx * 8 + base] | [r11 * 8 + base] | |
100 | [base] | [r12 * 8 + base] | |
101 | [rbp * 8 + base] | [r13 * 8 + base] | |
110 | [rsi * 8 + base] | [r14 * 8 + base] | |
111 | [rdi * 8 + base] | [r15 * 8 + base] |
5.1 SIB.base 寻址 base 寄存器
SIB.base 用来寻址 base 寄存器,可以用 REX.B 扩展为 4 编码
表3: SIB.base 寻址表
REX.B | ModRM.mod | SIB.base | |||||||
---|---|---|---|---|---|---|---|---|---|
000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 | ||
0 | 00 | rax | rcx | rdx | rbx | rsp | disp32 | rsi | rdi |
01 | rbp+disp8 | ||||||||
10 | rbp+disp32 | ||||||||
1 | 00 | r8 | r9 | r10 | r11 | r12 | disp32 | r14 | r15 |
01 | r13+disp8 | ||||||||
10 | r13+disp32 |
这个表与上面的表1 SIB.index 表是紧密相关的,而且还受到 ModRM.mod 的影响
SIB 的使用须由 ModRM 引导出:[SIB]、[SIB + disp8] 以及 [SIB + disp32] 形式,
分别由 ModRM = 00-XXX-100、ModRM = 01-XXX-100 以及 ModRM = 10-XXX-100 引出。
Reference
【1】https://nju-projectn.github.io/i386-manual/appa.htm
【2】https://nju-projectn.github.io/ics-pa-gitbook/ics2020/i386-intro.html
【3】https://blog.csdn.net/xfcyhuang/article/details/6230542