本文主要是介绍80x86指令系统(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、Intel 8086/8088的指令格式
Intel 8086/8088指令长度是可变的,指令机器码的长度为1~6个字节。双操作数指令的通用格式如图一:
其中第1字节和第2字节为基本字节,其他字段根据不同的指令有不同的作用。
1.指令第1字节的编码
通常指令的第1字节是操作码,但是也有特殊情况,比如有的指令寄存器字段(REG)在第1个字节中,有些指令的操作码中有3位辅助操作码在第2个字节中。大部分操作码中都含有一些指示位。
OP-code:指令操作码。
D位:方向选择位,用于双操作数指令(含立即操作数的指令和字符串指令除外),表示来自/到寄存器的方向。 D=0表示REG字段给出的寄存器是源操作数寄存器;D=1表示REG字段给出的寄存器是目的操作数寄存器。
W位:指示操作数类型,表示操作数为字节或字节处理方式。W=0表示为字节操作数;W=1表示为字操作数。
2.指令第2字节的编码[1]
指令的第2字节给出了指令的大多数寻址方式,这个字节可以指出两个操作数,一个由REG字段确定,另一个由MOD和R/M字段确定。
(1)REG 寄存器字段(3位):由REG字段确定的操作数一定是在某一个通用寄存器中(即寄存器寻址方式)。REG字段与W字段配合使用,共有16种组合,它不仅指明选择哪个寄存器,而且指明它是8位还是16位。有时,该字段为OP字段,即为操作码扩展字段。
(2)MOD 模式字段(2位):由MOD和R/M字段共同确定一个操作数。这个操作数可以在寄存器中(即寄存器寻址方式),也可以在存储器的某一单元(即直接寻址、寄存器间接寻址、基址寻址、变址寻址或基址变址相对寻址)。当MOD=11时,为寄存器方式,则R/M字段(与REG字段相同)用于选择一个寄存器。当MOD=00、01、10时,为存储器方式,结合R/M字段给出计算操作数有效地址EA的24种方法。
(3)R/M寄存器或存储器字段(3位):R/M为寄存器/存储器字段,当MOD=11时,R/M为寄存器字段;当MOD=00、01、10时,R/M为存储器字段。
3.指令的其他字段
其他字段根据不同的指令有不同的作用,所以指令的字节长度可以变化。通常由第3~6字节给出存储器操作数的位移量和立即操作数。如果一条指令为6个字节,则第3、第4字节为位移量,第5、第6字节为立即数。
二、操作数的类型
操作数的类型共有三种:立即数操作数、寄存器操作数、存储器操作数。
1.立即数操作数:操作数直接放在指令中作为源操作数,这种操作数称为立即数。立即寻址方式用来表示常数,可以用于给寄存器赋值。可以使用立即数操作数的指令有数据传输指令、算术运算指令、逻辑运算指令等;立即数只能为源操作数,不能作为目标操作数,目标操作数必须是寄存器操作数或是存储器操作数,源操作数长度与目的操作数长度应一致。
2.寄存器操作数
存放于80X86 CPU内部寄存器中的操作数称为寄存器操作数。寄存器操作数存放在以下寄存器中:
(1)通用寄存器(32位的通用寄存器:EAX, EBX,ECX,EDX,ESP,EBP,ESI,EDI,还有16位及8位的通用寄存器)
(2)段寄存器(CS、DS、SS、ES、FS、GS)
(3)EFLAGS寄存器
(4)系统寄存器,例如全局描述表寄存器(GDTR)或中断描述符表寄存器(IDTR)。所有的通用寄存器和地址指针寄存器既可以用作源操作数,又可以用作目标操作数。在算术和逻辑运算指令中,常常将AX寄存器当作累加器使用。段寄存器CS、DS、ES、SS用以存放当前的段地址。在与通用寄存器或存储器传送数据时,段寄存器通常也可以作为源操作数或目标操作数,但不能用一条指令简单地将一个立即数传送到段寄存器。当CS、DS、ES、SS需要赋初值时,可先将立即数传送到通用寄存器,然后再从通用寄存器传送到有关的段寄存器中。
3.存储器操作数:数据存放在存储器中,是8位、16位或32位的二进制数,分别占用一个、两个或四个存储单元,对应的数据类型分别为字节、字、双字。在指令中,存储器操作数可以作为源操作数或是目的操作数,但不允许两者同时为存储器操作数,即不允许存储器到存储器的操作。存储器操作数分为标号和变量两种:标号是对存放指令的存储单元地址所命名的名称;变量是指存储变量,为存放数据的存储单元的地址所起的名称。存储器操作数有三种属性[2]:
(1)段属性(SEGMENT)
标号或变量对应所在段的段地址在段寄存器中(CS、DS、ES、SS)。标号所在段基址通常在代码段CS寄存器中,存储变量段基址在DS中。无段超越,隐式出现。
(2)偏移量属性(OFFSET)
标号或变量的地址与段基址的偏移量值。在指令中显式出现。
(3)类型属性(TYPE)
标号类型属性,段内操作还是段间操作。段内操作定义为NEAR类型(即近程操作),段间操作定义为FAR操作(即远程操作)。
三、80X86的寻址方式
1.立即数寻址(Immediate Addressing)
立即寻址方式用来表示常数,可以用于给寄存器赋值。
举例,用ADD指令加立即数至EAX寄存器。
ADD EAX, 12345678H
2.寄存器寻址(Register Addressing)
操作数存放在寄存器中。寄存器可能是数据寄存器(8位、16位或32位)、地址指针或变址寄存器,以及段寄存器。
举例,
MOV ECX, EDX
在介绍了上面两种寻址方式后,下面介绍的寻址方式的操作数都存放在除代码段外的存储区中。操作数的物理地址由段基地址和偏移地址相加得到。为了找到存储器操作数的物理地址,首先必须确定操作数所在的段,然后获得偏移地址(也称为有效地址(EA))。在确认段的选择后,通过《Intel 80386 微处理器的存储器管理》一文中详细介绍了在实地址方式和虚地址保护方式下通过段寄存器来获得段基地址。存储器操作数的寻址方式需要确认段的选择和计算偏移地址的值。通过用不同寻址方式可以获得操作数的地址,然后就可以从存储器中获得操作数。接着需要介绍如何获得偏移地址,也称为有效地址(EA)。
(1)先介绍如何确认段的选择。
段的选择能显示或是默认规定,规定段的选择最通用的方法就是把它存放入段寄存器中,根据执行指令的操作类型来隐性地选择段寄存器。比如,取指时默认使用CS代码段寄存器,IP指令指针寄存器存放着预取指令的偏移地址;又比如在直接寻址时,默认使用DS数据段寄存器。在某些情况下为了特定的操作,可以用指定的段寄存器来代替标准的段寄存器(也就是默认的段寄存器),成为段超越。各种存储器操作所约定的隐含段寄存器、允许超越的段寄存器以及指令的有效地址所在的寄存器见图二。
当从存储器中读取数据时,DS段默认能够超越以允许访问其他段,在汇编程序内,段超越通常用冒号":"处理。以下的默认段选择不能被超越:
1)指令必须存放在CS短重。
2)在串操作中的目的串必须存放在由ES寄存器指向的数据段
3)PUSH指令的目的和POP指令的源必须用SS段。
(2)再确认有效地址(EA)。比例系数必须和变址寄存器同时使用,包含比例系数的三种组合只能用于80386及以后的微处理器。
1)位移量:一个8位、16位、32位的值,它是一个地址。
2)基地址:存放在基址寄存器中的值。
3)变址:存放在变址寄存器中的值。
4)比例系数:值2、4或8,用于与变址相乘。
有效地址(EA)的计算方式:
EA = 基地址 +(变址 * 比例系数) + 位移量
由上面四个中的一个或是多个组成,按照规则,共有10种组合,
(1)基地址
(2)变址
(3)位移量
(4)基地址 + 位移量
(5)变址 + 位移量
(6)基地址 + 变址
(7)基地址 + 变址 + 位移量
(8)(变址 * 比例系数) + 位移量
(9)基地址 + (变址 * 比例系数)
(10)基地址 +(变址 * 比例系数) + 位移量
(1)(2)为寄存器间接寻址,(3)为直接寻址,(4)(5)为寄存器相对寻址方式,(6)基址、变址寻址方式, (7)为基址、变址相对寻址,(8)为比例变址址方式,(9)为基址比例变址寻址方式,(10)为相对基址比例变址寻址方式。共有8种寻址方式,继续介绍寻址方式。
3.直接寻址(Direct Addressing)
操作数的有效地址只包含偏移量,偏移量的值称为有效地址(EA).直接寻址的指令的操作数一般隐含在数据段DS中,但也允许段超越。
举两个例子:
例一采用了默认段
MOV AX, [1234H]
例二允许段超越
MOV AX, ES:[1234H]
4.寄存器间接寻址(Register Indirect Addressing)
操作数的有效地址(EA)只包含在基址寄存器或是变址寄存器中。有效地址在某个寄存器中,操作数则存放在存储器中。在16位寻址时可用的寄存器为BX、BP、SI、DI,在32位寻址
时可用的寄存器为EAX、EBX、ECX、EDX、ESP、EBP、ESI、EDI。在使用BP、ESP、EBP时,默认段为SS段,其他寄存器的默认段为DS段。
例:
MOV AX, [BX]
那么物理地址为DS * 16 + BX,然后将该物理地址的值赋给AX。
5.寄存器相对寻址方式(Register Relative Addressing)
操作数的有效地址是一个基址或变址寄存器的内容与指令中指定的8位或16位位移量(Displacement)之和。它使用的寄存器及默认对应的段与“4.寄存器间接寻址(Register Indirect Addressing)”一样。
例子:
MOV AX, COUNT[SI]
或者
MOV AX, [COUNT + SI]
6.基址、变址寻址方式 (Based Indexed Addressing)
操作数的有效地址是一个基址寄存器和变址寄存器的值之和。它使用的寄存器及默认对应的段与“4.寄存器间接寻址(Register Indirect Addressing)”一样。
例子:
MOV AX, [BX][DI]
或者
MOV AX, [BX+DI]
7. 基址、变址相对寻址(Relative based Indexed Addressing)
操作数的有效地址是一个基址寄存器和变址寄存器的值,再加上偏移量之和。
例子: MOV AX, MASK[BX][SI]
8.比例变址寻址方式(Scaled indexed addressing)
操作数的有效地址是一个变址寄存器的值乘以比例系数,再加上偏移量之和。
例子:
MOV EAX, COUNT[ESI * 4]
9.基址比例变址寻址方式(Based scaled indexed addressing)
操作数的有效地址是一个基址寄存器的值,加上一个变址寄存器的值乘以比例系数。
例子:
MOV ECX, [EAX][EDX * 8]
10.相对基址比例变址寻址方式(Relative based scaled indexed addressing)
操作数的有效地址是一个基址寄存器的值,加上一个变址寄存器的值乘以比例系数,再加上偏移量之和。
例子:
MOV EAX, TABLE[EBP][EDI * 4]
转移地址的寻址方式
1.段内直接寻址
转向的有效地址为当前IP寄存器的内容和指令中指定的8位或16位位移量之和。当位移量为8位时,称为短转移;当位移量为16位时,称为近转移。
例:
JMP NEAR PTR PROG
JMP SHORT QUEST
其中,PROG和QUEST均为转向的符号地址。在汇编指令中,如果位移量为16位,则在符号地址前加操作符NEAR PTR;如果位移量为8位,则在符号地址前加操作符SHORT。这种寻址方式适用于条件转移及无条转移指令。当用于条件转移指令时,位移量只允许 8 位。对于80386及以后的微处理器,代码段的偏移地址放在EIP中,位移量为8位或是32位,8位为短跳转,32位为近跳转。
2.段内间接寻址
转向的有效地址是一个寄存器或是存储器中的内容,用来更新IP寄存器的内容。寄存器或是存储器中的内容可以通过上面介绍的九种寻址方式(去掉第一个“立即数寻址方式”)来获得。这种寻址方式和以下两种段间寻址方式都不能用于条件转移指令。也就是说,条件转移指令只能使用“段内直接寻址的8位位移量(于80386及以后的微处理器允许8位或32位)”,而JMP和CALL指令可以使用这四种寻址方式。
例:
JMP BX
假设DS = 2000H, BX = 1234H, 执行指令后,有效地址(EA)位1234,所以更新IP寄存器的内容后,IP = 1234H.
3.段间直接寻址
指令中直接提供了转向的段地址和偏移地址,只要用指令中的段地址代替CS寄存器中的内容就完成了从一个段跳转到另外一个段,用指令中的偏移地址替换IP寄存器中的内容。
例:
JMP FAR PTR NEXTPOINT
其中,NEXTPOINT位转向的符号地址,FAR PTR则表示段间转移的操作符。
4.段间间接寻址
用存储器中的两个连续的字的内容分别来替换IP和CS寄存器中的内容。很显然,存储器中的内容要通过寻址的方式获得.可以通过存储器操作数寻址的八种方式获得(上面介绍的后八种寻址方式)。
例如: JMP DWORD PTR[BP][DI]
其中,[BP][DI]说明寻址方式是“基址、变址寻址方式”,DWORD PTR位双字操作符号,说明转向地址需要取双字位段间转移指令。
引用及参考资料
[1]http://202.116.0.161/wjyl/site/text/chapter3/3.2.2.htm
[2]http://kecheng.lut.cn/wjyl/doc/jiaocai/chp4.pdf
这篇关于80x86指令系统(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!