您的位置:首页 > 其它

X86指令编码内幕 --- ModRM 与 SIB 设计上的 2 个原则

2011-03-25 04:28 561 查看


X86指令编码内幕 --- ModRM 与 SIB 设计上的 2 个原则

1、 rbp 作为 base 寄存器时,必须以 [base + disp] 形式存在

这种设计思想大概是基于:rbp 意为 stack base pointer,既然是 base pointer 那么它应要以 base 加上 offset 这种形式存在才合符它的意义。

基于这点,x86/x64 的编码上是没有 [rbp] 这个寻址模式存的,只有 [rbp + disp8] 和 [rbp + disp32] 这两种形式的寻址模式。

rbp 作为 base 寄存器,存在于 ModRM.r/m = 101 和 SIB.base = 101

(1)在 ModRM 寻址上的表现
ModRM.r/m 可以提供 [base] 寻址模式,即:ModRM.r/m = [rbp] 时

ModRM.r/m 编码表参见:ModRM.r/m 寻址表

★ 当 ModRM.mod = 00 & ModRM.r/m = 101 时

MocRM.mod = 00 时是对应着 [base] 这种寻址模式,而 ModRM.r/m = 101 时,按照编码规则,它应该对应着 [rbp]

但是在这个原则下,[rbp] 是不存在的,代替它的是 [disp32] 这个寻址模式,或者是 x64 体系新增的 [rip + disp32] 寻址模式。

★ 当 ModRM.mod = 01 & ModRM.r/m = 101 时

MocRM.mod = 01 时是对应着 [base + disp8] 这种寻址模式。

此时 ModRM.r/m = 101 时,并不违反规使则,它回到了正常的编码规则,即:它是 [rbp + disp8] 寻址模式。

★ 当 ModRM.mod = 10 & ModRM.r/m = 101 时

MocRM.mod = 10 时是对应着 [base + disp32] 这种寻址模式。

此时 ModRM.r/m = 101 时,并不违反规使则,它回到了正常的编码规则,即:它是 [rbp + disp32] 寻址模式。

(2)在 SIB 寻址上的表现
这和 ModRM 的情况一样,在 ModRM 寻址上 rbp 作为 base 寄存器时,和在 SIB 寻址上 rbp 作为 base 寄存器的情形都是一样的。

当 SIB.base = rbp(101)时, 它的编码结果和 ModRM.r/m = rbp(101)时一样的,都取决于 ModRM.mod

SIB.base 编码参见:SIB.base 寻址表

★ 当 ModRM.mod = 00 & SIB.base = 101 时

此时 SIB.base = [disp32]

SIB.base 按规则对应 [rbp] 寻址,在这个原则之下,[rbp] 寻址是不存在的,而以 [disp32] 寻址模式代替。

★ 当 ModRM.mod = 01 & SIB.base = 101 时

此时 SIB.base = [rbp + disp8]

这里按照编码规则是 [base + disp8] 这种寻址模式,并不违反规则。

★ 当 ModRM.mod = 10 & SIB.base = 101 时

此时 SIB.base = [rbp + disp32]

这里按照编码规则是 [base + disp32] 这种寻址模式,并不违反规则


2、 rsp 不能作为 index 寄存器,可以做为 base 寄存器

对于 [base + index * scale + disp] 这种寻址模式,如果 index 寄存器是 rsp 的话,这是不允许的。

那么,当 SIB.index = 100(rsp)时,会发生什么情况呢?

结果是:[base + index * scale + disp] ---> [base]

去掉 index,只剩下 base,在这种情况下,和 ModRM.r/m 的结果是一样的。

例1:寻址模式 [rax]
事实上,对于 [rax] 寻址,两种编码方式,分别是:仅使用 ModRM 寻址以及 ModRM + SIB 寻址

★ 仅使用 ModRM 寻址

这种编码方式是最常用的,绝大部分甚至说全部 assembler 都会编译为这种方式。

它的编码是:ModRM = 00-XXX-000

★ 使用 ModRM + SIB 寻址

这种编码方式,几乎不会有 assembler 会采用的,因为多了 1 个字节

最终编码是:ModRM = 00-XXX-100 SIB = 00-100-000

例2:实际的指令 mov rax, qword ptr [rax]

第 1 种编码结果是:48 8b 00(仅使用 ModRM 字节寻址)

第 2 种编码结果是:48 8b 04 20 (ModRM + SIB,其中:ModRM = 04,SIB = 20)

--------------------------------------------------------------------

这两种编码结果都是正确的,只是通常的 assembler 都是产生第 1 种编码结果,第 2 编码不会有 assembler 会使用的。

3、 [rbp] 寻址的实现
由于 [rbp] 寻址在编码上是不存在的,那么 assembler 会做些变通处理。

实际的编码为:[rbp] ---> [rbp + 0x00] 或者 [rbp + 0x00000000]

例1: 指令 mov rax, qword ptr [rbp] 它的编码是多少?
如上所述,[rbp] 会变成 [rbp + 0x00] 或者 [rbp + 0x00000000]

下面是使用 2 种版本的编码结果:

(1)仅使用 ModRM 寻址,编码结果是: 48 8b 45 00 (使用 [rbp + disp8] 方式)

或者是: 48 8b 85 00 00 00 00 (使用 [rbp + disp32] 方式)

(2)使用 ModRM + SIB,编码结果是: 48 8b 44 25 00 (使用 SIB 的 [rbp + disp8] 方式)

或者是: 48 8b 84 25 00 00 00 00 (使用 SIB 的 [rbp + disp32] 方式)

4、 [rsp] 寻址的实现
[rsp] 寻址只能通过引导出 SIB,然后在 SIB.base = rsp 来实现。

SIB 的 3 种方式为:[SIB]、[SIB + disp8] 以及 [SIB + disp32]

例2: 指令 mov rax, qword ptr [rsp] 它的编码是多少?
通过 ModRM = 00-XXX-100 ([SIB]) 引导出 SIB 字节。

或者: ModRM = 01-XXX-100 ([SIB + disp8]) 引出 SIB 字节

或者: ModRM = 10-XXX-100 ([SIB + disp32])引出 SIB 字节

然后 SIB = 00-100-100 (SIB.base = rsp)

最终的编码结果是: 48 8b 04 24 (SIB.base = rsp)

当然也可以这样: 48 8b 44 24 00 (使用 [SIB + disp8] 方式)

甚至: 48 8b 84 24 00 00 00 00 (使用 [SIB + disp32] 方式)

5、最后结合 ModRM 与 SIB 举例子

例1:指令 mov rax, qword [r13 + rbp] 编码是多少?
像这样的指令可以有 2 种形式,分别为: base = r13,index = rbp 以及 base = rbp,index = r13

(1)设 base = r13 而 index = rbp 时,编码是多少?

它的编码为:49 8b 44 2d 00

(2)设 base = rbp 而 r13 = index 时,编码是多少?

它的编码是:4a 8b 44 2d 00

2:指令 mov rax, qword [rbp + r8 * 8] 编码是多少?
base 是 rbp,这里使用的是: [rbp + 0x00],当然也可使用 [rbp + 0x00000000]
★ 使用 base = [rbp + 0x00] 编码时,它的 encodes 是:48 8b 44 c5 00

★ 使用 base = [rbp + 0x00000000] 时,它的 encodes 是:48 8b 84 c5 00 00 00 00

例3:指令 mov rax, qword [rsp + rbp * 8 + 0x0c] 编码是多少?
base 是 rsp, 这里使用 [SIB + disp8],当然也可以使用 [SIB + disp32]

★ 使用 base = [SIB + 0x0c] 编码时,它的 encodes 是:48 8b 44 ce 0c

★ 使用 base = [SIB + 0x0000000c] 时,它的 encodes 是:4a 8b 84 ce 05 00 00 00
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: