0%

8086指令基础 - 控制转移类指令

最近在学习 16位汇编编程,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习汇编开发的童鞋们提供一份参考。

运行环境:

  • 操作系统: Windows 10家庭版
  • 编译器:Windows XP Debug

控制转移类指令

控制转移类指令用于实现分支、循环、过程等程序结构,是仅次于传送指令的最常用指令

重点掌握:JMP、JCC、LOOP、CALL、RET、INT n、IRET常用系统功能调用

一般了解:LOOPZ、LOOPNZ INTO

控制转移类指令通过改变IP(和CS)值,实现程序执行顺序的改变

JMP 无条件转移指令

  • 只要执行无条件转移指令jmp,就使得程序转到指定的目标地址处,从目标地址处开始执行指令
  • 操作数是要转移到的目标地址
  • JMP指令分为四种类型:
    • 段内转移、直接寻址
    • 段内转移、间接寻址
    • 段间转移、直接寻址
    • 段间转移、间接寻址

位移量是紧接着JMP指令后的那条指令的偏移地址,到目标指令的偏移地址的地址位移;当向地址增大方向转移时,位移量为正;向地址减小方向转移时,位移量为负

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Code segment
start:
;设置数据段
mov ax,Data
mov ds,ax
mov es,ax
;设置堆栈段
jmp LABEL1 ;段内短转移 段内近转移
mov ax,MyStack
jmp ax
jmp [2000h] ;jmp内存
mov ss,ax

LABEL1:
mov ah,09
mov dx,offset MYMSG
int 21h
;退出
mov ax,4c00h
int 21h
Code ends
end start

寻址方式

  • 直接寻址方式

    • 转移地址像立即数一样,直接在指令的机器代码中,就是直接寻址;使用标号表达
  • 间接寻址方式

    • 转移地址在寄存器或主存单元中,就是通过寄存器或存储器的间接寻址方式;用寄存器或存储器表达

目标地址范围

段内

  • 段内转移 - 近转移(near)
    • 在当前代码段64KB范围内转移(+-32范围)
    • 不需要改变CS段地址,只要改变IP偏移地址
1
JMP label   ;IP←IP+位移量
  • 段内转移 - 短转移(short)
    • 转移范围可以用一个字节表达,在段内-128~+127范围
1
JMP r16/m16     ;IP←r16/m16

段间

  • 段间转移 - 远转移(far)
    • 从当前代码段跳转到另一个代码段,可以在1MB范围
    • 需要更改CS段地址和IP偏移地址
    • 目的地址必须用一个32位数表达,叫做32位远指针,它就是逻辑地址
1
2
3
4
5
JMP far ptr label
;IP←label的偏移地址
;CS←label的段地址
JMP far ptr mem
;IP←[mem],CS←[mem+2]

1.**实际编程时,汇编程序会根据目标地址的距离,自动处理成短转移、近转移或远转移**
2.**程序员可用操作符short、near ptr 或far ptr** 强制

条件转移指令

在指令手册中我们可以看到所有的JCC指令

1
2
3
jcc label:
;条件满足,发生转移,IP<-ip + 8位位移量
;条件不满足,顺序执行
  • 指定的条件CC如果成立,程序转移到由标号lable指定的目的地址去执行指令;条件不成立,则程序将顺序执行下一条指令
  • 操作数label是采用短转移,成为相对寻址方式

Tables Are
Z/E 相等
N
S 符号
P 奇偶
O 溢出
C 进位
L 小于(有符号数)
G 大于(有符号数)
A 高于(无符号数)
B 低于(无符号数)
  • 判断单个标志位状态

    • 这组指令单独判断5个状态标志之一
      ⑴JZ/JE和JNZ/JNE:利用零标志ZF,判断结果是否为零(或相等)
      ⑵JS和JNS:利用符号标志SF,判断结果是正是负
      ⑶JO和JNO:利用溢出标志OF,判断结果是否产生溢出
      ⑷JP/JPE和JNP/JPO:利用奇偶标志PF,判断结果中“1”的个数是偶是奇
      ⑸JC/JB/JNAE和JNC/JNB/JAE:利用进位标志CF,判断结果是否进位或借位
  • 比较无符号数高低

    • 无符号数的大小用高(Above)低(Below)表示
      利用CF确定高低、利用ZF标志确定相等(Equal)
      两数的高低分成4种关系:
      ⑴ 低于(不高于等于):JB(JNAE)
      ⑵ 不低于(高于等于):JNB(JAE)
      ⑶ 低于等于(不高于):JBE(JNA)
      ⑷ 不低于等于(高于):JNBE(JA )
  • 比较有符号数大小

    • 有符号数的大(Greater)小(Less)需要组合OF、SF标志,并利用ZF标志确定相等(Equal)
      两数的大小分成4种关系:
      ⑴ 小于(不大于等于):JL(JNGE)
      ⑵ 不小于(大于等于):JNL(JGE)
      ⑶ 小于等于(不大于):JLE(JNG)
      ⑷ 不小于等于(大于):JNLE(JG )

计算器CX为0转移

1
2
3
JCXZ label
;CX=0,发生转移:IP←IP+8位位移量
;CX≠0,顺序执行

这是一条较特殊的指令
CX寄存器通常在程序中用做计数器
JCXZ指令用来判断计数是否为0

循环指令

1
2
3
4
5
6
LOOP label  ;CX←CX-1,
;CX≠0,循环到标号label
LOOPZ label ;CX←CX-1,
;CX≠0且ZF=1,循环到标号label
LOOPNZ label ;CX←CX-1,
;CX≠0且ZF=0,循环到标号label

demo:

1
2
3
4
5
6
7
8
9
10
        mov cx,count    ;设置循环次数
mov si,offset string
xor bx,bx ;bx清0,用于记录空格数
mov al,20h
again: cmp al,es:[si]
jnz next ;ZF=0,非空格,转移
inc bx ;ZF=1,是空格,个数加1
next: inc si
loop again
;字符个数减1,不为0继续循环