1.可以修改 IP, 或通知修改 CS 和 IP 的指令 统称为 转移指令。
概括的讲,转移指令就是可以控制 CPU 执行内存中某处代码的指令。
8086CPU 的转移行为有一下几类:
- 只修改 IP 时, 称为段内转移, 比如: jmp ax
- 同时修改 CS 和 IP 时,称为段间转移,比如: jmp 1000:0
由于转移指令对 IP 的修改范围不同,段内转移又分为: 短转移 和 近转移
- 短转移 IP 的修改范围为 -128~127
- 近转移 IP 的修改范围 -3287~32767
8086CPU 的转移指令分为以下几类:
- 无条件转移指令(如: jmp)
- 条件转移指令
- 循环指令(如:loop)
- 过程
- 中断
2. 操作符 offset
offset在汇编语言中是由编译器处理的符号。他的功能是 取得标号的偏移地址。
// 将 start 处的第一条指令 复制到 s0处:
assume cs:codesg
codesg segment
start: mov ax,bx
mov si,offset start // 相当于 mov si,0
mov di,offset s0 // 相当于 mov di, s0代码段的首地址
mov ax,cs:[si]
mov cs:[di],ax
s0: nop // nop的机器码占一个字节
nop
mov ax,4c00H
int 21H
codesg ends
end start
3. jmp 指令
jmp 指令 为 无条件转移指令,可以只修改 IP,也可以同时修改 CS 和 IP。需要给出两种信息:
(1)转移的目的地址
(2)转移的距离(段间转移,段内短转移,段内近转移)
3. 依据位移进行转移的 jmp 指令
jmp short 标号 (转移到标号处执行指令)
这种格式的 jmp 指令实现的是 段内短转移,它对 IP 的修改范围为 -128~127,也就是说,它向前转移时最多越过 128 个字节,向后转移可以最多越过 127 个字节。
jmp指令中的"标号" 是 代码段中的标号, 指明了指令要转移的目的地,转移指令结束后, CS:IP 应该指向标号处的指令。
CPU在执行 jmp 指令的时候并不需要转移的目的地址。
”jmp short 标号“ 指令所对应的机器码中,并不包含转移目的地的地址,而是包含转移的位移。这个位移 是编译器根据汇编指令中的 ”标号“ 计算出来的。
实际上 ”jmp short 标号“ 的功能为: (IP) = (IP)+8位位移
(1) 8位位移 = 标号处的地址 - jump 指令后第一个字节的地址
(2)short 指明此处的位移位 8位位移
(3)8位位移的范围为 -128~127,用补码表示。
(4)8位位移由编译程序在编译时算出。实际上 ”jmp near ptr 标号“ 的功能为: (IP) = (IP)+16位位移
(1) 16位位移 = 标号处的地址 - jump 指令后第一个字节的地址
(2)near ptr 指明此处的位移位 16位位移, 进行的是段内近转移。
(3)16位位移的范围为 -32768~32787,用补码表示。
(4)16位位移由编译程序在编译时算出。-
实际上 ”jmp far ptr 标号“ 的功能为: 段间转移,又称远转移
far ptr 指明了用 标号的段地址 和 偏移地址 修改 CS 和 IP。
(1) 16位位移 = 标号处的地址 - jump 指令后第一个字节的地址
(2)near ptr 指明此处的位移位 16位位移, 进行的是段内近转移。
(3)16位位移的范围为 -32768~32787,用补码表示。
(4)16位位移由编译程序在编译时算出。
”jump16位 reg“ 的功能为: (IP)=(16位reg)
far ptr 指明了用 标号的段地址 和 偏移地址 修改 CS 和 IP。
(1) 16位位移 = 标号处的地址 - jump 指令后第一个字节的地址
(2)near ptr 指明此处的位移位 16位位移, 进行的是段内近转移。
(3)16位位移的范围为 -32768~32787,用补码表示。”jmp word ptr 内存单元地址“ 的功能为: 段内转移
从内存单元地址处开始存放着一个字,是转移的目的偏移地址。”jmp dword ptr 内存单元地址“ 的功能为: 段间转移
从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址, 低地址出是转移的目的偏移地址。
(CS)= (内存单元地址+2)
(IP)=(内存单元地址)
4. 练习
1.若要使程序中的jmp指令执行后,CS:IP指向程序的第一条指令,在data段中应该定义哪些数据?
assume ds:data,cs:code
data segment
db 2 dup (0)
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
jmp word ptr [bx+1]
mov ax,4c00h
int 21h
code ends
end start
2.补全程序,使得jmp指令执行后,CS:IP指向第一条指令
assume ds:data,cs:code
data segment
dd 12345678H
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov [bx],bx
mov [bx+2],code
jmp dword ptr ds:[0]
mov ax,4c00h
int 21h
code ends
end start
3.;内存数据如下
2000:1000 BE 00 06 00 00 00 ……
此时CPU执行指令
mov ax, 2000H
mov es, ax
jmp dword ptr es:[1000H]
后,(CS) = 0006H (IP) = 00BEH
5. jcxz 指令
指令格式: jcxz 标号 (如果 (cx)=0, 转移到标号处执行)
(1)操作: 当(cx)= 0 时,(IP)=(IP)+ 8位位移
(2)8位位移=标号处的地址-jcxz指令后的第一个字节的地址
(3)8位位移的范围为 -128~127,用补码表示
(4)8位位移由编译程序在编译时算出。
- 当 (cx)!= 0 时,什么也不做,程序继续执行
- jcxz 标号 = if (cx) == 0 jump short 标号
6. 练习
补全编程,利用jcxz指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。
assume cs:code
code segment
start: mov ax,2000H
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch,0
jcxz ok
inc bx
jmp short s
ok: mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
7. loop 指令
指令格式:loop 标号
操作:
(1)(cx)= (cx)+ 1
(2)如果(cx)!= 0, (IP)=(IP)+8 位位移
8. 练习
补全编程,利用loop指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。
assume cs:code
code segment
start: mov ax,2000H
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch,0
inc cx
inc bx
loop s
ok: dec bx
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
9. 根据位移进行转移的意义
jmp short 标号
jmp near ptr 标号
jcxz 标号
loop 标号
他们对IP的修改是根据 转移目的地址和转移起始地址之间的位移来进行。在它们对应的机器码中不包含转移的目的地址,而包含的是目的地之的位移。方便了程序段在内存中的浮动装备,无论目的地址如何变化,指令的转移位移是不变的。