您的位置: 网站首页 > 程序开发 > 汇编语言与微机原理教程 > 第9章 80x86的寻址方式与指令系统 > 【9.3.4 控制转移指令】

9.3.4 控制转移指令

 

9.3.4  控制转移指令

程序控制指令能控制程序执行的流程,可构成转移、循环、调用和返回。

1.控制转移指令

转移指令分无条件转移和条件转移两类,它们本身执行后都不影响FL寄存器的状态标志。

(1)无条件转移指令。

无条件转移指令JMP<TARGET>,控制程序转移到TARGET(目标)标号处去执行。按TARGET目标地址单元的属性有4种转移范围、5种指令格式。

JMP SHORT<TARGET>           ; 段内直接短转移

JMP NEAR PTR<TARGET>        ; 段内直接近转移

JMP WORD PTR<TARGET>        ; 段内间接转移

JMP FAR PTR<TARGET>         ; 段间直接转移

JMP DWORD PTR(TARGET)      ; 段间间接转移

段内转移只改变IP值,CS(代码段基址)不变。段内直接转移为相对寻址,将IP指向的(下条)指令距目标TARGET的偏移量(字节距离)与IP的当前值相加后送IP,其中,段内短转移的偏移量为8位,(以当前指令位置为准的)转移范围为129~-126(若以IP当前值为准则为127~-128);段内直接近转移的偏移量为16位、(以当前指令位置为准的)转移范围为32769~-32766(若以IP当前值为准则为32767~-32768);段内间接转移是绝对寻址,TARGET是一个16位的寄存器或存储器单元,将其内容直接赋给IP;段间转移跨段,段间直接转移将指令中给出的TARGET偏移量和段基址赋给IP和CS,段间间接转移将指令中给出的TARGET存储单元开始的4个字节分别赋给IP和CS,从而实现跨段转移。

无条件转移指令的汇编格式、语句操作、转移范围如表9-1所示。

表9-1  无条件转移指令

指令种类

格    式

操    作

转移范围

段内直

接转移

短转移

JMP SHORT<TARGET>

IP←IP+Disp8

-128~127

近转移

JMP NEAR PTR<TARGET>

IP←IP+Disp16

-32768~32767①

段内间接转移

JMP<Reg16>

IP←Reg16

当前代码段内

JMP<Mem16>

IP←Mem16

段间直接转移

JMP FOR PTR<TARGET>

IP←TARGET偏移量

CS←TARGET段基址

跨段,整个内存

段间间接转移

JMP DWORD PTR <TARGET>

IP←(EA),CS←(EA十2)

注:①在当前代码段内,<……>内为符号地址或寄存器或存储单元的具体内容。

(2)条件转移指令。

条件转移指令测试标志寄存器(FL)的当前状态标志,满足条件就转移到目标地址去执行,否则顺序向下执行。条件是对一个或两个或3个状态标志位的状态判断。

8086/8088所有条件转移指令都是段内直接短转移,转移的范围是-128~127个字节距离。指令长度为两个字节,第一字节为操作码,第二字节为距TARGET(目标)的8位偏移量。

条件转移指令的汇编格式、转移条件、应用场合、指令编码等如表9-2所示。

【例9-4】一个16位数的数组存储在以ARRAY为首地址的数据段中,长度为n(小于256)。编程求数组中正数、0及负数的个数,分别存放在BH、BL、DI中。

MOV CX,<n>                  ; 数组长度送计数器CX

MOV AX.0

MOV SI,AX                   ; 数组指针初始化为0

MOV BX,AX                   ; 结果寄存器清零

MOV DI.AL

AGAIN:  CMP AX,ARRAY[SI]   ; 比较

JG      PLUS

Jz.    ZERO

INC     DI                  ; 是负数,负数个数寄存器加l

JMP     NEXT

ZER0:  INC BL               ; 是0,0个数寄存器加1

JMP NEXT

PLUS:  INc BH               ; 是正数,正数个数寄存器加1

NEXT:  ADD SI,2            ; 指向下一个数组元素

DEC CX

JNZ AGAIN                   ; 未结束则继续

表9-2  条件转移指令

判断

指令名称

汇编格式

转移条件

应用

等价助记符

单标志位判断

结果为零(相等)转移

JZ<TARGET>

ZF=1

相等

比较

JE<TARGET>

结果不为零(不相等)转移

JNZ<TARGET>

ZF=0

JNE<TARGET>

结果为负转移

JS<TARGET>

SF=1

正负

判断

 

结果为正转移

JNS<TARGET>

SF=0

 

结果溢出转移

JO<TARGET>

OF=1

溢出

判断

 

结果不溢出转移

JNO<TARGET>

OF=0

 

结果偶特性转移

JP<TARGET>

PF=0

奇偶

判断

JPE<TARGET>

结果奇特性转移

JNP<TARGET>

PF=1

JPO<TARGET>

低于(不高于等于)转移

JB<TARGET>

CF=1

无符

号数

比较

JNAE<TARGET>

JC<TARGET>

不低于(高于等于)转移

JNB<TARGET>

CF=0

JAE<TARGET>

JNC<TARGET>

双标志位判断

低于等于(不高于)转移

JBE<TARGET>

CF∨ZF=1

有符

号数

比较

JNA<TARGET>

不低于等于(高于)转移

JNBE<TARGET>

CF∨ZF=0

JA<TARGET>

小于(不大于等于)转移

JL<TARGET>

SF xor 0F=1

JNGE<TARGET>

不小于(大于等于)转移

JNL<TARGET>

SF xor 0F=0

JGE<TARGET>

三标志位判断

小于等于(不大于)转移

JLE<TARGET>

(SF xor 0F)

∨ZF=1

JNG<TARGET>

不小于等于(大于)转移

JNLE<TARGET>

(SF xor 0F)

∨ZF=0

JG<TARGET>

注:<……>内为目标的具体符号地址名称为∨指or,∧指and。

从80386开始扩大了条件转移的范围,实模式下能够转移到代码段的任何位置。

2.循环指令

循环程序非常普遍,用条件指令就可实现;为方便编程,基本指令集特意提供了4条循环指令。

循环指令放在循环程序的开头或结尾,通过测试CX是否为0以及ZF标志的状态来控制循环结束与否。循环指令长度都是两个字节,一个字节操作码加8位偏移量,循环转移范围为-128~127。循环指令执行不影响标志寄存器(FL)的状态标志。

循环指令的汇编格式、测试条件、语句操作如表9-3循环控制指令所示。

表9-3  循环控制指令

指令名称

汇编格式

测试条件

语句操作

循环

LOOP<TARGET>

CX≠0

CX←CX-1,

满足条件则循环执行,否则顺序向下执行(退出循环)

为零(相等)循环

LOOPZ<TARGET>

LOOPE<TARGET>

(ZF=1)∧(CX≠0)

不为零(不相等)循环

LOOPNZ<TARGET>

LOOPNE<TARGET>

(ZF=0)∧(CX≠0)

CX为零循环

JCXZ<TARGET>

CX=0

同上,但CX不减1

注:<……>内为目标的具体符号地址名称。

【例9-5】一字符串长度(<256)存放在ASCII STR单元,ASCII STR单元之后接着存放该字符串。试编程判断该字符串中是否有“空格”字符,若有DI置1,否则DI清零。

MOV BX,0                ; 地址指针初始化为0

MOV DI,BL               ; 预置没有“空格”标志

MOV AL,20H              ; “空格”字符送AL

MOV CX,ASCIISTR[BX]     ; 串长度送CX

NEXT:  INC  BX

CMP AL,ASCIISTR[BX]     ; 判断是否为空格

LOOPNZ NEXT

JNZ  D0NE

MOV DI,01H              ; 置有“空格”标志

DONE:…                 ; 没有“空格”,继续运行

32位的80x86微处理器还可以使用ECX作为隐含的循环计数器。即便是80486,循环指令也只能在短距离内进行循环,即相对于当前循环指令的地址,转移的范围为-129~126。

3.子程序调用指令(CALL)和返回指令(RET)

子程序调用不同于转移指令,首先要把CALL指令的下一条指令地址(即返回地址)入栈保存,然后转向子程序的首地址去执行。调用分段内调用和段间调用。段内调用只对IP操作(CS不变),段间调用要同时对CS和IP操作。段内/段间调用又分直接调用和间接调用。调用和返回指令都没有条件判断。

调用和返回指令的汇编格式、语句操作如表9-4所示。

返回指令根据调用的距离属性自动执行段内返回或段间返回。带立即数返回指令废除栈顶若干个(偶数)字节单元,使堆栈指针SP向栈底(高地址方向)移动<Exp>个字节单元,常用于以堆栈传送参数的子程序调用。

表9-4  子程序调用和返回指令

指令名称

汇编格式

语句操作

段内直接调用

CALL<PROC>

SP←SP-2,(SP)←IP,IP←IP+Disp16

段内间接调用

CALL<Reg16>

CALL<Mem16>

SP←SP-2,(SP)←IP,IP←Reg16

SP←SP-2,(SP)←IP,IP←Mem16

段间直接调用

CALL<PROC>

SP←SP-2,(SP)←CS,SP←SP-2,(SP)←IP,

IP←偏移地址,CS←段基址

段间间接调用

CALL<Mem16>

SP←SP-2,(SP)←CS,SP←SP-2,(SP)←IP,IP←(EA),CS←(EA+2)

段内返回

RET

IP←(SP),SP←SP+2

段内带立即数返回

RET<Exp>

IP←(SP),SP←SP+2,SP←SP+<Exp>

段间返回

RET

IP←(SP),SP←SP+2,CS←(SP),SP←SP+2

段间带立即数返回

RET<Exp>

IP←(SP),SP←SP+2,CS←(SP),SP←SP+2,SP←SP+<Exp>

注:<……>内为具体名称(过程名、寄存器、存储器或表达式,Exp表达式的值为16位无符号偶数。CALL指令格式中可加属性操作符,以指明或修改操作数的属性,参见JMP指令)。

CALL和RET指令都不影响标志寄存器(FL)的标志位。

4.中断指令(INT)和中断返回指令(IRET)

中断指令(INT)是一种特殊的调用指令(调用例行中断子程序),是段间调用;与段间CALL指令相同的是须先把CS:IP入栈保存,不同的是还要首先把标志寄存器(FL)入栈保存。中断返回是段间返回,执行IRET指令,依次恢复IP、CS和FL。

INT和IRET指令汇编格式、语句操作如表9-5所示。

表9-5  中断指令和中断返回指令

指令名称

汇编格式

语句操作

中断指令调用

INT<Exp>

SP←SP-2,[SP]←FL,SP←SP-2,[SP]←CS

SP←SP-2,[SP]←IP

IP←[n×4],CS←[n×4+2]

断点中断调用

INT或INT 3

溢出中断调用

INT 0或INT 4

中断返回

IRET

IP←[SP],SP←SP+2,CS←[SP],SP←SP+2,

FL←[SP],SP←SP+2

注:<Exp>表达式结果是n,n为中断类型号1~255,不能为0。