5. ModRM 寻址模式
| 
       Opcode 对指令提供操作码,ModRM 最主要作用是对指令的 operands 提供寻址,另一个作用是对 Opcode 进行补充,而 SIB 则是对 ModRM 进行补充寻址  | 
    
  回到前面举的这个例子:  
  
REX prefix   | 
    Opcode  | 
    ModRM  | 
    SIB  | 
    displacement  | 
    immediate  | 
  ||||||||
4  | 
    W  | 
    R  | 
    X  | 
    B  | 
    mod  | 
    reg  | 
    r/m  | 
    scale  | 
    index  | 
    base  | 
  |||
0100  | 
    1  | 
    0  | 
    0  | 
    0  | 
    C7  | 
    10  | 
    000  | 
    100  | 
    11  | 
    001  | 
    000  | 
    44 33 22 11   | 
    78 56 34 12   | 
  
(1)C7 这个 Opcode 是 Group 属性,需要 ModRM.reg 来配合定位。
(2)ModRM.mod = 10 结合 ModRM.r/m = 100 提供 [SIB + disp32] 的寻址
(3)ModRM.reg = 000 表明 Opcode 是个 mov Ev, Iz
(4)SIB 由 ModRM.r/m = 100 来引导出
(5)REX.W = 1 使用 64 位的 operand
  1、ModRM 的结构
--  | 
    位  | 
    描述  | 
  
ModRM.mod  | 
    [7:6]  | 
    提供寻址模式: 11 = register 00, 01, 10 = memory | 
ModRM.reg  | 
    [5:3]  | 
    提供 register 或者对 Opcode 进行补充 | 
ModRM.r/m  | 
    [2:0]  | 
    提供 register 或者 memory 依赖于 ModRM.mod | 
  上表所示 ModRM 字节的组成部分为:mod-reg-r/m 三个部分,按 2-3-3 的比例组成,在这整篇文档中的写法是:ModRM.mod、ModRM.reg 以及 ModRM.r/m。
★ ModRM.mod 提供寻址的模式,这个模式以 displacement 值作区别的。当 ModRM.mod = 11 时,它提供 register 寻址。 
★ ModRM.reg 提供寄存器寻址,reg 表示寄存器 ID 值,或者对 Group 属性的 Opcode 进行补充。
★ ModRM.r/m 提供 register 寻址或 memory 寻址,取决于 ModRM.mod 值:ModRM.mod = 11 时,ModRM.r/m 提供寄存器的 ID 值。
  
  
  ModRM.mod  | 
     寻址模式  | 
     描述  | 
  
00  | 
     [base]  | 
    提供 [base] 形式的 memory 寻址 | 
01  | 
     [base + disp8]  | 
    提供 [base + disp8] 形式的 memory 寻址 | 
10  | 
     [base + disp32]   | 
    提供 [base + disp32] 形式的 memory 寻址 | 
11  | 
     register  | 
    提供 register 寻址。 | 
  这个 ID 值可以被 REX.R 扩展为 4 位: 0000 ~ 1111(对应于 RAX 到 R15 寄存器)。 
详见:寄存器编码表
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
按照 ModRM 编码规则,当 ModRM.r/m = 100,ModRM.r/m 应该是对应于 [rsp] 寻址。
事实上并非如此,ModRM.r/m 对应的是 SIB 寻址,由此而引导出 SIB 字节。指令系统设计者选择在 [rsp] 位置上用 SIB 进行替代。
这是因为:
★ 必须要有编码对应于 SIB 字节。
★ 用 SIB 代替 [rsp] 或许因为 [rsp] 相比其它的寻址并不那么常用。
2.1、那么怎样实现 [rsp] 寻址的编码?
既然在 ModRM 上无法满足 [rsp] 的寻址,那么只好在 SIB 里实现 [rsp] 的寻址。
在 SIB 里实现 [rsp] 寻址,是根据一个重要的原则: rsp 寄存器不能做为 index 寄存器,只能做 base 寄存器。
具体 SIB 的实现细节,详见:[rsp] 寻址的实现
同样情况下,按照 ModRM 编码规则,ModRM.r/m = 101 时,应该对应于 [rbp] 寻址。
事实上并非如此:当 ModRM.mod = 00 时,ModRM.r/m = 101 它对应的是 [disp32] 的寻址,在 64 位下,它是 [rip + disp32]。
指令系统的设计者们在 ModRM.r/m = 101 这个地方又进行了变通。
3.1、 那么怎样实现 [rbp] 寻址的编码呢?
在 [rbp] 寻址的实现上,又遵循另一个重要原则:rbp 作为 base 寄存器时,它必须以 [base + disp] 这种形式存在。
这个原则是建立在:rbp 意为 stack base pointer(基址指针),从语义上讲 base pointer 应该要加一个偏移量(displacement)
因此:[rbp] 这种形式在 encode 上是不存在的。
  但是在 assembly(汇编语句)层面上是正确的,即:mov qword ptr [rbp], rax 是正确的语句。
具体 [rbp] 的实现,详见:[rbp] 寻址的实现
    
  16 位寻址与 32 位寻址有较大的差异,16 位下是不支持 [base + index * scale + disp] 这种寻址模式的,这样在编码序列里就无需提供 SIB   字节了。
  
    即:在 16 位下是无 SIB 字节的。 
注:
    16 位的 ModRM 寻址支持的是基址和变址寄存器间接寻址和 基址+变址寻址模式。基址寄存器 2 个:就是   bx 和 bp。变址寄存器也是 2 个:就是 si 和 di。 
基于上述设计,基址+变址寻址的组合只有 4 个,也就是:[bx+si]、[bx+di]、[bp+si] 以及 [bp+di]。
ModRM.mod  | 
      ModRM.r/m  | 
      ModRM.r/m 寻址   | 
    
00  | 
      000  | 
      [bx+si]  | 
    
001  | 
      [bx+di]  | 
    |
010  | 
      [bp+si]  | 
    |
011  | 
      [bp+di]  | 
    |
100  | 
      [si]  | 
    |
101  | 
      [di]  | 
    |
110  | 
      [disp16]  | 
    |
111  | 
      [bx]  | 
    |
01  | 
      000  | 
      [bx+si+disp8]  | 
    
001  | 
      [bx+di+disp8]  | 
    |
010  | 
      [bp+si+disp8]  | 
    |
011  | 
      [bp+di+disp8]  | 
    |
100  | 
      [si+disp8]  | 
    |
101  | 
      [di+disp8]  | 
    |
110  | 
      [bp+disp8]  | 
    |
111  | 
      [bx+disp8]  | 
    |
10  | 
      000  | 
      [bx+si+disp16]  | 
    
001  | 
      [bx+di+disp16]  | 
    |
010  | 
      [bp+si+disp16]  | 
    |
011  | 
      [bp+di+disp16]  | 
    |
100  | 
      [si+disp16]  | 
    |
101  | 
      [di+disp16]  | 
    |
110  | 
      [bp+disp16]  | 
    |
111  | 
      [bx+disp16]  | 
    |
11  | 
      000  | 
      ax  | 
    
001  | 
      cx  | 
    |
010  | 
      dx  | 
    |
011  | 
      bx  | 
    |
100  | 
      sp  | 
    |
101  | 
      bp  | 
    |
110  | 
      si  | 
    |
111  | 
      di  | 
    
    
    
    
    
  
  寄存器的 ID 取值为:0000 ~ 1111。由 REX.R 以及 REX.B   位进行扩展访问。
  
    
    
    6、结合 Opcode 来看寻址模式及 Opcode 的定位
    
  Opcode 定义指令的执行码,用于执行什么操作,对于操作数寻址上,Opcode 结合 ModRM 来定义操作数,这是一个经过反复琢磨推敲的过程,而最终又影响到 Opcode   的定位。
    
    
    6.1、 一个操作数的 Opcode   定位
    
    操作数要么就是 registers,要么就是 memory,要么就是 Immediate   值。如果指令只有一个操作数。
  
(1)operand 是 register 的情况下
  
| 
       除了上述嵌入 Opcode 情况外,如果 ModRM 用于寻址 1 个操作数,这条指令的 Opcode 必定是:Group 属性  | 
    
| 前面已提过: Opcode 的分组是按 Operands 属性进行的。即:这一组 Opcode 拥有相同类型的 Operands。 这个类型的 Operands 主要是单个内存操作数或单个寄存器操作数而非嵌入 Opcode 中。  | 
        
  
  
mik 写于 2008-11-26 15:40