1 机器码 的结构 {
机器码 有6 个域,分别是:
1. Prefixes (这个域中Prefixes 的顺序可以被打乱)
2. OpCode (是必须的)
3. Byte ModRM
4. Byte SIB
5. Diaplacement
6. imm Operand
其中:
Code 域是必须的,其他域可选。6 个域的顺序绝对不能乱(出现的域,编号小的必须在编号大的之前)。
}
2 一条指令的开始和结束:
2.1 开始:CPU 查看EIP,EIP 指向的地址被认为是一条指令的第一个字节。
2.2 结束:CPU 解码机器码(多半是OpCode),计算指令该在哪里结束。如果该指令不是控制类型的指令(改变EIP 的指令),那么指令结束的下一个字节将被认为是下一条指令的开始。
3 Prefixes:
性质:
它是唯一在Code 域之前的域,包含一个或多个Prefixes,每一个Prefixes 只有一个byte。如果Prefixes 无法对其后的OpCode 生效,那么该Prefixes 将会被忽略(例如 rep inc eax中,rep 将会被忽略)。
3.1Prefixes 0x66:用于切换默认操作数的大小。默认操作数如果是 32位,那么Prefixes 0x66 将会切换到16 位操作数。所以:在默认操作数是32 位的OS 上,任何操作word 的指令都较操作dword 的指令长一个字节(Prefixes 0x66),并且会多花一个时钟周期去执行。这里的默认操作数由描述符的D/B 位决定:当TYPE 属于 (0x8-0xf] 时段为CS,此时为D 位,代表Default operand size,置位表示默认值是32 位地址(Prefixes 0x67) 和 32 位或8 位操作数(Prefixes 0x66),复位表示默认值是16 位地址 和 16 位或8 位立即数。
3.2 Prefixes 0x67:用于切换默认地址的大小。和Prefixes 0x66 类似。
3.3 Prefixes 0xF2、0xF3:Rep Prefixes。其中0xF2 表示Repne (0 == ecx || 1 == ZF),0xF3 表示Rep/Repe (0 == ecx || 0 == ZF)。如果一条指令对ZF 没有影响,那么0xF3 表示Rep,否则表示Repe。当然对于不改变ZF 的串指令,0xF2 和0xF3 是一样的。
3.4 Prefixes 0x2E、0x3E、0x26、0x36、0x64、0x65 {
这些Prefixes 人称Segment Override Prefixes,用于改变默认段。
其中:
Prefixes | 对应的段 | 该段的默认指令组 |
0x2E | CS | EIP 寄存器 |
0x3E | DS | 串操作指令的源操作数在DS |
0x26 | ES | 目的操作数在内存单元的串指令 |
0x36 | SS | 堆栈操作指令 |
0x64 | FS | |
0x65 | GS |
3.5 Prefixes 0xF0 :锁地址总线
PS: 1 Win32 中CS、DS、SS 只是用户模式程序中段的别名,你可以通过上述三个寄存器中阿任意一个来寻址数据。
2 改变目的操作数的值是不允许的,目的操作数无法通过Prefixes 来改变。(例如0x65A5 代表movs [dword es:edi],[dword gs:edi])
}
4 Code 域的种类:
x86/x64 平台上,大于1 字节的机器码是通过escape opcode + opcode 形式表示的。
Code 域字节数 | escape opcode |
1 | |
2 | 0x0F |
3 | 0x0F3A/0x0F3B |
当有一部分操作数是寄存器或者立即数时,不会用到ModRM寻址,前者直接嵌入到OpCode,后者直接嵌入指令中。
ModRM共有三个部分,格式是2:3:3,三个部分人称ModRM.mod、ModRM.reg、ModRM.r/m。
--
|
位
|
描述
|
ModRM.mod
| b6&b7 | 提供寻址模式 |
ModRM.reg | b3-b5 | 指定寄存器 |
ModRM.r/m | b0-b2 | 提供寄存器或内存寻址 |
5.1 ModRM.mod 提供寻址的模式。这个模式以displacement 值作区别的,当0b11 == ModRM.mod 时,它提供寄存器 寻址。
ModRM.mod
|
寻址模式
|
描述
|
00
|
[base]
| 提供 [base] 形式的 memory 寻址 |
01
|
[base + disp8]
| 提供 [base + disp8] 形式的 memory 寻址 |
10
|
[base + disp32]
| 提供 [base + disp32] 形式的 memory 寻址 |
11
|
register
| 提供 register 寻址。 |
5.2.1 对应8 个全寄存器的情况:
000 | EAX |
001 | ECX |
010 | EDX |
011 | EBX |
100 | ESP |
101 | EBP |
110 | ESI |
111 | EDI |
000 | AL |
001 | CL |
010 | DL |
011 | BL |
100 | AH |
101 | CH |
110 | DH |
111 | BH |
ModRM.mod
|
ModRM.r/m
|
ModRM.r/m 寻址
|
00
|
000
|
[eax]
|
001
|
[ecx]
| |
010
| [edx] | |
011
| [ebx] | |
100
|
[SIB]
| |
101
| [disp32] | |
110
|
[esi]
| |
111
|
[edi]
| |
01
|
000
|
[eax + disp8]
|
001
|
[ecx + disp8]
| |
010
|
[edx + disp8]
| |
011
|
[ebx + disp8]
| |
100
|
[SIB + disp8]
| |
101
|
[ebp + disp8]
| |
110
|
[esi + disp8]
| |
111
|
[edi + disp8]
| |
10
|
000
|
[eax + disp32]
|
001
|
[ecx + disp32]
| |
010
|
[ebx + disp32]
| |
011
|
[edx + disp32]
| |
100
|
[SIB + disp32]
| |
101
|
[ebp + disp32]
| |
110
|
[esi + disp32]
| |
111
|
[edi + disp32]
| |
11
|
000
|
eax
|
001
|
ecx
| |
010
|
edx
| |
011
|
ebx
| |
100
|
esp
| |
101
|
ebp
| |
110
|
esi
| |
111
|
edi
|
注意:A 当100== ModRM.r/m 时,采用的其实是SIB 寻址,地址由SIB 补充。SIB 中对esp 进行补充寻址有一条重要的规则:esp 不能做index 而只能做base。
B 当101 == ModRM.r/m 时,采用的其实是[disp32] 的寻址。但是在encode 层面,这种情况其实是不存在的。
6 SIB:
ModRM 提供的是 registers 寻址、[register] 寻址(寄存器间接寻址)以及 [register + displacement](寄存器基址寻址),SIB 提供的是 [base + index * scale] 这种形式的寻址。即:基址 + 变址。
SIB 的结构和ModRM 类似,同样是2:3:3 结构,分别为SIB.base、SIB.index、SIB.scale。
--
|
位
|
描述
|
SIB.scale
|
b6&b7
| 提供 scale |
SIB.index
| b3-b5 | 提供 index 寄存器 |
SIB.base
| b0-b2 | 提供 base 寄存器 |
6.1SIB.scale:可以为 0b00、0b01、0b10、0b11。其中0bnn 代表2^(0bnn),例如SIB.scale 为0b10 便代表4。
6.2 SIB.index:可以用来寻址index 寄存器,寻址模式如下:
SIB.index
|
寻址模式
|
000
| [eax * 2^(SIB.Scale) + base] |
001
| [ecx * 2^(SIB.Scale) + base] |
010
| [edx* 2^(SIB.Scale) + base] |
011
| [ebx* 2^(SIB.Scale) + base] |
100
| [base] |
101
| [ebp* 2^(SIB.Scale) + base] |
110
| [esi* 2^(SIB.Scale) + base] |
111
| [edi* 2^(SIB.Scale) + base] |
6.3SIB.base:可以用来寻址base 寄存器,寻址模式如下:
ModRM.mod
|
SIB.base
| |||||||
000
|
001
|
010
|
011
|
100
|
101
|
110
|
111
| |
00
|
eax
|
ecx
|
edx
|
ebx
|
esp
|
disp32
|
esi
|
edi
|
01
|
ebp+disp8
| |||||||
10
|
ebp+disp32
|
SIB 形式 | ModRM 引出的形式 |
[SIB] | 00:xxx:100 |
[SIB + disp8] | 01:xxx:100 |
[SIB + disp32] | 10:xxx:100 |
B ModRM 与 SIB 设计上的 2 个原则(上图已经用红色区域标出):
(1)ebp 作为 base 寄存器时,必须以 [ebp + disp] 这种形式存在
(2)esp 不能作为 index 寄存器,可以做为 base 寄存器
7 Displacement:
一条相同的指令可以被不同的机器码表示,运行的效果都相同,主要有以下几点原因:
A OpCode 的多样性
B ModRM 寻址能产生和其导出SIB 寻址相同的效果
C displacement 的长度不同,32 位下可以是2 byte 或者8 byte。