[汇编]8086指令系统---控制转移指令

[汇编]8086指令系统---控制转移指令(一)

控制转移指令通过改变CS:IP来控制程序的执行流程。这类指令包括无条件转移指令、条件转移指令、循环指令、子程序调用和返回指令以及中断和中断返回指令。
 
    ⑴ 无条件转移
      JMP 跳转

      ⑵ 条件转移
      JZ/JNZ    结果为零/不为零则转移
      JS/JNS    结果为负/为正则转移
      JO/JNO    溢出/不溢出则转移
      JP/JNP    奇偶位为1/为0则转移
      JB/JNB    低于/不低于则转移
      JBE/JNBE   低于等于/高于则转移
      JL/JNL    小于/不小于则转移
      JLE/JNLE   小于等于/大于则转移
      JCXZ     CX为零则转移

     ⑶ 循环指令
      LOOP      循环
      LOOPZ/LOOPE  为零/相等时循环
      LOOPNZ/LOOPNE 不为零/不等时循环

      ⑷ 子程序调用与返回
      CALL      调用
      RET       返回

      ⑸ 中断及中断返回
      INT       中断
      INTO      溢出则中断
      IRET       中断返回


  程序中指令的执行顺序是由CS:IP来决定的,程序转移类指令可改变IP或CS、IP的内容,从而控制指令的执行顺序,实现指令转移、程序调用等功能。

 

  1 无条件转移指令

 JMP指令控制程序无条件地跳转到目的单元,使用JMP指令可有三种格式:

 ⑴ JMP SHORT label 短转移(short jump)
   
 ⑵ JMP NEAR PTR label 近转移(near jump)

 ● JMP label 直接转移(direct jump)
  
 ● JMP reg 寄存器间接转移(register indirect jump)
  
 ● JMP WORD PTR OPR 存储器间接转移(memory indirect jump)
  
 ⑶ JMP FAR PTR label 远转移(far jump)

  短转移的目标地址(或称转向地址)相对于当前IP值的位移量在-128至+127字节之间,当前IP值是指JMP指令的下一条指令的地址(如图3.11所示)。对短转移JMP,机器指令的第一个字节为操作码EB,第二个字节为位移量00~FF,这是一个带符号的补码数。转向地址的计算方法为:(IP)当前+8位位移量。操作符SHORT指示汇编程序将JMP指令汇编成一个2字节指令。


  ⑴ JMP SHORT label 短转移(short jump)
    执行操作:(IP) ← (IP)当前+8位位移量

  短转移示意图
  [汇编]8086指令系统---控制转移指令_第1张图片

  ⑵ JMP NEAR PTR label 近转移(near jump)
  近转移是JMP指令的缺省格式,可以写为"JMP label"。它可在当前代码段内转移,机器指令的操作码是E9,位移量是16位的带符号补码数。指令中的转向地址可以是直接寻址方式、寄存器寻址方式、寄存器间接方式和存储器寻址方式。

  ● JMP label 直接转移(direct jump)
  执行操作:(IP) ← OFFSET label = (IP)当前+16位位移量
  转移的目标地址在指令中可直接使用符号地址,由于位移量为16位,它的转移范围应是-32768至+32767,也就是说,近转移指令可以转移到段内的任一个位置。

  ● JMP reg 寄存器间接转移(register indirect jump)
  执行操作:(IP) ← (reg)
  转移的目标地址在寄存器中,例如指令"JMP BX"执行的结果,将BX的内容送给IP。

  ● JMP WORD PTR OPR 存储器间接转移(memory indirect jump)
  执行操作:(IP) ← (PA+1,PA)
  存储器的物理地址PA由指令中的寻址方式确定,JMP指令执行的结果,把PA单元的字内容送到IP寄存器中。例如"JMP WORD PTR [DI]",物理地址PA = (DS)×24+(DI),指令执行的结果是(IP)= (PA+1,PA)。

  ⑶ JMP FAR PTR label 远转移(far jump)
  执行操作:(IP) ← label的段内偏移地址
       (CS) ← label所在段的段地址
  远转移实现的是段间的跳转,即从当前代码段跳转到另一个代码段中,这意味着指令执行后,不仅要改变IP的值,CS也会得到一个新的段地址。在汇编指令中,远转移的目标地址也可以使用除立即寻址方式外的任何寻址方式来表示。
 
  2 条件转移指令(conditional jump)

  条件转移指令是在满足了规定的条件后才控制程序转移的一类指令,8086的条件转移指令总结在表3.4中。

  所有条件转移指令都是短转移指令,转移的目标地址必须在当前IP地址的-128至+127字节范围之内,因此条件转移指令是2字节指令。

  计算转向地址的方法和无条件短转移指令是一样的,看例3.40的反汇编代码。

  例3.40程序中的"JNZ AGAIN"汇编成"JNZ 000D",000D是标号AGAIN的地址,指令"JNZ 000D"的机器代码是75FA,75是操作码,FA是位移量。当CPU读取JNZ指令后,IP寄存器自动加2(JNZ的指令长度)指向了下一条指令(MOV),此时IP的当前值是0013。计算转向地址时,(IP)当前+位移量 = 0013+FA = 0013+FFFA = 000D,这正是AGAIN的偏移地址。实际上FA是-6的补码,8位的FA与16位的0013相加时,FA符号扩展成为FFFA,相加的加结果为000D。
            表3.4 条件转移指令
分类
指 令
转 移 条 件
说 明
(Ⅰ)
JZ/JE
ZF=1
为零/相等, 则转移
JNZ/JNE
ZF=0
不为零/不相等, 则转移
JS
SF=1
为负, 则转移
JNS
SF=0
为正, 则转移
JO
OF=1
溢出, 则转移
JNO
OF=0
不溢出, 则转移
JP
PF=1
奇偶位为1, 则转移
JNP
PF=0
奇偶位为0, 则转移
JC
CF=1
进位位为1, 则转移
JNC
CF=0
进位位为0, 则转移
(Ⅱ)
JB/JNAE/JC
CF=1
低于/不高于等于, 则转移
JNB/JAE/JNC
CF=0
不低于/高于等于, 则转移
JBE/JNA
(CF [汇编]8086指令系统---控制转移指令(一) ZF)=1
低于等于/不高于, 则转移
JNBE/JA
(CF [汇编]8086指令系统---控制转移指令(一) ZF)=0
不低于等于/高于, 则转移
(Ⅲ)
JL/JNGE
(SF [汇编]8086指令系统---控制转移指令(一) OF)=1
小于/不大于等于, 则转移
JNL/JGE
(SF [汇编]8086指令系统---控制转移指令(一) OF)=0
不小于/大于等于, 则转移
JLE/JNG
((SF [汇编]8086指令系统---控制转移指令(一) OF) [汇编]8086指令系统---控制转移指令(一) ZF)=1
小于等于/不大于, 则转移
JNLE/JG
((SF [汇编]8086指令系统---控制转移指令(一) OF) [汇编]8086指令系统---控制转移指令(一) ZF)=0
不小于等于/大于, 则转移
(Ⅳ)
JCXZ
(CX)=0
CX的内容为0, 则转移

注: (Ⅰ)根据条件码的值转移 (Ⅱ)比较两个无符号数,根据比较的结果转移
(Ⅲ)比较两个带符号数,根据比较的结果转移 (Ⅳ)根据CX寄存器的值转移

 

  

       1050:0000  B86610    MOV AX,1040
    1050:0003  8ED8     MOV DS,AX
    1050:0005  B90500    MOV CX,0005
    1050:0008  BB0000    MOV BX,0000
    1050:000D  0207 AGAIN: ADD AL,[BX]
    1050:000F  43      INC BX
    1050:0010  49      DEC CX
    1050:0011  75FA     JNZ 000D
    1050:0013  A20500    MOV [0005],AL
    1050:0016  B44C     MOV AH,4C
    1050:0018  CD21     INT 21

  假设程序进行两个带符号数的比较,并根据比较结果转移,其中(AL)=80H,(BL)=01,请指出下面两组指令的转向地址。

  ⑴ CMP AL,BL     ⑵ CMP AL,BL
    JL XY         JB XY  

  答:⑴ 转向目标地址XY;⑵不能实现转移。
    执行CMP指令时,(AL)-(BL)=80-01=7F,条件码设置为:SF=0,OF=1,CF=0。执行JL指令时,测试转移条件:SF[汇编]8086指令系统---控制转移指令(一)OF = 0 [汇编]8086指令系统---控制转移指令(一)1 =1,说明满足(AL)<(BL)的转移条件,因此,(IP)←XY的偏移地址,程序即转移到XY单元执行新的指令。

  JB指令的转移条件为CF=1,而CMP的执行结果使CF=0,所以不能引起转移。

 

[汇编]8086指令系统---控制转移指令(二)

 

3 循环指令

  这一组指令在循环结构的程序中用来控制一段程序(称为循环体)的重复执行,在汇编指令中循环的转向地址用标号来表示,而在机器指令中给出的是位移量,所以执行循环指令时,若满足循环条件,CPU就计算转向地址:(IP)当前+8位位移量→(IP),即实现循环。

  若不满足循环条件,即退出循环,程序继续顺序执行。
  循环指令都是短转移格式的指令,也就是说,位移量是用8位带符号数来表示的,转向地址在相对于当前IP值的-128 ~ +127字节范围之内。

  对条件循环指令LOOPZ(LOOPE)和LOOPNZ(LOOPNE),除测试CX中的循环次数外,还将ZF的值作为循环的必要条件,因此,要注意将条件循环指令紧接在形成ZF的指令之后。

  在多重循环的程序结构中,如果各层循环都使用循环指令来控制,则应注意对CX中循环计数值的保存与恢复。
循环指令均不影响条件码。

  LOOP  label    循环(loop)
  执行操作:① (CX)←(CX)-1
       ② 若(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束

  LOOPZ/LOOPE label 为零/相等时循环(loop while zero,or equal)
  执行操作:① (CX)←(CX)-1
       ② 若ZF=1且(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束

  LOOPNZ/LOOPNE label 不为零/不等时循环(loop while nonzero,or not equal)
  执行操作:① (CX)←(CX)-1
       ② 若ZF=0且(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束

    例 编写程序,实现两个数据块BLOCK1和BLOCK2相加,结果存入BLOCK2。
       DATA   SEGMENT
       BLOCK1   DW   100 DUP(?)
       BLOCK2   DW   100 DUP(?)
       DATA  ENDS
       ; - - - - - - - - - - - - - - - - - -
       CODE   SEGMENT
       ASSUME CS:CODE,DS:DATA,ES:DATA
    START:MOV   AX,DATA
       MOV   DS,AX        ; initialize the data segment
       MOV   ES,AX        ; initialize the extra segment
       CLD             ; DF=0 for autoincrement
       MOV   CX,100        ; load the counter
       MOV   SI,OFFSET BLOCK1  ; address of block1
       MOV   DI,OFFSET BLOCK2  ; address of block2
    NEXT: LODSW            ; load the data of block1 into AX
       ADD   AX,ES:[DI]     ; add the data of block2 to AX
       STOSW            ; store the sum to block2
       LOOP   NEXT        ; repeat 100 times
       MOV   AX,4C00H      ; return to DOS
       INT   21H
    CODE  ENDS
       END   START

   4 子程序调用与返回指令

  子程序是一种非常重要的计算机编程结构,它存储在存储器中,可供一个或多个调用程序(主程序)反复调用。主程序调用子程序时使用CALL指令,由子程序返回主程序时使用RET指令。由于调用程序和子程序可以在同一个代码段中,也可以在不同的代码段中,因此,CALL指令和RET指令也有近调用、近返回及远调用、远返回两类格式。

 ⑴ CALL NEAR PTR SUBPROUT 近调用(near call)
  近调用是CALL指令的缺省格式,可以写为"CALL subrotine"。它调用同一个代码段内的子程序(子过程),因此,在调用过程中不用改变CS的值,只需将子程序的地址存入IP寄存器。CALL指令中的调用地址可以用直接和间接两种寻址方式表示。

 ⑵ CALL FAR PTR SUBPROUT 远调用(far call)
  远调用适用于调用程序(也称为主程序)和子程序不在同一段中的情况,所以也叫做段间调用。和近调用指令一样,远调用指令中的寻址方式也可用直接方式和间接方式。

 ⑶ RET 返回指令(return)
  RET指令执行的操作是把保存在堆栈中的返回地址出栈,以完成从子程序返回到调用程序的功能。

  ● CALL SUBROUT 段内直接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← (IP)当前+16位位移量(在指令的第2、3个字节中)
  
  ● CALL DESTIN 段内间接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← (EA) ; (EA)为指令寻址方式所确定的有效地址

  ● CALL FAR PTR SUBROUT 段间直接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (CS)当前
         (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← 偏移地址(在指令的第2、3个字节中)
         (CS) ← 段地址(在指令的第4、5个字节中)

  ● CALL WORD PTR DESTIN 段间间接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (CS)当前
         (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← (EA) ; (EA)为指令寻址方式所确定的有效地址
         (CS) ← (EA+2)

  从CALL指令执行的操作可以看出,第一步是把子程序返回调用程序的地址保存在堆栈中。对段内调用,只需将IP的当前值,即CALL指令的下一条指令的地址存入SP所指示的堆栈字单元中。对段间调用,保存返回地址则意味着要将CS和IP的当前值分别存入堆栈的两个字单元中。

  CALL指令的第二步操作是转子程序,即把子程序的入口地址交给IP(段内调用)或CS:IP(段间调用)。对段内直接方式,调转的位移量,即子程序的入口地址和返回地址之间的差值就在机器指令的2、3字节中。对段间直接方式,子程序的偏移地址和段地址就在操作码之后的两个字中。对间接方式,子程序的入口地址就从寻址方式所确定的有效地址中获得。

  ● RET 段内返回(近返回)
  执行操作:(IP) ← ((SP)),(SP) ← (SP)+2

  ● RET 段间返回(远返回)
  执行操作:(IP) ← ((SP)),(SP) ← (SP)+2
       (CS) ←((SP)),(SP) ← (SP)+2

  ● RET N 带立即数返回
  执行操作:① 返回地址出栈(操作同段内或段间返回)
       ② 修改堆栈指针:(SP) ← (SP)+N

  子程序的最后一条指令必须是RET指令,以返回到主程序。如果是段内返回,只需把保存在堆栈中的偏移地址出栈存入IP即可,如果是段间返回,则要把偏移地址和段地址都从堆栈中取出送到IP和CS寄存器中。

  带立即数返回指令,除完成偏移地址出栈或偏移地址和段地址出栈的操作外,还要再使SP的内容加上一个立即数N,使堆栈指针SP移动到新的位置。指令中的N可以是一个常数,也可以是一个表达式。带立即数返回指令适用于C或PASCAL的调用规则,这些规则在调用过程(子程序)前先把参数压入堆栈,子程序使用这些参数后,如果在返回时丢弃这些已无用的参数,就在RET指令中包含一个数字,它表示压入到堆栈中参数的字节数,这样堆栈指针就恢复到参数入栈前的值。

  CALL指令和RET指令都不影响条件码。

    根据下面调用程序和子程序的程序清单,画出RET指令执行前和执行后的堆栈情况。假设初始的SS:SP=A000:1000。
 
    0000  B8 001E   MOV  AX,30
    0003  BB 0028   MOV  BX,40
    0006  50      PUSH AX     ; push data1 into stack
    0007  53      PUSH BX     ; push data2 into stack
    0008  E8 0066   CALL ADDM    ; call subroutine
    000B  B4 02    MOV  AH,2
    …   …      …
    0071  ADDM     PROC NEAR  ; entry point (IP)←0071=000b+0066
    0071  55      PUSH BP     ; save BP
    0072  8B E4    MOV  BP,SP    ; addressing the stack with BP
    0074  8B 46 04  MOV  AX,[BP+4] ; get data2 from stack
    0077  03 46 06   ADD  AX,[BP+6] ; add data1
    007A  CD      POP  BP     ; get back BP
    007B  C2      0004 RET 4   ; return and revert SP
    007E  ADDM     ENDP

 
图 CALL指令和RET指令对堆栈的影响

 

[汇编]8086指令系统---控制转移指令_第2张图片

  如图3.12所示,主程序中的两条PUSH指令将数据30和40压入堆栈,CALL指令执行后,返回地址000B又压入堆栈,紧接着程序控制转移到子程序ADDM。子程序中的PUSH指令又使BP的值进栈,此时SP指向栈顶0FFA。MOV指令将0FFA传送给BP,使BP作为寻址堆栈数据的指针。(BP+4)指向的是40,(BP+6)指向的是30,取出数据后用POP指令恢复了BP原先的值,此时,(SP)=0FFC,这是RET 4指令执行前的堆栈状态。

  执行RET 4指令时,先使返回地址出栈:(IP)←000B,(SP)←0FFC+2=0FFD,然后,(SP)+4=0FFD+4=1000,结果使SP跳过了堆栈数据而回到了原始位置。

  5 中断及中断返回指令

 INT n 中断指令(interrupt),n为中断类型号

 IRET 中断返回指令(return from interrupt)

 INTO 溢出则中断(中断类型为4)

  INT n 中断指令(interrupt),n为中断类型号
  执行操作:① 入栈保存FLAGS:(SP) ← (SP)-2,((SP)) ← (FLAGS)
       ② 入栈保存返回地址:(SP) ← (SP)-2,((SP)) ← (CS)
                  (SP) ← (SP)-2,((SP)) ← (IP)
       ③ 转中断处理程序:(IP) ← (n×4)
                 (CS) ← (n×4+2)


  IRET 中断返回指令(return from interrupt)
  执行操作:① 返回地址出栈:(IP) ← ((SP)),(SP) ← (SP)+2
                (CS) ← ((SP)),(SP) ← (SP)+2
       ② FLAGS出栈:(FLAGS) ← ((SP)),(SP) ← (SP)+2

  INTO 溢出则中断(中断类型为4)
  执行操作:若OF=1(有溢出),则:
       ① 入栈保存FLAGS:(SP) ← (SP)-2,((SP)) ← (FLAGS)
       ② 入栈保存返回地址:(SP) ← (SP)-2,((SP)) ← (CS)
                  (SP) ← (SP)-2,((SP)) ← (IP)
       ③ 转中断处理程序:(IP) ← (4×4)= (10H)
                 (CS) ← (4×4+2)= (12H)

  中断指令用于调用中断例行程序(又称中断服务程序),这是一种远调用。完成各种功能的中断例行程序都有一个编号,称为中断类型号。各种中断例行程序的入口地址按中断类型号的顺序存储在一个表中,这个表称为中断向量表。每个中断例行程序的入口地址占用4个字节,因此,它在中断向量表中的地址可用中断类型号乘4来求得。执行中断指令时,首先要入栈保存调用程序执行的现场,即当时的标志寄存器的值和断点的地址,然后,根据中断类型号(n×4)到中断向量表中取得中断例行程序的入口地址,分别送给IP和CS,以实现调用中断例行程序的功能。

  中断返回指令IRET的操作和INT指令相反,即从堆栈中取出返回地址和标志位,然后返回到被中断的程序。
INTO指令隐含的中断类型号为4,因此保存断点地址和标志位后,从中断向量表的10H和12H两个字中取出中断例行程序的入口地址,从而转去运行中断例行程序。

  INT指令(包括INTO)执行后,把IF和TF置0,但不影响其它标志位。

 

  6 处理机控制指令

  处理机控制指令包括一组置0或置1标志位的指令,还有一些控制处理机状态的指令。

 
  6.1 标志位处理指令

  这一组指令分别对标志位CF、DF、IF执行置0、置1或求反的操作,如,CLD指令执行的操作是:DF←0;STD执行的操作是:DF←1。

  标志位处理指令只影响本指令指定的标志,而不影响其它标志位。

    ⑴ 标志位处理指令      ⑵ 处理机控制指令
      CLC CF置0          NOP 无操作
      STC CF置1          HLT 停机
      CMC CF求反          WAIT 等待
      CLD DF置0          ESC 转义
      STD DF置1          LOCK 封锁
      CLI IF置0
      STI IF置1

 

  6.2 处理机控制指令

  NOP 无操作指令(no operation)

  HLT 停机指令(halt)

  WAIT 等待指令(wait)

  ESC mem 转义指令(escape)

  LOCK前缀封锁(lock)

  NOP 无操作指令(no operation)
  执行操作:不执行任何操作,其机器码占用1个字节单元,执行时间为3个时钟周期,因此,该指令的作用表现在时间和空间上。时间上它可使上下两条指令的执行有一点间隔,这使某些指令的执行,特别是控制硬件接口的指令因为有一点延时而增加可靠性。空间上它的位置可在调试指令时用其它指令来代替。

  HLT 停机指令(halt)
  执行操作:使处理机停止软件的执行并等待一次外部中断的到来,中断结束后处理机继续执行下面的程序。使用该指令的目的通常是为了保持外部硬件中断与软件系统的同步。

  WAIT 等待指令(wait)
  执行操作:测试微处理器的BUSY/TEST管脚,如果执行WAIT指令时,BUSY/TEST=1(指示不忙),则继续执行下一条指令。如果执行WAIT指令时,BUSY/TEST=0(指示忙),则微处理器等待直到BUSY/TEST管脚变为1。
  
  ESC mem 转义指令(escape)
  执行操作:mem指定存储单元,执行ESC指令时,从存储器取得指令或操作数通过总线送给8087~80387数值协处理器。协处理器能处理算术运算、函数运算、对数运算等数值运算,其运算速度比使用常规指令写的软件快的多。

  LOCK前缀 封锁(lock)
  执行操作:指令前加LOCK,使得在锁定指令期间保持锁存信号LOCK=0,以禁止外部总线上的主控制器或系统其它部件。例如,LOCK MOV AL,[SI]执行时,总线封锁直至MOV指令执行完毕。

 

  【小结】

   
1、8086寻址方式

  寻址方式
    操作数地址(PA)
   指令格式举例
  立即寻址
操作数在指令中给出
MOV DX,100H ; (DX)←100H
  寄存器寻址
操作数在寄存器中
ADD AX,BX ; (AX)←(AX)+(BX)
  直接寻址
操作数的有效地址由指令直接给出
MOV AX,[100] ; (AX)←(100)
MOV AX,VAR ; (AX)←(VAR)
  寄存器
  间接寻址
PA=(DS)×16+(BX)或(SI)或(DI)
PA=(SS) ×16+(BP)
MOV AX,[BX] ;
(AX)←((DS)×16+(BX))
  寄存器
  相对寻址
PA=(DS)×16+(BX)或(SI)或(DI)+位移量
PA=(SS) ×16+(BP)+位移量
MOV AL,MESS[SI];
(AL)←((DS)×16+(SI)+OFFSET MESS)
  基址变址
  寻址
PA=(DS)×16+(BX)+(SI)或(DI)
PA=(SS) ×16+(BP) +(SI)或(DI)
MOV AX,[BX+DI];
(AX)←((DS)×16+(BX)+(DI))
  相对基址
  变址寻址
PA=(DS)×16+(BX)+(SI)或(DI)+位移量
PA=(SS) ×16+(BP) +(SI)或(DI)+位移量
MOV AX,BUFF(BX+DI);
(AX)←((DS)×16+(BX)+(DI)+OFFSET BUFF)

   2、8086指令系统
   学习一条指令时,要注意以下几个方面:
   (1) 指令功能--该指令能实现何种操作,通常指令助记符就是指令功能的英文缩写词。
   (2) 指令支持的寻址方式--指令中的源操作数和目的操作数字段允许采用的寻址方式。
   (3) 指令对标志位的影响--该指令执行后对各个标志位的影响。
   (4) 指令的特殊要求--该指令隐含使用或限定使用的寄存器以及需要预置的参数。
 



你可能感兴趣的:(8086,控制转移指令)