本篇主要介绍 8086CPU 的转移指令。

转移指令

修改 IP 或 同时修改 CS 和 IP 的指令称为转移指令。也就是说转移指令是能控制 CPU 执行内存中某处代码的指令。

8086CPU 转移行为分类:

  • 只修改 IP ,称为段内转移,例如:jmp ax

    根据转移指令对 IP 修改范围,段内转移又可以分为:

    • 短转移:修改范围为 -128 ~ 127,2^7 = 128
      • 近转移:修改范围为 -32768 ~ 32767,2^15 = 32768
  • 同时修改 CS 和 IP ,称为段间转移,例如:jmp 1000:0

依据位移进行转移的 jmp 指令

jmp short 标号(转到标号处执行指令)

  • 8 位位移 = “标号”处的地址 - jmp 指令后的第一个字节的地址
  • short 指明此处的位移为 8 位位移
  • 8 位位移的范围为 -128 ~ 127 ,用补码表示
  • 8 位位移由编译程序在编译时算出

jmp near ptr 标号 16 位位移

例如下面的程序:

assume cs:codesg
codesg segment
start: mov ax,0 ;长度为3
jmp short s ;长度为2
add ax,1 ;长度为3
s: inc ax ;长度为1
mov ax,4c00h
int 21H
codesg ends
end start

当程序执行完后 ax 中的内容为 1 ,因为执行 jmp short s 后跳过了 add ax,1。从 debug (下图所示)中可以清楚的看到 jmp short s 直接由编译器编译成了 jmp 0008。来验证一下上面的计算方法 “8 位位移 = “标号”处的地址 - jmp 指令后的第一个字节的地址”,标号处的偏移地址为 8(3+2+3) ,jmp 指令后的第一个字节的地址为 5(3+2),即 8 位位移为 3,也就是下图中 jmp 处对应的机器码 EB03 中的 03。

3
3

我们在上面的 jmp 指令前后各加一条指令再来验证下,代码如下:

assume cs:codesg
codesg segment
start: mov ax,0 ;长度为3
mov bx,0 ;长度为3
jmp short s ;长度为2
add ax,1 ;长度为3
add ax,1 ;长度为3
s: inc ax ;长度为1
mov ax,4c00h
int 21H
codesg ends
end start

标号处的偏移地址为 14,jmp 指令后的第一个字节的地址为 8,则 8 位位移为 6。如下图所示。

4
4

“jmp near ptr 标号” 和 “jmp short 标号” 的功能相近,实现的段内近转移,它的功能为:

  • 16 位位移 = “标号”处的地址 - jmp 指令后的第一个字节的地址
  • near ptr 指明此处的位移为 16 位位移
  • 16 位位移的范围为 -32768 ~ 32767 ,用补码表示
  • 16 位位移由编译程序在编译时算出

转移的目的地址在指令中的 jmp 指令

“jmp far ptr 标号” 实现的是段间转移,也称为远转移,功能如下:

  • (CS)= 标号处所在段的段地址
  • (IP)= 标号在段中的偏移地址

far ptr 表明了指令用标号段的段地址和偏移地址来同时修改 CS 和 IP。代码如下所示:

assume cs:codesg
codesg segment
start: mov ax,0
mov bx,0
jmp far ptr s
db 256 dup (0)
s: add ax,1
inc ax
mov ax,4c00h
int 21H
codesg ends
end start

在 debug 中能够清楚的看到 jmp far ptr s 要跳转的段地址和偏移地址

5
5

转移地址在内存中的 jmp 指令

转移地址在内存中的 jmp 指令有两种方式:

  • jmp word ptr 内存单元地址(段内转移)
  • jmp dword ptr 内存单元地址(段间转移)

“jmp word ptr 内存单元地址” 的功能是从内存单元地址开始处存放着一个字,是转移的偏移地址。

“jmp dword ptr 内存单元地址” 的功能是从内存单元地址开始处存放着两个字节,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。

jcxz 指令

jcxz 是条件转移指令,指令格式为:jcxz 标号(如果 cx 的值为 0,跳到标号处执行),所有的条件转移指令都是短转移。

loop 指令

loop 指令为循环指令,指令格式为:loop 标号 (如果 cx 的值为不为 0 ,跳到标号处执行),所有的循环指令都是短转移。