编码ADD指令:一些例子
弄清楚使用如此复杂的体系来编码一条指令,一些小例子很有必要。所以现在来看看如何使用不同的寻址模式来编码一条X86的ADD指令。ADD指令有四个操作码$00,$01,$02,$03 ,使用哪个操作码取决于操作码中的s位及d位。(如Figure 5.15所示) 下面的每个格式描述了如何编码使用不同寻址模式的ADD指令。
寄存器直接寻址
操作码中的d位及MOD-REG-R/M组织方式的不同导致了一个有趣的问题,那就是一条指令对应两个不同的机器码。例如 add(al,cl)也可以编码为$02,$c8,只要在上面的编码方式中将MOD-REG-R/M 中REG 及R/M域所指定的寄存器进行互换,将操作码中的d位由值0变为值1即可实现。这个问题仅出现于有两个操作数的指令中。
直接寻址:
寄存器间接寻址:
寄存器相对寻址:
32位偏移:
比例变址寻址:
编码立即数操作数
出现立即数的ADD指令与标准的ADD指令主要有三个不同。第一,操作码的最高有效值值为1.,这告诉CPU此条指令有一个立即数操作数,这个单一的改变并未告诉CPU将要执行的是ADD指令,我们马上就可以看到。
第二个不同在于在操作码中没有d位了。很显然的,立即数是不可能作为目的操作数的,所以目的操作数只能为MOD-REG-R/M 字节中由MOD R/M指定的那个操作数。
没有d位,取而代之的是x位(符号扩展位)。 这里操作码中的s位与x位要注意一下,s位是指定MOD R/M所指定的那个操作数的大小,而x位表明立即数是否需要进行符号扩展。对于8位的操作数,CPU忽略x位。对于16位或32位操作数来说,x位同时指定了立即数的尺寸。当x位为0时,表明立即数的尺寸同另外一个操作数的尺寸一样;当X位为1时,则表明立即数是一个有符号的操作数,另一个操作数的尺寸同立即数的尺寸不一样,在进行运算之前立即数需要进行有符号的扩展。这一点也使程序的更小,因为一般来说,都是把小的立即数加到16位或32位的操作数上的。
第三个不同在于MOD-REG-R/M 中的REG域。既然立即数是源操作数,MOD-R/M域指定另一个操作数,则REG域这时就空出来了。X86使用这空出来的3个位来作为操作码的扩展。对于ADD指令,这三个位都为0。(其它位值对应于其它不两同的指令)