第五部分 ModR/M
5.1 ModR/M的涵义。
Opcode之后就是ModR/M。Opcode部分是一条指令之中必不可少的部分,没有指令编码,CPU就不知道该如何操作。前面提起过Opcode中有时候也用3个bit来编码寄存器,当指令只有这样一个寄存器操作对象,或者指令的操作对象默认已知的时候,那么指令只需要Opcode部分就行了(Prefix可能也存在)。当指令中存在内存操作对象的时候,就需要ModR/M甚至后面的SIB来编码了。ModR/M一般是用来对内存操作对象进行编码的。当指令中出现了两个寄存器操作对象,或者一个寄存器一个内存操作对象的时候,ModR/M字节一般都会存在的。ModR/M的长度是固定的1个字节,这个字节8个bit被分成了3个部分,Mod(6-7bit),Reg/Opcode(3-5bit),R/M(0-2bit),如图所示:
Mod(2bits):
ModR/M共两个bit能编码4种对象,在ModR/M中这4种对象对应着4种不同的操作对象——后面的3个bit的R/M部分到底是寄存器操作对象还是内存操作对象,如果是内存操作对象,内存寻址模式是什么。4种对象中必需有一个用来定义R/M部分是寄存器,那么剩下的3种就编码内存的寻址方式。所以Mod = 1寄存器 + 3寻址模式。
Reg/Opcode(3bits):
这3个bits是用来编码寄存器的,编码方式前面提到过。这里还有(“/”)或Opcode,前面已经提起过,这部分有可能用于辅助操作指令编码。大家可以想到,当这3个bit用到操作指令编码的时候,指令中就只能有寄存器和内存中的其中一个操作对象了,是内存还是寄存器,就看Mod的值了。
R/M(3bits):
“R”是指Register寄存器,“M”是指Memory内存。这3个bit的涵义很明显,寄存器或者内存,具体这3个bit用来编码什么就要看Mod的值了。
从上面的描述可以看出来:
1、指令只能由两个寄存器操作对象,一个寄存器一个内存操作对象,而不可能同时出现两个内存操作对象(暂时先不考虑立即数操作对象)。这就是初学汇编的时候教科书告诫我们的,不能用 mov 内存1,内存2……,两个内存之间的操作,必须使用寄存器作为中转。其实原因很简单,intel指令中只留了一个位置用作内存寻址编码(R/M位置)。
2、ModR/M编码了两种操作对象(3-5bit用作Opcode的时候不太多,大部分情况,还是用来编码寄存器),其中一个一定是寄存器,另外一个是内存或者是寄存器。
3、当R/M部分用作内存寻址的时候,3个bit共有8种编码,再乘以Mod的3种内存寻址模式,共有 3 * 8 = 24种寻址方式。386以前,16位的情况是,的确只有24种内存寻址方式。386(32位)以后intel增加了一种新的寻址方式SIB,新的寻址模式下一个部分再总结,这里要说的是,3种寻址模式的每个R/M的8种编码中都有一个用来指示SIB寻址模式,这样我目前要考虑的就只有(386-32位)24 - 3 = 21中寻址方式了。
5.1.1 32位寻址模式
intel把所有的寻址方式都列了一张表,现在我们对照这张表(先看32位寻址表),看看我们上面所说的情况:
先看Mod那一列:共4种,前3种(