归根结底,处理器只认识机器语言,处理器会按照机器码的指示进行动作。
x86体系结构使用指令长度可变的机器语言,一条机器码指令可以从1字节到13字节不等。这个跟ARM还是有很大区别,ARM32位处理器的话,是定长指令,是32位长度。
8086~80286使用16位指令模式,80386以上处理器也可以工作在16位指令模式,两者是兼容的。16位模式和32位模式,其指令机器码格式有一些差别,具体格式如下:
32位指令格式的头两个字节,因为不常出现,所以称为超越前缀(override prefix)。第一个字节用来修改指令操作数地址的长度,第二个字节修改寄存器长度。如果80386以上按16位指令模式的机制操作(实模式或保护模式),而使用32位寄存器,则指令的前面出现寄存器长度前缀66H。如果按32位指令模式操作(只在保护模式),而且使用32位寄存器,则不存在寄存器长度前缀。如果在32位指令模式中出现16位寄存器,则要使用寄存器长度前缀选择16位寄存器。在带有前缀的指令中,前缀把寄存器及操作数地址的长度从16位转换到32位,或是从32位转换到16位。注意,16位指令模式用8位及16位寄存器和寻址方式,而32位指令模式使用8位及32位寄存器和寻址方式,这是默认的用法。前缀可超越这些默认值,因此32位寄存器可以用于16位模式,而16位寄存器可以用于32位模式。
操作码
操作码一般为1~2字节。
1.第一个字节
第一个字节格式为(大部分情况,不是所有指令都是这个格式):
(1).前6位表示不同的操作码。
(2).D-数据流方向
D=1,数据从位于指令第二个字节的R/M字段流向寄存器(REG)字段。
D=0,数据从REG字段流向R/M字段。
(3).W-字节或字或双字
w=0,数据长度是字节
w=1,数据长度是字或者双字(80386以上为双字)
2.第2个字节
第二个字节格式为:
(1)MOD字段
MOD字段规定指令的寻址方式,MOD字段选择寻址类型及所选的类型是否有位移量。下表列出了在没有操作数地址长度超越前缀(67H)时,16位指令模式下MOD字段各种可能的取值。如果MOD字段的内容是11,它选择寄存器寻址模式。寄存器寻址用R/M字段指定一个寄存器而不是存储单元。如果MOD字段的内容是00,01,10,R/M字段选择数据存储器寻址方式之一。当MOD字段选择了数据存储器寻址方式时,00表示寻址方式没有位移量,01表示包含8位符号扩展的位移量,10表示包含16位的位移量。比如MOV AL,[DI]指令没有使用位移量,MOV AL,[DI+2]指令用8位的位移量(+2),MOV AL,[DI+1000H]指令用16位的位移量(+1000H)。
如果是80386及以上处理器,MOD=01,表示8位的位移量,MOD=10,表示32位的位移量。
下表表示REG字段和R/M字段(MOD=11)寄存器的分配情况:
如果MOD字段是00,01或者10,则R/M按新的意义理解,编程寻址方式的定义。以下是16位寻址方式对应的R/M代码:
以下是32位寻址方式对应的R/M代码:
以上为常见机器码的相关格式,因x86属于复杂指令集,指令种类非常多,不是所有指令都符合这些规则,但是那些指令比较少用到,至少linux0.11内核里面基本没有用到。
以上信息来源于《intel微处理器结构、编程与接口》第六版。