4.2 8086寻址方式
指令中关于如何求出操作数有效地址的方法称为寻址方式。计算机按照指令给出的寻址方式求出操作数有效地址的过程,称为寻址操作。在程序设计中,有时需要直接写出操作数本身,有时希望给出操作数的地址,有时希望给出操作数所在地址的地址。为了满足程序设计需要,8086/8088给出多种寻址方式,根据操作数的类型及来源大致分为3类:数据寻址、转移地址寻址和I/O寻址。8086提供7种基本的数据寻址方式:① 立即寻址;② 寄存器寻址;③ 直接寻址;④ 寄存器间接寻址;⑤ 寄存器相对寻址;⑥ 基址变址寻址;⑦ 相对基址变址寻址。后面5种寻址方式属于存储器寻址,用来确定操作数所在的存储单元的有效地址EA的计算方法。
4.2.1 立即寻址
操作数直接出现在指令中,此时的操作数也叫立即数。立即数紧跟在操作码后面,一起存放在代码段中。例如:
MOV AX,2010H
该指令的源操作数采用立即寻址方式,指令执行后,(AX)=2010H。执行过程如图4-1所示。
✵ 说明:
- 在该指令格式中,AX是目标操作数,2010H是源操作数。
- 在所有的指令中,立即数只能作源操作数,不能作目标操作数。
- 立即数应与目标操作数的长度一致。
- 立即数默认采用十进制形式,以十六进制形式出现的立即数应以字母H为后缀,以八进制形式出现的立即数应以字母Q为后缀。
图4-1 立即寻址与寄存器寻址方式的指令执行示意图
- 以十六进制形式出现的立即数,若以字母开头,则必须以数字0为前缀。
- 立即数还可以用+、-、×、/表示的算术表达式,也可以用圆括号改变运算顺序。
- 立即数只能是整数,不能是小数、变量或其他类型的数据。
4.2.2 寄存器寻址
操作数在寄存器中,在指令中指定寄存器号。由于寄存器号短,因此,采用寄存器寻址方式的指令的机器码长度短。而且,操作数在寄存器中,指令执行时,操作就在CPU的内部进行,不需要通过访问存储器来取得操作数,因而指令的执行速度快。在编程中,如有可能,应尽量在指令中使用这种寻址方式。
对于16位操作数,寄存器可以是:AX,BX,CX,DX,SI,DI,SP,BP,CS,DS,SS和ES;对8位操作数,寄存器可以是:AH,AL,BH,BL,CH,CL,DH和DL。例如:
MOV AX,2010H
该指令的目标操作数采用寄存器寻址方式,指令执行后,(AX)=2010H。执行过程如图4-1所示。
✵ 说明:
- 在一条指令中,寄存器寻址方式既可用于源操作数,也可用于目标操作数,还可以两者都用寄存器寻址方式。
- 源操作数与目标操作数的长度应一致。例如,不能将寄存器AX的内容传送到寄存器BH中,也不能将寄存器BH的内容传送到寄存器AX中。
- 两个操作数不能同时为段寄存器。
- 目标操作数不能是代码段寄存器。
除以上两种寻址方式外,下面5种寻址方式的操作数均存放在存储器区域中。这5种寻址方式统称为存储器寻址方式。采用存储器寻址方式的指令中的操作数称为内存操作数。必须注意的是,双操作数指令中的两个操作数不能同时采用存储器寻址方式。
4.2.3 直接寻址
操作数在存储器中,指令中以具体数值的形式直接给出操作数所在存储单元的有效地址EA。为了与立即数区别,该有效地址必须用[]括起。例如:
MOV AX,[2010H]
该指令的源操作数采用直接寻址方式。若(DS)=2000H,那么指令执行后,(AX)=1225H。执行过程如图4-2所示。
图4-2 直接寻址方式的指令执行示意图
如上例所示,采用直接寻址方式时,如果指令中没有用前缀说明操作数存放在哪个段,则操作数默认存放在数据段。8086系统允许操作数存放在代码段、堆栈段或附加段。此时,就需要在指令中利用前缀指明段超越。例如:
MOV ES:[1225H],AX
该指令的目标操作数采用直接寻址方式。操作数存放在由ES指示的附加段中,其物理地址=ES×10H+1225H。
在汇编语言指令中,可以用符号地址代替数值地址。例如:
MOV AX,NUMA
此时,NUMA是存放操作数的内存单元的符号地址(关于符号地址的具体说明,请参阅4.3节的有关介绍)。上面这条指令还可以写成如下的形式:
MOV AX,[NUMA]
若DATA1数据存放在附加段,则可以用如下的形式指定段超越前缀:
MOV AX,ES: NUMA 或 MOV AX,ES:[NUMA]
4.2.4 寄存器间接寻址
操作数的有效地址EA存放在基址寄存器BX、BP或变址寄存器SI、DI中。为了区别于寄存器寻址方式,指令中指定的寄存器名要用[]括起来。指令中使用SI、DI、BX寄存器时,操作数默认存放在数据段中;使用BP寄存器时,操作数默认存放在堆栈段中。允许段超越。
操作数的物理地址=(DS)×10H+(SI)/(DI)/(BX)或(SS)×10H+(BP)
例如:
MOV AX,[SI]
该指令的源操作数采用寄存器间接寻址方式。
若(DS)=2000H,(SI)=2010H,那么指令执行后,(AX)=1225H。执行过程如图4-3所示。
若操作数不存放在间址寄存器默认的段,则指定段超越的指令可采用如下形式。此时,操作数的物理地址=ES×10H+SI。
MOV AX,ES:[SI]
图4-3 寄存器间接寻址方式的指令执行示意图
4.2.5 寄存器相对寻址
操作数的有效地址EA是指令中指定的基址或变址寄存器的值与位移量之和。指令中使用SI、DI、BX寄存器时,操作数默认存放在数据段中;使用BP寄存器时,操作数默认存放在堆栈段中。允许段超越。
操作数的物理地址=(DS)×10H+(SI)/(DI)/(BX)+8位或16位位移量或操作数的物理地址=(SS)×10H+(BP)+8位或16位位移量
例如:
MOV AX,8[BX]
该指令的源操作数采用寄存器相对寻址方式。
若(DS)=2000H,(BX)=2008H,那么指令执行后,(AX)=1225H。执行过程如图4-4所示。
✵ 说明:
- 偏移量是符号数,8位偏移量的取值范围为:00~0FFH(即+127D~-128D);16位偏移量的取值范围为:0000~0FFFFH(即+32767D~-32768D)。
- 8086汇编允许用下面3种形式表示相对寻址,它们是等效的。
MOV AX,[BX]+8 MOV AX,8[BX] MOV AX,[BX+8]
图4-4 寄存器相对寻址方式的指令执行示意图
4.2.6 基址变址寻址
操作数的有效地址EA是指令中指定的基址寄存器的值与变址寄存器的值之和。指令中使用基址寄存器BX时,操作数默认存放在数据段中;使用基址寄存器BP时,操作数默认存放在堆栈段中。允许段超越。
操作数的物理地址=(DS)×10H+(SI)/(DI)+(BX)
或 操作数的物理地址=(SS)×10H+(SI)/(DI)+(BP)
例如:
MOV AX,[BX] [SI]
该指令的源操作数采用基址变址寻址方式。
若(DS)=2000H,(BX)=2008H,(SI)=8H,那么指令执行后,(AX)=1225H。执行过程如图4-5所示。
4.2.7 相对基址变址寻址
操作数的有效地址EA是指令中指定的基址寄存器的值与变址寄存器的值以及8位或16位位移量之和。指令中使用基址寄存器BX时,操作数默认存放在数据段中;使用基址寄存器BP时,操作数默认存放在堆栈段中。允许段超越。
图4-5 基址变址寻址方式的指令执行示意图
操作数的物理地址=(DS)×10H+(SI)/(DI)+(BX)+8位或16位位移量或 操作数的物理地址=(SS)×10H+(SI)/(DI)+(BP)+8位或16位位移量
例如:
MOV AX,3[BX] [SI]
该指令的源操作数采用寄存器相对寻址方式。
若(DS)=2000H,(BX)=2008H,(SI)=5H,那么指令执行后,(AX)=1225H。执行过程如图4-6所示。
图4-6 相对基址变址寻址方式的指令执行示意图