microcomputer_principle_07_程序控制指令
Carpe Tu Black Whistle

程序控制指令

  • 程序控制类指令的本质是:
    • 控制程序的执行方向
  • 决定程序执行方向的因素:
    • CS, IP

修改IP,会使程序改变在当前代码段中执行的顺序**
同时修改CS和IP,会使程序走向另一个代码段执行


这两个寄存器的值,不能被随便修改。可以作为源操作数,但是一般不能作为目标操作数存在。

程序控制类指令以“隐含”的方式修改CS和IP,以实现控制程序走向的目的(Intel指令集不允许由指令直接修改CS和IP)

通过修改IP或CS和IP,实现程序的三种基本控制结构

  • 顺序,选择(分支),循环

学习程序控制类指令,需要重点关注: 如何实现对CS和IP的修改


  • 转移指令
  • 循环控制
  • 过程调用
  • 中断控制

转移指令

通过修改指令的偏移地址段地址及偏移地址实现程序的转移

  • 无条件转移指令 –> 无条件转移到目标地址
  • 条件转移指令 –> 当具备 一定条件时 转移到目标地址
    (通常指状态标志位)

无条件转移指令

  • format:
    • JMP OPRD

可以实现在当前代码段内或段间转移

JMP

  1. 无条件段内转移
  • 转移的 目标地址 在当前代码段内,段地址不改变。
  • 目标地址是16位偏移地址。
    • 指令中直接给出目标地址->段内直接转移
    • 指令中的 寄存器或存储器 操作数指出目标地址->段内间接转移

段内转移

段内直接转移

  • 转移目标地址由指令直接给出
  • format:
    • JMP Label -> 标号起名:不超过32字符,首字母不是数字

标号最好有具体含义,JMP与Label间无说明->近地址标号

JMP会计算IP与Label之间的位移量
下一条要执行指令的偏移地址=IP+位移量

段内间接转移

  • 段内间接转移
    • 转移的目标地址存放在某个16位寄存器或存储器的某两个单元
  • e.g.
    • MOV BX, 1200H
    • JMP BX
  • 执行完上述指令后:
    • IP=1200H
1
2
MOV BX, 1200
JMP WORD PTR[BX]

JMP2

段间转移

  • 转移的 目标地址 不在当前代码段内。
  • 目标地址 为32位,包括段地址和偏移地址。
    (目标地址->指令中直接给出->段间直接转移
    (指令中32bit存储器操作数指出目标地址–>段间间接转移

段间间接转移

  • 段间间接寻址
    • 转移的目标地址由指令中的32bit操作数给出
    • 32bit目标地址须存放于内存中

32位操作数/地址,低位IP高位CS

  • e.g.
    • JMP DWORD PTR[BX]

JMP

JMP3

  • e.g.

    1
    2
    3
    4
    5
    MOV SI, 1122H
    MOV WORD PTR[SI], 0120H
    ADD SI, 2
    MOV WORD PTR[SI], 0122H
    JMP WORD PTR[SI]

    以上为段内转移
    JMP4

  • e.g.

    1
    2
    3
    4
    5
    MOV SI, 1122H
    MOV WORD PTR[SI], 0120H
    ADD SI, 2
    MOV WORD PTR[SI], 0122H
    JMP DWORD PTR[SI-2]

    JMP5

跳转后CS:0122H IP:0120H

条件转移指令

  • 在满足一定条件下,程序转移到目标地址继续执行
  • 条件转移指令均为段内短转移,即转移范围为:
    -128 ——> +127

基于1个标志为状态

  • JC/JNC
    • 判断CF的状态。常用于两个无符号数大小比较
  • JZ/JNZ
    • 判断ZF的状态。常用于循环体的结束判断
  • JO/JNO
    • 判断OF的状态。常用于有符号数溢出的判断
  • JP/JPE、JNP/JPO
    • 判断PF的状态。用于判断运算结果低8位中1的个数是否位偶数
  • JS/JNS
    • 判断SF的状态。常用于判读数的性质

基于2or3标志位状态

  • JA/JAE/JB/JBE
    • 判断CF或CF+ZF的状态。常用于无符号数大小的比较。
  • JG/JGE/JL/JLE
    • 判断SF+OF或SF+OF+ZF的状态。常用于有符号数大小的比较

基于CX内容转移的指令

  • JCXZ
    • 可根据指令执行后CX的结果实现转移

条件转移例

  • 统计内存数据段中以TABLE为首地址的100个8bit带符号数中,正数、负数和零元数的个数。
  • 基本思路:
    • 可先将存放统计值的单元(或寄存器)清零
    • 读取一个数,通过标志位的状态判断数的性质
      • 最高位为1,则为负数
      • 最高位为0,则为正数或零

不改变数本身,影响标志位(获得数的性质)
对自身使用and和or操作来,实现标志位flag的获取

instruct flow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
START:  XOR AL, AL
MOV PLUS, AL ; 3个MOV指令,用于清零存储器
MOV MINUS, AL
MOV ZERO, AL
LEA SI, TABLE
MOV CX, 100
CLD

CHECK: LODSB ; 将SI中的字节,取入AL
OR AL, AL
JS X1 ; 判断是否为负
JZ X2 ; 判断是否为0
INC PLUS
JMP NEXT

X1: INC MINUS
JMP NEXT

X2: INC ZERO

NEXT: DEC CX
JNZ CHECK
HLT

循环控制指令

  • 循环范围:
    • 以当前IP为中心的-128~+127范围内循环。
  • 循环次数由CX寄存器指定。
  • 循环指令:
    • LOOP –> 无条件循环指令

  • LOOPZ
  • LOOPNZ
    (条件循环指令)

无条件循环指令

  • format:
    • LOOP LABEL
  • loop requirement:
    • CX0
  • manipulation,相当于:
    1
    2
    DEC CX
    JNZ LABEL(LOOP)

条件循环指令

  • function:
    • 先使CX-1,再根据CX中的值及ZF值来决定是否继续循环
  • format:
    • LOOPZ Label –> 继续循环条件:CX0,且ZF=1
    • LOOPNZ Label –> 继续循环的条件:CX0,且ZF=0

循环例

  • 在以DATA为首地址的内存数据段中,存放由200个16bit有符号数,试找出其中最大和最小的符号数,并分别放在MAX和MIN为首的内存单元中。

  • 题目分析:

    • 先取数据块中第1个数,将其同时暂存于MAX和MIN中;
    • 循环读取其它数,并分别与MAX和MIN中的数进行比较
      • 若大于,则取代原MAX中的数;
      • 若小于MIN,则取代MIN
  • NOTE: 有符号数比较,应该采用JG和JL等用于符号数的条件转移指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
START:  LEA SI, DATA
MOV CX, 200
CLD
LODSW
MOV MAX, AX
MOV MIN, AX
DEC CX

NEXT: LODSW
CMP AX, MAX
JG LARGE
CMP AX, MIN
JL SMALL
JMP GOON

LARGE: MOV MAX AX
JMP GOON;

SMALL: MOV MIN, AX

GOON: LOOP NEXT

过程调用

  • 过程调用指令
    • 用于调用一个子过程
  • 与转移指令的比较
    • 子过程执行结束后要返回原调用处
      • 必须保护返回地址

call

入口地址: 子程序第一条指令,在内存中的存放处
断点:调用指令的下一条指令的地址

执行过程

  1. 保护断点
  • 将调用指令的下一条指令的地址(断点)压入堆栈
  1. 获取子过程的入口地址
  • 子过程第1条指令的地址
  1. 执行子过程 –> 程序员编写
  • 功能实现,参数的保存及恢复
  1. 恢复断点,返回原程序。
  • 将断点偏移地址由堆栈弹出

断点保护和恢复由系统自动完成,但会影响堆栈的栈顶指针

call category

段内调用

  • 被调用程序与调用程序在同一代码段
    • 调用前,只需保护断点的偏移地址
  1. CALL TIMER –> 直接调用
  2. CALL WORD PTR[SI] –> 间接调用
    (间接调用: 子程序的入口地址在内存中)

call in segment

段间调用

  • 子过程与原调用程序不在同一代码段
    • –> 调用前需保护断点的段基地址和偏移地址
  • 先将断点的CS压栈,再压入IP。
  • e.g.
    1
    2
    CALL FAR TIMER    ;调用名为TIMER的远过程 
    CALL DWORD PTR[SI];32位存储器操作数,表示远过程调用

返回

  • func:
    • 从堆栈中弹出断点地址,返回原程序
  • format:
    • RET (stand for return)

子程序的最后一条指令必须是RET

中断控制指令

程序控制的最后一段指令

中断概念

某种异常或随机事件使处理器暂时停止正在运行的程序,转去执行一段特殊处理程序,并在处理结束后返回源程序被中断处继续执行的过程。

中断概念中间,所谓 事件 叫做 中断源

中断指令:

  • 引起CPU产生一次中断的指令

中断与过程调用:

  • 相似点:

    • 从一个正在执行的过程转向另一个过程(程序处理),并在执行完后返回原程序继续执行
  • 区别:

    • 中断是随机事件或异常事件引起,调用是事先已在程序中安排好;
    • 调用指令在指令中,直接给出子程序入口地址,中断指令只给出中断向量码,入口地址则在向量码指向的内存单元中。
    • 调用可以是近过程调用或源过程调用,中断处理程序均为远过程;
    • 响应中断请求不仅要保护断点地址,还要保护FLAGS内容。
  • format:
    INT n (0~255)

  • explanation:

    • n*4 –> 存放中断服务子程序入口地址的单元的偏移地址

n4

执行过程

  1. 将FLAGS压入堆栈;
  2. 将INT指令的下一条指令的CS、IP压栈;
  3. 由n4得到存放中断向量的地址;
  4. 将中断向量(中断服务程序入口地址)送CS和IP 寄存器;
    (以上过程,全部由硬件系统完成)
  5. 转入中断服务程序。 –> 软件工程师实现

执行INT指令之后,SP-2压入FLAGS保护

image

SP-2 将断点的段基地址入栈

image

SP-2 将断点偏移地址入栈

image

以上为自动化实现过程


找入口

进行n4的运算,然后指向中断向量表

n4位置和n4+1为IP地址,n4+2和n4+3存储CS地址

中断指令程序例

1
2
3
4
CS      IP
6200H: 010DH MOV SP, 1200H
6200H: 0110H INT 21H
6200H: 0112H MOV AX, BX

image

  • 执行INT 21H 指令后
    • IP=[21H*4]
    • CS=[(21H*4)+2]

image

  • format:
    • IRET
  • 中断服务程序的最后一条指令,负责:
    • 恢复断点
    • 恢复标志寄存器内容