7. displacement 值


上一页 返回目录 下一页

 

  displacement 是 ModRM 地址寻址里的一部分,displacement 为 base 或 index 提供一个 offset 值。

  因此:在指令的编码中必须要提供 ModRM 字节,需要的时候还要提供 SIB 字节。

 

1、关于 displacement 的看法

(1)基于 ModRM 字节寻址的情况下,displacement 不是指令中的 immediate 部分

  例如指令:mov edx, dword ptr [0x08040400]

  它的指令编码是:8b 15 00 04 04 08

  这条指令的 displacement 虽然是嵌在 encode 中,但它不属于 immediate 的概念,它是需要通过 ModRM.r/m 的寻址。

 

(2)有一种情况下,绝对地址不需要 ModRM 字节进行寻址,这个地址值是 immediate 部分

指令:mov eax, dword ptr [0x08040400]

它的指令编码可以译为:a1 00 04 04 08 (当绝对地址与 eax/rax 寄存器之间的寻址,它可以使用这种编码方式)

在这种情况下,它不需要 ModRM 字节进行寻址,这个地址值是 immediate 概念。

当然,这条指令也可以译为:8b 05 00 04 04 08 (通过 ModRM 进行寻址),此时它就是 displacement 部分。

 

 

2、提供 displacement 的几个方式

由 ModRM.mod 来控制 displacement:

(1)提供绝对地址方式

 
ModRM
SIB
寻址
说明
mod
reg
r/m
scale
index
base
1
00
XXX
101
---
ModRM = [disp32]
非 64 位模式下,只需 ModRM 字节寻址
2
00
XXX
100
XX
100
101
ModRM + SIB = [disp32]
ModRM 字节配合 SIB 字节寻址

上表是提供绝对地址寻址的两种方式。表格中的 XX/XXX 表示可以为任意值。

注意方式 1 中,提供的 [disp32] 是在 非 64 位模式下。

 

(2)为 base 提供一个 offset 值

 
ModRM
SIB
寻址
说明
mod
reg
r/m
scale
index
base
1
01
XXX
≠100
---
ModRM = [base + disp8]
给 base 提供一个 8 位的 displacement
2
10
XXX
≠100
---
ModRM = [base + disp32]
给 base 提供一个 32 位的 displacement
3
01
XXX
100
XX
100
101
ModRM + SIB = [base + disp8]
ModRM 字节配合 SIB 字节寻址
4
10
XXX
100
XX
100
101
ModRM + SIB = [base + disp32]
ModRM 字节配合 SIB 字节寻址

可以提供 8 位和 32 位的 displacement 值。

表格中的 XX/XXX 表示该项为任意值,8 位和 32 位的 displacemnet 各有 2 种编码方式。

 

 

(3)为 index 提供一个 offset 值

 
ModRM
SIB
寻址
说明
mod
reg
r/m
scale
index
base
1
00
XXX
100
XX
≠100
101
ModRM + SIB = [index * scale + disp32]
ModRM 字节配合 SIB 字节寻址

ModRM 配合 SIB 寻址,这里 SIB.index ≠100 时,提供任意的 index 寄存器(除了 rsp 寄存器),可以为 index 提供一个 32 位的 displacement 值。

仅在这一种情况下才允许 index + base 寻址。

看下面的指令:

mov rax, qword ptr [rcx * 8 + 0x0c]

它的 encode 是: 48 8b 04 cd 0c 00 00 00

它使用的 [base + index * 8] 寻址模式,在 SIB.base = 101(即:base = rbp 的情况下,base 此时为 disp32

上面的有几种寻址方式,是依据 x32/x64 的两大原则,详见:ModRM 与 SIB 设计上的 2 个原则

 

(4)给 rip 提供一个 displacement 值

仅在 64 位模式下,可以为 rip 提供一个 displacement 值

 
ModRM
SIB
寻址
说明
mod
reg
r/m
scale
index
base
1
00
XXX
101
---
ModRM = [rip + disp32]
仅在 64 位模式下,可以提供 [rip + disp32]

当在 64 位模式下,ModRM = 00-XXX-101 是 [rip + disp32] 寻址,这是 x64 体系中新增的一个寻址模式。

这种寻址模式很容易就得出 rip 值,如下指令:

lea rax, [rip]

编译器会译出:8d 05 00 00 00 00 -----> lea rax, [rip + 0x00000000]

 

 

3、 displacement 的符号位

 大部分情况下,displacement 是 signed(符号数),在绝对地址情况下,它是 unsigned(无符号数)

(1)displacement 是 signed(符号数)

  无论是为 base 还 index 提供一个 offset 值,此时 displacement 都是 singed(符号数),那么将会按 singed 的计算方式,计算结果。

  在这种情况下,当 displacement 是 disp8 时,它会被符号扩展到 address size(取决于 effective address size)


关于 effective address size 的详见:default(缺省)与 effective(有效)

 

(2) displacement 是 unsigned(无符号数)

  当 displacement 是绝对地址是,它是 unsigned(无符号数)。

  例如: mov edx, dword ptr [0x08040400] 此时 displacement 是一个 unsigned(无符号数)

 

 

 

4、displacement 的长度

在 16 位下 displacement 分为 8 位和 16 位,在 32 位下分为 8 位和 32 位,而在 64 位下同样只有 8 位和 32 位。

4.1、 displacement 的 signed-extended(符号扩展)

虽然有 8 位的 displacement,实际上,都会被 processor 进行 signed-extended 符号扩展到 address size

当 displacement size 是小于 address size 的,这个 displacement 就会被 singed-extended 到 address size

这个 address size 是指令当前的 address size,它取决于 effective address size。

★ 没有经过 address size override 的,address size 就是它的 default address size

★ 经过 address size override 后,address size 就等于 override 的 address size


关于 effective address size 的详见:default(缺省)与 effective(有效)

 

4.2、 x64 体系的 64 位下的 displacement

  64 位的 default address size 是 64 位,在没有 address size override 的,无论 disp8 还是 disp32 都会被扩展到 64 位地址上。


这里就产生了一些疑问,在 x86/x64 的指令格式中,displacement 是没有 64 位的。

★ 到度有没有 64 位的 displacement 呢?

★ 没有的话,怎么使用 64 位绝对地址呢?

★ 有的话,什么情况下才会出现 64 位的 displacement 呢?

  在 x64 体系的的编码中,确实没有 64 位 displacement 这回事,但是并不表示 64 位下不能使用 64 位的绝对地址。 这个 64 位的绝对地址并不是 displacement 的意思。


例子: mov rax, qword ptr [0xffff800008040400]

  这条指令是正确的,而且它使用了 64 位的绝对地址。

  它的 encode 是:48 a1 00 04 04 08 00 08 ff ff

  这条指令的 Opcode 是 a1,指令形式为:MOV rAX, Ov

  second operand 是 O 表示它将是一个直接的地址形式,这个 operand 是允许使用 64 位的绝对地址,而不需要 ModRM 寻址。

  在这里地址值 [0xffff800008040400] 它是以 immedeate 值形式嵌在 encode 中,它属于 immediate 部分,而非 displacement 值。

同样,指令:mov qword ptr [0xffff800008040400], rax 也是正确的

  它的 encode 是:48 a3 00 04 04 08 00 08 ff ff

 

另一个例子是:mov rcx, qword ptr [0xffff800008040400]

  这条指令是错误的,它不可能产生 encode,opcode a1 是仅仅对 rax 寄存器可用,因此:只有 rax 寄存器才能使用 64 位的绝对地址值。

 

4.3、 Opcode a1 和 a3 可以使用 64 位绝对地址的本质

  这两个 Opcode 的 operand 嵌入 encode 中,它不依赖于 ModRM 寻址。 在这种情况下,可以设计使用 64 位的地址值(immediate)。

因此:

  设计使用 64 位地址的前提条件必须是: operand 不依赖于 ModRM 寻址,换句说说:operand 是嵌在 Opcode 里的。

 

4.4、 不能使用 64 位 displacement 的本质

  我们来看一看,是什么原因限制了 64 位 displacement 的使用。

例子: mov qword ptr [rax + rcx * 8 + 0x11223344], 0x12345678

  这个例子是前面多次提到过,它的 encode 是:48 c7 84 c8 44 33 22 11 78 56 34 12 (共 12 个 bytes)

  可以看出,限制 64 位 displacement 使用的原因就是:指令长度的限制

  由于 x86/x64 的指令长度限制 15 bytes, 如果上面这条指令可以使用 64 位 displacement 的话,指令长度超过了 15 bytes。

因此:

  使用 64 位 displacement 第 2 个前提条件是:指令长度不能超过 15 bytes

 

4.5、 operand 类型为 O (直接地址值,不依赖于 ModRM 寻址)的最终设计前提就是前面所说的两个条件:

operand 不依赖于 ModRM 寻址,换句说说:operand 是嵌在 Opcode 里的。

指令长度不能超过 15 bytes

 

 

那么:能不能为 x64 体系扩展指令格式为更长的格式呢?

  显然,x64 体系设计者们没有采取这种方式,出于兼容的大提前下,是不可能有这种考虑的。

 

上一页 返回目录 下一页


mik(deng zhi)写于 2008-11-26 15:40