x86指令编码简述(机器码)
reg 表示寄存器方式,在不包括立即数的双操作数指令的情况下,规定必须有一个操作数在寄存器中,该寄存器由 reg 字段指定,并与操作码字节中的 w 位相组合确定的寄存器。(除了操作码必须外,其它字段是可选的)(操作码字段的位 0 用于选择 8 位或 16 位寄存器:1 表示 16 位寄存器,0 表示 8 位寄存器,位 0 就是 w ,在 8 位的最后啊!(Mod 在橙色块,Reg 在上面绿色块,R
机器码的格式结构:
一般的 x86 机器指令格式,包含了一个指令前缀字节、操作码、Mod R/M 字节、伸缩索引字节(SIB)、地址位移和立即数。指令按小端顺序存放,因此前缀字节位于指令的起始地址(基本遇不到)。
每条指令都必须要有一个操作码,而其他字段则是可选的。少数指令包含了全部字段,平均来看,绝大多数指令都有 2 个或 3 个字节。

指令字段解析:
1):指令前缀覆盖默认操作数大小。(基本遇不到)
2):操作码指定指令的特定变体,比如按照使用的参数(寄存器|操作数)类型,指令 ADD 有 9 种不同的操作码。
(具体操作码看参考手册)
3):Mod R/M 字段指定寻址模式和操作数,符号 “R/M” (register/memory) 代表的是寄存器和模式。
4):伸缩索引字节(scale index byte, SIB)用于计算数组索引偏移量。
5):地址位移字段保存了操作数的偏移量,在 “基址-偏移量” 或 “基址-变址-偏移量” 寻址模式中,该字段还可以与 “基址或变址寄存器” 相加。
6):立即数字段保存了常量操作数。
操作码的组成:在多数操作码中,常使用某些位来指示某些信息,下面列举出部分位及其含义:
(1:在参考手册 opcodes.html 的 Opcode 列中已经不需要考虑 d 和 s 了(定死了),但还是理解一下)
(2:上面操作码组成中只列出了 d、s、w,还有很多其它的如 rrr、sss 等,具体看操作码手册附录)
|_____________OP_______________|__d__|__w__|
|_____________OP_______________|__s__|__w__| <--此格式用于立即寻址方式
w (word) 值表示紧跟的操作数的大小类型:
w=1 时 对字来操作(如果是寄存器的话就是 16 位寄存器)
w=0 时 对字节来操作(如果是寄存器的话就是 8 位寄存器)
d 值在双操作数指令中才有效:(两个都是寄存器时以目的寄存器为准,不包括立即数的双操作数下)
d=1 时 有且只有一个寄存器用于目的操作数
d=0 时 有且只有一个寄存器用于源操作数
s 值只要有立即数存在就使用:
s=1 时 立即数为 8 位,但要求扩展成 16 位数
s=0 时 当指令作字节操作/有 16 位立即数
Mod R/M 字节标识操作数寻址方式:(不包括立即数的双操作数指令的情况下)
| mod | reg | r/m |
|_____|_____|_____|_____|_____|_____|_____|_____|
reg 指定寄存器编号,在不包括立即数的双操作数指令的情况下,规定必须有一个操作数在寄存器中。如果只有一个寄存器,则该寄存器由 reg 字段指定编号。如果两个操作数都是寄存器,则以目的寄存器为准。并与操作码字节中的 w 位相组合进一步确定寄存器大小类型。(reg 的 rrr 确定 8 个通用寄存器编号,操作码的末尾 w 位确定寄存器的大小)
Mod 值指定操作数的寻址模式:
|
Mod(oo) |
位移 |
|
00 |
如果 mmm = 110,则操作码后面跟 16 位偏移 |
|
01 |
操作码后面是一个 8 位有符号的偏移 |
|
10 |
操作码后面是一个 16 位有符号的偏移 |
|
11 |
R/M (mmm)字段包含的是寄存器编号 |
rrr W=0 W=1 reg32
- 000 : AL : AX : EAX
- 001 : CL : CX : ECX
- 010 : DL : DX : EDX
- 011 : BL : BX : EBX
- 100 : AH : SP : ESP
- 101 : CH : BP : EBP
- 110 : DH : SI : ESI
- 111 : BH : DI : EDI
mmm : Function
- 000 : DS:[BX+SI]
- 001 : DS:[BX+DI]
- 010 : SS:[BP+SI]
- 011 : SS:[BP+DI]
- 100 : DS:[SI]
- 101 : DS:[DI]
- 110 : SS:[BP]
- 111 : DS:[BX]
sss : Segment Register
- 000 : ES
- 001 : CS
- 010 : SS
- 011 : DS
- 100 : FS (Only 386+)
- 101 : GS (Only 386+)
Mod R/M 字节与内存寻址模式探究:
如果 Mod R/M 字节只用于标识寄存器操作数(mod=11),那么 Intel 指令编码就会相对简单。实际上 Intel 汇编语言有着各种各样的内存寻址模式,这就使得 Mod R/M 字节编码相当复杂。
Mod R/M 字节可以指定 256 个不同组合的操作数,下表只列岀了 mod 字段 为 00 时的 Mod R/M 字节的值:
(Mod 在橙色块,Reg 在上面绿色块,R/M 在紫色块,黄色块是总的加起来的 Mod R/M 字节值,蓝色块是要操作的 R/M 字段对应的源操作数。根据 Mod R/M 字节内部结构,阅读顺序是 mod—>reg—>r/m)
|
字节 |
AL |
CL |
DL |
BL |
AH |
CH |
DH |
BH |
||
|
字 |
AX |
CX |
DX |
BX |
SP |
BP |
SI |
DI |
||
|
寄存器ID |
000 |
001 |
010 |
011 |
100 |
101 |
110 |
111 |
||
|
Mod |
R/M |
Mod R/M 值 |
有效地址 |
|||||||
|
00 |
000 |
00 |
08 |
10 |
18 |
20 |
28 |
30 |
38 |
[BX+SI] |
|
001 |
01 |
09 |
11 |
19 |
21 |
29 |
31 |
39 |
[BX+DI] |
|
|
010 |
02 |
0A |
12 |
1A |
22 |
2A |
32 |
3A |
[BP+SI] |
|
|
011 |
03 |
0B |
13 |
1B |
23 |
2B |
33 |
3B |
[BP+DI] |
|
|
100 |
04 |
0C |
14 |
1C |
24 |
2C |
34 |
3C |
[SI] |
|
|
101 |
05 |
0D |
15 |
1D |
25 |
2D |
35 |
3D |
[DI] |
|
|
110 |
06 |
0E |
16 |
1E |
26 |
2E |
36 |
3E |
16 位偏移量 |
|
|
111 |
07 |
0F |
17 |
1F |
27 |
2F |
37 |
3F |
[BX] |
|
Mod R/M 编码解析:
mod 字段指定寻址模式的集合,比如 mod=00 时有 8 种可能的 R/M 数值(000b〜111b),上表的 “有效地址栏” 指定了对应源操作数类型。
举例编码 MOV AX, [Si]:
根据上表 “有效地址栏” 可得 Mod 位为 00,R/M 位为 100,AX 的寄存器编号为 000,因此完整的 Mod R/M 字节为 00 000 100。(即 04h)
|
mod |
reg |
r/m |
|
00 |
000 |
100 |
附录一:32 位寻址模式
|
oo |
mmm |
rrr |
Description |
|
00 |
000 |
DS:[EAX] |
|
|
00 |
001 |
DS:[ECX] |
|
|
00 |
010 |
DS:[EDX] |
|
|
00 |
011 |
DS:[EBX] |
|
|
00 |
100 |
000 |
DS:[EAX+scaled_index] |
|
00 |
100 |
001 |
DS:[ECX+scaled_index] |
|
00 |
100 |
010 |
DS:[EDX+scaled_index] |
|
00 |
100 |
011 |
DS:[EBX+scaled_index] |
|
00 |
100 |
100 |
SS:[ESP+scaled_index] |
|
00 |
100 |
101 |
DS:[disp32+scaled_index] |
|
00 |
100 |
110 |
DS:[ESI+scaled_index] |
|
00 |
100 |
111 |
DS:[EDI+scaled_index] |
|
00 |
101 |
DS:disp32 |
|
|
00 |
110 |
DS:[ESI] |
|
|
00 |
111 |
DS:[EDI] |
|
|
01 |
000 |
DS:[EAX+disp8] |
|
|
01 |
001 |
DS:[ECX+disp8] |
|
|
01 |
010 |
DS:[EDX+disp8] |
|
|
01 |
011 |
DS:[EBX+disp8] |
|
|
01 |
100 |
000 |
DS:[EAX+scaled_index+disp8] |
|
01 |
100 |
001 |
DS:[ECX+scaled_index+disp8] |
|
01 |
100 |
010 |
DS:[EDX+scaled_index+disp8] |
|
01 |
100 |
011 |
DS:[EBX+scaled_index+disp8] |
|
01 |
100 |
100 |
SS:[ESP+scaled_index+disp8] |
|
01 |
100 |
101 |
SS:[EBP+scaled_index+disp8] |
|
01 |
100 |
110 |
DS:[ESI+scaled_index+disp8] |
|
01 |
100 |
111 |
DS:[EDI+scaled_index+disp8] |
|
01 |
101 |
SS:[EBP+disp8] |
|
|
01 |
110 |
DS:[ESI+disp8] |
|
|
01 |
111 |
DS:[EDI+disp8] |
|
|
10 |
000 |
DS:[EAX+disp32] |
|
|
10 |
001 |
DS:[ECX+disp32] |
|
|
10 |
010 |
DS:[EDX+disp32] |
|
|
10 |
011 |
DS:[EBX+disp32] |
|
|
10 |
100 |
000 |
DS:[EAX+scaled_index+disp32] |
|
10 |
100 |
001 |
DS:[ECX+scaled_index+disp32] |
|
10 |
100 |
010 |
DS:[EDX+scaled_index+disp32] |
|
10 |
100 |
011 |
DS:[EBX+scaled_index+disp32] |
|
10 |
100 |
100 |
SS:[ESP+scaled_index+disp32] |
|
10 |
100 |
101 |
SS:[EBP+scaled_index+disp32] |
|
10 |
100 |
110 |
DS:[ESI+scaled_index+disp32] |
|
10 |
100 |
111 |
DS:[EDI+scaled_index+disp32] |
|
10 |
101 |
SS:[EBP+disp32] |
|
|
10 |
110 |
DS:[ESI+disp32] |
|
|
10 |
111 |
DS:[EDI+disp32] |
附录二:寻址模式与机器码(假设 myWord 的起始地址偏移量为 0102h)
|
指令 |
机器码 |
寻址模式 |
|
mov ax, my Word |
A1 02 01 |
直接 |
|
mov my Word,bx |
89 IE 02 01 |
直接 |
|
mov [di],bx |
89 ID |
变址 |
|
mov [bx+2],ax |
89 47 02 |
基址 - 偏移量 |
|
mov [bx+si],ax |
89 00 |
基址 - 变址 |
|
mov word prt [bx+di+2], 1234h |
C7 41 02 34 12 |
基址 - 变址 - 偏移量 |
附录三:8 位和 16 位 MOV 指令所有的指令格式和操作码:(根本还是对照着参考附录来)
|
操作码 |
指令 |
说明 |
操作码 |
指令 |
说明 |
|
88/r |
MOV eb, rb |
字节寄存器送 EA 字节操作数 |
8E/2 |
MOV SS, rw |
字寄存器送 SS |
|
89/r |
MOV ew, rw |
字寄存器送 EA 字操作数 |
8E/3 |
MOV DS, mw |
内存字送 DS |
|
8A/r |
MOV rb, eb |
EA 字节操作数送字节寄存器 |
8E/3 |
MOV DS, rw |
字寄存器送 DS |
|
8B/r |
MOV rw, ew |
EA 字操作数送字寄存器 |
A0 dw |
MOV AL, xb |
字节变量(偏移量为 dw)送 AL |
|
8C/0 |
MOV ew, ES |
ES 送 EA 字操作数 |
A1 dw |
MOV AX, xw |
字变量(偏移量为 dw)送 AX |
|
8C/1 |
MOV ew, CS |
CS 送 EA 字操作数 |
A2 dw |
MOV xb, AL |
AL 送字节变量(偏移量为 dw) |
|
8C/2 |
MOV ew, SS |
SS 送 EA 字操作数 |
A3 dw |
MOV xw, AX |
AX 送字寄存器(偏移量为 dw) |
|
8C/3 |
MOV ew, DS |
DS 送 EA 字操作数 |
B0+rb db |
MOV rb, db |
字节立即数送字节寄存器 |
|
8E/0 |
MOV ES, mw |
内存字送 ES |
B8+rw dw |
MOV rw, dw |
字立即数送字寄存器 |
|
8E/0 |
MOV ES, rw |
字寄存器送 ES |
C6 /0 db |
MOV eb, db |
字节立即数送 EA 字节操作数 |
|
8E/2 |
MOV SS, mw |
内存字送 SS |
C7 /0 dw |
MOV ew, dw |
字立即数送 EA 字操作数 |
下表是上面中缩写符号的补充信息:
|
/n: |
操作码后面跟一个 Mod R/M 字节,该字节后面可能再跟立即数和偏移量字段。数字 n( 0〜7 )为 Mod R/ M 字节中 reg 字段的值 |
|
/r: |
操作码后面跟一个 Mod R/M 字节,该字节后面可能再跟立即数和偏移量字段 |
|
db: |
操作码和 Mod R/M 字节后面跟一个字节立即操作数 |
|
dw: |
操作码和 Mod R/M 字节后面跟一个字立即操作数 |
|
+rb: |
8 位寄存器的编号(0〜7 ),与前面的十六进制字节一起构成 8 位操作码 |
|
+rw: |
16 位寄存器的编号(0〜7 ),与前面的十六进制字节一起构成 8 位操作码 |
实战部分机器指令类型:
单字节指令:(空操作数或隐含操作数)
没有操作数或只有一个隐含操作数的指令是最简单的指令,这种指令只需要操作码,其值由处理器的指令集直接确定,没有任何变化可言。
下表列出了几个常见的单字节指令:
|
指令 |
操作码 |
指令 |
操作码 |
|
AAA |
37 |
LODSB |
AC |
|
AAS |
3F |
XLAT |
D7 |
|
CBW |
98 |
INC DX |
42 |
在这些指令中,INC DX 指令好像是不应该岀现的,它出现的原因是:指令集的设计者决定为某些常用指令提供独特的操作码。其结果是,为了代码量和执行速度要对寄存器增量操作进行优化(就是对常用指令给特权,提高执行速度)。
立即数送寄存器指令:(MOV Reg Imm 1011wrrr)
举例由指令手册可知,将一个立即数送寄存器的 MOV 指令格式为 MOV Reg Imm 1011wrrr ,其中操作码可以拆分成 B8 + wrrr,B8 是 MOV Reg Imm 的基指令 (10110000),+wrrr 表示变体类型。
w 表示对字操作(16位寄存器),rrr 指明寄存器编号(0〜7)。Imm 立即操作数(常数)按照小端顺序(起始地址为最低字节)添加到指令
【示例 1】MOV AX, 1 机器指令为 B8 01 00(十六进制),编码过程如下:
1) 立即数送 16 位寄存器的操作码为 B8
2) AX 的寄存器编号为 0,将 0 加上 B8(参见上表所示)
3) 立即操作数(0001)按小端顺序添加到指令(01, 00)(因为操作数是单独的类型,字大小,所以在最小 byte 划分中逆序存放)。
【示例 2】MOV BX, 1234h 机器指令为 BB 34 12,编码过程如下:
1) 立即数送 16 位寄存器的操作码为 B8。
2) BX 的寄存器编号为 3,将 3 加上 B8 得到操作码 BB。
3) 立即操作数字节为 34 12。
寄存器送寄存器指令:(MOV Reg Reg 1000101woorrrmmm)
举例由指令手册可知,寄存器送寄存器指令指令格式为 MOV Reg Reg 1000101woorrrmmm ,其中操作码可以拆分成 BA + w + Mod R/M 。
BA 是 MOV Reg Reg 的基指令 (10001010),+w 表示操作数类型。Mod R/M 字节标识操作数寻址方式,这里由于两个都是寄存器寻址,所以 Mod(oo)字段值为 11,reg 和 r/m 字段分别指定目的寄存器和源寄存器编号。
比如,MOV AX, BX 的机器码为 8B C3,解析如下:
寄存器送其他操作数的 16 位 MOV 指令的 Intel 编码为 8B/r,其中 /r 表示操作码后面带一个 Mod R/M 字节。(基指令 8A (10001010) 加 w=1 (16 位寄存器),所以是 8B (10001011))
Mod R/M 的值为 C3,它包含如下字段:
|
mod |
reg |
r/m |
|
11 |
000 |
011 |
- 位 6〜7 是 mod 字段,指定寻址模式。mod 字段为 11 表示 r/m 字段包含的是一个寄存器编号(r/m 字段指定源操作数)。
- 位 3〜5 是 reg 字段,指定目的操作数。在本例中,AX 就是编号为 000 的寄存器。
- 位 0〜2 是 r/m 字段,指定源操作数。本例中,BX 是编号为 011 的寄存器。
下表列出了更多使用 8 位和 16 位寄存器操作数的例子:
(al 和 ax 分别是 8 位和 16 位寄存器,w 分别 为 0 和 1,所以才一个是 8A 一个是 8B)
|
指令 |
机器码 |
mod |
reg |
r/m |
|
mov ax, dx |
8B C2 |
11 |
000 |
010 |
|
mov al, dl |
8A C2 |
11 |
000 |
010 |
|
mov ex, dx |
8B CA |
11 |
001 |
010 |
|
mov cl, dl |
8A CA |
11 |
001 |
010 |
更多推荐



所有评论(0)