ModR/M由Mod + RM + Reg/Opcode三部分组成,如下所示:
许多指令的机器码组成中都需要使用ModR/M字段,8086 CPU为16位寻址,因此需要了解16位寻址形式下的ModR/M字节具体值,组成情况,如下图所示。
ModR/M表查询方法:
类似于坐标的方式,通过Mod和R/M值来确定哪一行,Reg/Opcode值来确定哪一列,所交汇的单元格,就是ModR/M字节的值。
比如:
Mod为00,R/M为011,对应的寻址方式为[bp+di];
Reg/Opcode为001,表示CL/CX/ECX/MM1寄存器或操作,所组成的ModR/M值为0Bh。
如果想了解指令的机器码,就需要了解 x86 处理器的指令集。
要想了解 x86 处理器的指令集,Intel 的官方资料是必不可少的,下面是 x86 架构软件开发手册,可以从这里下载。
我们举几个立即数操作的例子:
mov al, 3
mov cx, 3
mov edx, 3
然后,把表格中每一类寻址方式,都举一个例子,进行描述,如下:
序号 | 寻址方式 | Mod | R/M | 汇编例子 |
---|---|---|---|---|
1 | disp16 | 00 | 110 | mov cx,[0100h]与mov [0100h],cx |
2 | [BX] | 00 | 111 | mov cx,[bx] |
3 | [BX+SI] | 00 | 000 | mov cx,[bx+si] |
4 | [BX]+disp8 | 01 | 111 | mov cx,[bx+10h] |
5 | [BX+SI]+disp8 | 01 | 000 | mov cx,[bx+si+10h] |
6 | [BX]+disp16 | 10 | 111 | mov cx,[bx+0100h] |
7 | [BX+SI]+disp16 | 10 | 000 | mov cx,[bx+si+0100h] |
8 | ECX/CX/CL/MM1 | 11 | 001 | mov ax,cx |
9 | EAX/AX/AL/MM0 | 11 | 000 | mov cx,ax |
因此,一共有12个汇编指令转机器码的例子,接下来,依次来讲解。
通常将一条汇编指令,转换为机器码,需要经过如下几个步骤:
mov al, 3
表示将立即数3存储到8位
寄存器al中。
查询指令手册,与MOV r8,imm8
指令相符,其操作码为B0+rb,rb表示目的操作数r8寄存器的编号。
当前指令的r8,就是al,al编号为0,因此操作码为B0+0=B0。
上面的编号,每个数字都代表了一组寄存器。比如:数字 0 代表了 AL、AX、EAX、MM0这一组寄存器;数字 1 代表了 CL、CX、ECX、MM1这一组寄存器;依此类推。
根据X86指令基本格式定义,当前指令不存在Instruction Prefixes、ModR/M、SIB和Displacement,如下:
目前mov指令和al寄存器,都在操作码中体现了,但是立即数还没有体现,因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | 立即数 | 机器码 |
---|---|---|---|
mov al,3 | B0 | 3 | B003 |
mov cx, 3
表示将立即数3存储到16位
寄存器cx中。
查询指令手册,与MOV r16,imm16
指令相符,其操作码为B8+ rw,rw表示目的操作数r16寄存器的编号。
当前指令的r16,就是cx,cx编号为1,因此操作码为B8+1=B9。
根据X86指令基本格式定义,当前指令不存在Instruction Prefixes、ModR/M、SIB和Displacement。
目前mov指令和cx寄存器,都在操作码中体现了,但是立即数还没有体现,因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | 立即数 | 机器码 |
---|---|---|---|
mov cx, 3 | B9 | 3 | B90300 |
机器码左边为低地址,右边为高地址,为了存储16位形式的0003h,需要将高8位00h放入高地址,低8位03h放入低地址,因此立即数表示为0300h。
mov edx, 3
表示将立即数3存储到32位
寄存器edx中。
查询指令手册,与MOV r32,imm32
指令相符,其操作码为B8+ rd,rd表示目的操作数r32寄存器的编号。
当前指令的r32,就是edx,edx编号为2,因此操作码为B8+2=BA。
根据X86指令基本格式定义,当前指令不存在Instruction Prefixes、ModR/M、SIB和Displacement。
目前mov指令和edx寄存器,都在操作码中体现了,但是立即数还没有体现,因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | 立即数 | 机器码 |
---|---|---|---|
mov edx, 3 | BA | 3 | BA03000000 |
mov cx,[0100h]
,段地址默认在ds中,表示将ds * 16 + 0100h位置处内存单元数据(2字节),存储到16位
寄存器cx中。
查询指令手册,与MOV r16,r/m16
指令相符,其操作码为8B /r,/r表示这条指令具有ModR/M字段。
因此,我们查询ModR/M表,如下图所示:
我们首先分析指令mov cx,[0100h]
的组成,目的操作数为cx,源操作数为[0100h];表格中disp16的意思是Displacement16,即16位的偏移,汇编中[0100h]正是disp16,比如[10h]就是disp8,[00010000h]就是disp32。
因此,以disp16为行,以CX为列,交汇处0E表示ModR/M值(Mod=00,Reg/Opcode=001,R/M=110)。
目前mov指令和cx寄存器,都在操作码中体现了,但是立即数0100h还没有体现,因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 立即数 | 机器码 |
---|---|---|---|---|
mov cx,[0100h] | 8B | 0E | 0100 | 8B0E0001 |
机器码中,0100h,仍然保持低字节放在低地址,高字节放在高地址。
mov cx,ds:[0100h]
或mov cx,cs:[0100h]
,其机器码也是8B0E0001,唯一的区别是所使用的段寄存器不一样,前者是cx = ds * 16 + 0100h,后者是cx = cs * 16 + 0100h。
另外,试想一下mov [0100h],cx
,又该如何查询ModR/M表?
此时,其操作码为89 /r。查ModR/M表时,实际上还是以disp16为行,以CX为列,来定位ModR/M值,依旧为0E。
汇编指令 | 操作码 | ModR/M | 立即数 | 机器码 |
---|---|---|---|---|
mov [0100h],cx | 89 | 0E | 0100 | 890E0001 |
我们可以看出,当内存与寄存器之间进行数据操作时,ModR/M值与写入的方向无关,此时写入方向是由操作码来进行区别的。
所以,我们查ModR/M表时,需要重点注意:
情况1,内存与寄存器进行数据操作,如下图所示:
情况2,寄存器与寄存器进行数据操作,如下图所示:
情况2,具体分析见mov ax,cx与mov cx,ax指令。
mov ax,cx
,表示将cx寄存器内容存储到ax寄存器中。
查询指令手册,与MOV r16,r/m16
指令相符,其操作码为8B /r,/r表示这条指令具有ModR/M字段。
因此,我们查询ModR/M表,如下图所示:
以源操作数cx为行,以目的操作数ax为列,交汇处C1表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 机器码 |
---|---|---|---|
mov ax,cx | 8B | C1 | 8BC1 |
另外,mov cx,ax
指令,其操作码也为8B /r,查询ModR/M表,如下图所示:
以源操作数ax为行,以目的操作数cx为列,交汇处C8表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 机器码 |
---|---|---|---|
mov cx,ax | 8B | C8 | 8BC8 |
我们可以看出,当寄存器与寄存器之间进行数据操作时,ModR/M值决定了,目的和源操作数所使用的是哪个寄存器,以及寄存器写入的方向。
mov cx,[bx]
,表示将bx寄存器中地址,指向的内存单元,存储到cx寄存器中。
查询指令手册,与MOV r16,r/m16
指令相符,其操作码为8B /r,/r表示这条指令具有ModR/M字段。
因此,我们查询ModR/M表,以[bx]为行,以cx为列,交汇处0F表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 机器码 |
---|---|---|---|
mov cx,[bx] | 8B | 0F | 8B0F |
mov cx,[bx+si]
,表示将bx寄存器中地址+si寄存器中地址,指向的内存单元,存储到cx寄存器中。
与MOV r16,r/m16
指令相符,其操作码为8B /r。
查ModR/M表,以[bx+si]为行,以cx为列,交汇处08表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 机器码 |
---|---|---|---|
mov cx,[bx+si] | 8B | 08 | 8B08 |
mov cx,[bx+10h]
,表示将bx寄存器中地址+10h,指向的内存单元,存储到cx寄存器中。
与MOV r16,r/m16
指令相符,其操作码为8B /r。
查ModR/M表,以[bx]+disp8为行,以cx为列,交汇处4F表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 立即数 | 机器码 |
---|---|---|---|---|
mov cx,[bx+10h] | 8B | 4F | 10 | 8B4F10 |
mov cx,[bx+si+10h]
,表示将bx寄存器中地址+si寄存器中地址+10h,指向的内存单元,存储到cx寄存器中。
与MOV r16,r/m16
指令相符,其操作码为8B /r。
查ModR/M表,以[bx+si]+disp8为行,以cx为列,交汇处48表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 立即数 | 机器码 |
---|---|---|---|---|
mov cx,[bx+si+10h] | 8B | 48 | 10 | 8B4810 |
mov cx,[bx+0100h]
,表示将bx寄存器中地址+0100h,指向的内存单元,存储到cx寄存器中。
与MOV r16,r/m16
指令相符,其操作码为8B /r。
查ModR/M表,以[bx]+disp16为行,以cx为列,交汇处8F表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 立即数 | 机器码 |
---|---|---|---|---|
mov cx,[bx+0100h] | 8B | 8F | 0100 | 8B8F0001 |
mov cx,[bx+si+0100h]
,表示将bx寄存器中地址+si寄存器中地址+0100h,指向的内存单元,存储到cx寄存器中。
与MOV r16,r/m16
指令相符,其操作码为8B /r。
查ModR/M表,以[bx+si]+disp16为行,以cx为列,交汇处88表示ModR/M值。
因此指令的机器码组成,如下所示:
汇编指令 | 操作码 | ModR/M | 立即数 | 机器码 |
---|---|---|---|---|
mov cx,[bx+si+0100h] | 8B | 88 | 0100 | 8B880001 |
参考文档: