8086指令格式
1.组成
8086的指令使用的是1-6Byte(s)的变长指令。由3个部分组成:
- 操作码(1 Byte)
- 操作数(寻址方式+寄存器/内存地址)(1-5 Byte(s))
举几个例子,下图是1Byte-6Bytes不同长度指令的划分:
2.举个例子
先来翻译一下上面的各个部分:D(Destination)目的操作数,W(word)字,MOD 模式/方式,REG(Register)寄存器,R/M(Register/Memery)内存或寄存器
根据解释可以看到,上面这种格式的指令,有源操作数和目的操作数,其中一个是寄存器变量,另一个是存储器/寄存器变量。
抽象为:
OPTION REG, REG
OPTION REG, M
OPTION M, REG
解释各个部分所表示的内容:
第一字节
第一字节的中的D和W与第二字节中的REG有很大的关系,D表示指令中的REG部分是否为目的操作数,D=1表示REG表示目标操作数;W表示操作数的类型(长度),W=1表示是一个字数据。
第二字节
第二字节中的MOD表示寻址的方式,共有4中:
- 00 存储器寻址,无偏移
- 01 存储其寻址,有8位的偏移
- 10 存储器寻址,有16位的偏移
- 11 寄存器寻址,无偏移
第二字节中的REG表示一个寄存器:
第二字节中的M/REG表示一个内存或寄存器,这个字段需要和MOD结合起来看,如图:
总结一下
- D和REG,可以确定指令中寄存器是源操作数还是目的操作数。
- W确定操作数类型
- 根据W和REG可以确定REG指的是那个寄存器。
- 根据MOD和M/REG确定寻址方式,可以找到操作数的位置,根据W可以确定数据
举个例子:
MOV AH, [BX+DI+50H]
第一字节的前6位我们不必纠结,先不管他,首先来看一下,指令中的寄存器是AH是,因为AH表示一个字节数据,所以W=0;通过查REG的表我们可以看到,表示AH的REG(在第二个字节中)值为100;
因为AH是目的操作数,所以D=1。
第一字节分析完毕,XXXXXX 10
另一个操作数,使用存储器寻址,所以MOD是00,01,10中的某一个,它们三个的区别就是偏移量,根据指令我们可以看到,使用了8位的偏移量,所以MOD=01,这次再进行查表,可以看到对应的R/M=001。
第二字节分析完毕,01 100 001
因为有一个8位偏移量,使用第三个字节表示。
第三字节,50H(注意,低字节在前) 0101 0000
所以,我们可以推知,这条指令的机器码为
xxxx xx10 0110 0001 0101 0000
在DOSBox+masm的环境下编译以下这条语句看一下
将8A6150H写成2进制
1000 1010 0110 0001 0101 0000
可见,我们的分析是正确的
ADD 2345H[BX][DI], DX
还按面的例子一样分析,由DX以及它是一个源操作数可以直到D=0,W=1
,通过查REG的表可以得到AX的REG的值为000。
第一个字节:xxxxxx01
第二个字节还有MOD和R/M没确定,这两个值是根据目标操作数得到,目标操作数使用基址变址相对寻址的方式,而且偏移量是一个16位的,基址寄存器位BX,变址寄存器位DI,通过查表可以得到R/M=001,MOD=10
第二个字节:10 000 001
第三个字节:偏移量低8位 45H 0100 0101
第三个字节:偏移量高8位 23H 0010 0011
所以,我们推知,这条指令的机器码为
xxxx xx01 1000 0001 0100 0101 0010 0011
接下来再跟编译结果作比较验证一下:
将89914523H转换成2进制
1000 1001 1001 0001 0100 0101 0010 0011
可见我们的推导是正确的。
总结
上面举的两个例子并不能涵盖所有编码的推导方式,但是提供给大家一个推导的思路。