8086/8088汇编指令系统剖析(四)

时间:2022-01-18 19:26:09

转移指令


8086/8088提供了大量用于控制程序流程的指令,按功能分为如下四类:


1)无条件转移指令和条件转移指令;

2)循环指令;

3)过程调用和过程返回指令

4)软中断指令和中断返回指令


由于程序代码可以分为多个段,所以根据转移时是否重置代码段寄存器CS的内容,他们又可以分为段内转移和段间转移两大类。段内转移是指仅重新设置指针指令IP的转移,由于没有重置CS,所以转移后继续执行的指令仍在同一个代码段中。条件转移指令和循环指令只能实现段内转移,段间转移是指不仅重新设置IP,而且重新设置代码段寄存器CS的转移,由于重置CS,所以转移后继续执行的指令在另一个段中。软中断指令和中断返回指令总是段间转移。段内转移也称近转移,而段间转移也称远转移。

对无条件转移指令和过程调用指令而言,按确定转移目的的地址方式还可分为直接转移和间接转移。

下面介绍无条件转移指令,条件转移指令和循环指令。这些指令均不影响标志。


1.无条件转移指令


1)无条件段内直接转移指令

无条件段内直接转移指令的使用格式如下:

JMP标号


这条指令使控制无条件转移到标号地址处。例如:


NEXTMOV AXCX

­......

JMP NEXT

......

JMP OVER

' .......

OVERMOV AX1


无条件段内直接转移指令对应的机器指令格式如下,由操作码和地址差构成。


指令操作码 |地址差


其中的地址差是程序中该无条件转移指令的下一条指令开始地址到转移目标地址的差值,由汇编程序在汇编时计算得出。因此,在执行无条件段内转移指令时,实际的动作是把指令中的地址差加到指令指针IP上,使IP之内容为目标地址,从而达到转移的目的。请注意,指令中的地址差值由汇编程序计算得出。


段内无条件直接转移指令中的地址差可用一个字节表示,也可以用一个字表示。如果地址差只要用一个字节表示,就称为短转移;如果地址差要用一个字表示,就称为近转移。一个字节表示的地址差的范围是-128+127,所以,如果以转移指令本身为基准,那么短转移的范围则在-126+129之间。一个字表示的地址差的范围是065535,当IP与地址差之和超过65535时,那么便在段内反饶(即取65535的模),所以,近转移的范围是整个段。

如果当汇编程序汇编到该转移指令时能够正确地计算出地址差,那么汇编程序就根据地址差的大小,决定使用一个字节表示地址差,还是使用一个字表示地址差。例如,上例中的“JMP NEXT”指令。如果当汇编程序汇编到该指令时还不能计算出地址差,那么汇编程序就按两个字节地址差汇编转移指令。例如,上例中的“JMPOVER”指令。对于后一种情况。如果程序员在写程序时能估计出用一个字节就可表示地址差,那么可在标号前加一个汇编程序操作符SHORT,例如:


JMP SHORT OVER



这样汇编程序就按一字节的地址差汇编此转移指令。当实际的地址差无法用一个字节表示时,汇编程序会发出汇编出现错误的提示。

这种利用目标地址与当前转移指令本身地址之间的差值记录转移目标地址的转移方式也称为相对转移相对转移有利于程序的浮动。


2)无条件段内间接转移指令


JMP OPRD


这条指令使控制无条件地转移到由操作数OPRD的内容给定的目标地址处。操作数OPRD可以是通用寄存器,也可以是字存储单元。例如:


JMP CXCX寄存器的内容送入IP

JMP WORD PTR [1234H];字存储单元[1234H]的内容送IP



3)无条件段间直接转移指令


无条件段间直接转移指令的使用格式如下:


JMP FAR PTR标号


这条指令使控制无条件转移到标号所对应的地址处。标号前的符号“FAR PTR”向汇编程序说明这是段间转移。只有当标号具有原属性,且标号处的指令已先被汇编的情况下,才可省去远属性的说明“FAR PTR”


例如:


JMP FAR PTR EXITEXIT是定义在另一个代码段中的标号


无条件段间直接转移指令的机器指令格式如下,由操作码及包含段值和偏移的地址构成。


指令操作码 |目标地址偏移 |目标地址段值


无条件段间直接转移指令的具体动作是把指令中包含的目标地址段值和偏移分别置入CSIP


这种指令中直接包含转移目标地址的转移方式称为绝对转移。


4)无条件段间间接转移指令


无条件段间间接转移指令的格式如下:


JMP OPRD


这条指令使控制无条件地转移到由操作数OPRD的内容给定的目标地址处。操作数OPRD必须是双字存储单元。例如:


JMP DWORD PTR [1234h];双字存储单元的低字内容送到IP

;双字存储单元的高字内容送到CS


2.条件转移指令


8086/8088提供了大量的条件转移指令,他们根据某标志位或者某些标志位的逻辑运算判别条件是否成立。如果条件成立,则转移,否则继续顺序执行。

所有条件转移都只是段内转移。

条件转移也采用相对转移方式。即通过在IP上加一个地址差的方法实现转移。但条件转移指令中只用一个字节表示地址差,所以,如果条件转移指令本身作为基准,那么条件转移的范围在-126+129之间。如果条件转移的目标超出此范围,那么必须借助于无条件转移指令。


条件转移指令不影响标志。

条件转移指令的格式列于表2.3中,有些条件转移指令有两个助记符,还有些条件转移指令有三个助记符。使用多个助记符的目的是便于记忆和使用。


指令格式 |转移条件 |转移说明 |其他说明

JZ标号 ZF=1等于0转移 单个标志

JE标号 ZF=1或者相等转移

----------------------------------------------------------------------------------------------------------

JNZ标号 ZF=0不等于0转移 单个标志

JNE标号 ZF=0或者不相等转移

-----------------------------------------------------------------------------------------------------------


JS标号 SF=1为负转移 单个标志

-----------------------------------------------------------------------------------------------------------

JNS标号 SF=0为正转移 单个标志

-----------------------------------------------------------------------------------------------------------

JO标号 OF=1溢出转移 单个标志

-----------------------------------------------------------------------------------------------------------

JNO标号 OF=1不溢出转移 单个标志

------------------------------------------------------------------------------------------------------------

JP标号 PF=1偶转移 单个标志

JPE标号 PF=1

------------------------------------------------------------------------------------------------------------

JNP标号 PF=0奇转移 单个标志

JPO标号 PF=0

-------------------------------------------------------------------------------------------------------------

JB标号 CF=1低于转移 单个标志

JNAE标号 CF=1或者,不高于等于转移 无符号数

JC标号 CF=1或者,进位标志被置转移

------------------------------------------------------------------------------------------------------------

JNB标号 CF=0不低于转移 单个标志

JAE标号 CF=0或者,不高于等于转移 无符号数

JNC标号 CF=0或者,进位标志被清转移

------------------------------------------------------------------------------------------------------------

JBE标号 (CFZF=1低于等于转移 两个标志

JNA标号 (CFZF=1或者,不高于转移 无符号数

------------------------------------------------------------------------------------------------------------

JNBE标号 (CF或者ZF=0不低于等于转移 两个标志

JA标号 (CF或者ZF=0或者,高于转移 无符号数

------------------------------------------------------------------------------------------------------------

JL标号 (SF异或OF=1小于转移 两个标志

JNGE标号 (SF异或OF=1或者,不大于等于转移 有符号数

------------------------------------------------------------------------------------------------------------

JNL标号 ((SF异或OF)或ZF=1小于等于转移 三个标志

JGE标号 ((SF异或OF)或ZF=1不大于转移 有符号数

-------------------------------------------------------------------------------------------------------------

JNLE标号 ((SF异或OF)或ZF=1不小于等于转移 三个标志

JG标号 ((SF异或OF)或ZF=1大于转移 有符号数



条件转移指令是用的最多的转移指令。通常,在条件转移指令前,总有用于条件判别的有关命令。

下面的程序片段测试AX的低四位是否全是0,如果均是0,那么CX=0,否则使CX=-1


MOV CX-1;先使CX=-1

TEST AX0FH;测试AX的低4

JNZ NZERO;不全为0则转移

MOV CX0;全为0时使CX=0

NZERO.......


3.循环指令


利用条件转移指令和无条件转移指令可以实现循环,但为了更加方便于循环的实现,8086/8088还提供了四条实现循环的循环指令。

循环指令类似与条件转移指令,不仅属于段内转移,而且也采用相对转移的方式,即通过IP上加一个地址差的方式实现转移。循环指令中也只用一个字节表示地址差,所以,如果以循环指令本身作为基准,那么循环转移的范围在-126+129之间。

循环指令不影响各标志。


1)计数循环指令LOOP

计数循环指令的格式如下:


LOOP标号


这条指令使寄存器CX的值减1,如果结果不等与0,则转移到标号,否则顺序执行LOOP指令后的指令。该指令类似如下的两条指令:


DEC CX

JNZ标号


通常在利用LOOP指令构成循环时,先要设置好计数器CX的初始值,即循环次数。由于首先进行CX寄存器减1操作,再判断结构是否为0,所以最多可循环65536次。

如下程序片段实现把从偏移1000H开始的512个字节的数据复制到从偏移3000H开始的缓冲区中。


MOV SI1000H

MOV DI3000H

MOV CX512

NEXTMOV AL[SI]

INC SI

MOV [DI],AL

INC DI

LOOP NEXT


........



2)等于/全零循环指令LOOPE/LOOPZ

等于/全零循环指令有两个助记符,格式如下:


LOOPE标号


或者


LOOPZ标号


这条指令使寄存器CX的值减1,如果结果不等于0,并且零标志ZF等于1,那么则转移标号,否则顺序执行。注意指令本身实施的寄存器CX1操作不影响标志。

如下的程序片段在字符串中查找第一个非“A”字符。设字符串长度已保存在CX中,并且DSDI指向字符串。如果找到,那么使BX指向该非“A”字符,如果找不到,那么使BX=0FFFFH


......

MOV AL,‘A’

DEC DI

NEXTINC DI

CMP AL[DI]

LOOPE NEXT

MOV BX,DH

JNE OK

MOV BX-1

OK.......


3)不等于/非零循环指令LOOPNE/LOOPNZ

不等于/非零循环指令有两个助记符,格式如下:


LOOPNE标号

LOOPNZ标号


这条指令使寄存器CX的值减1,如果结果不等于0,并且零标志ZF等于0,那么则转移到标号,否则顺序执行。注意指令本身实施的寄存器CX1操作不影响标志。


4)跳转指令

跳转指令也可以认为是条件转移指令,跳转指令格式如下:


JCXZ标号


该指令实现当寄存器CX的值等于0时转移到标号,否则顺序执行。通常该指令用在循环开始前,以便在循环次数位0时,跳过循环体。