第9章 转义指令
# 第9章 转移指令
==转移指令:可以修改 IP,或同时修改 CS 和 IP 的指令统称为转移指令。==
概括而言,转移指令就是可以控制 CPU 执行内存中某处代码的指令。
8086CPU 的转移行为有以下几类:
- 只修改 IP 时,称为段内转移,比如:
jmp ax。 - 同时修改 CS 和 IP 时,称为段间转移,比如:
jmp 1000 : 0。
根据转移指令对 IP 的修改范围可分为短转移和近转移:
- 短转移 IP 的修改范围:-128~127
- 近转移 IP 的修改范围:-32768~32767
8086CPU 的转移指令分为以下几类:
- 无条件转移指令(如:jmp)
- 条件转移指令
- 循环指令(如:loop)
- 过程
- 中断
# 9.1 操作符 offset
功能:取得标号的偏移地址
assume cs:codesg
codesg segment
start:mov ax,offset start ;相当于 mov ax,0
s:mov ax,offset s ;相当于 mov ax,3
codesg ends
end start
2
3
4
5
6
上图的案例:取得标号 start 和 s 的偏移地址为 0 和 3
# 9.2 根据位移进行转移的 jmp 指令
jmp 为五条件转移指令,可以只修改 IP,也可以同时修改 CS 和 IP 。
jmp 指令要给出两种信息:
- 转移的目的地址
- 转移的距离(段间转移、段内短转移,段内近转移)
段内短转移格式:jmp short 标号(转到标号处执行指令)
jmp short 标号指令不包含转移的目的地址,而包含转移的位移。这个位移时根据 ”标号“ 计算出来的。
实际上,jmp short 标号的功能为:(IP)=(IP)+8位位移
- 8位位移 = 标号处的地址 - jmp 指令后的第一个字节的地址;
- short 指明此处的位移为 8 位位移;
- 8位位移的范围为 -128~127,用补码表示
- 8位位移由编译程序在编译时算出
assume cs:codesg
codesg segment
start:mov ax,0
jmp short s
add ax,1
s:inc ax
codesg ends
end start
2
3
4
5
6
7
8
程序执行后,ax 中的值为1,因为执行 jmp short s 后,越过了 add ax,1,IP 指向了标号 s 处的 inc ax。
jmp near ptr 标号 与 jmp short 标号 功能相近,它实现的是段内近转移。
jmp near ptr 标号的功能为:(IP)=(IP)+16位位移
- 16位位移 = 标号处的地址 - jmp 指令后的第一个字节的地址;
- near ptr 指明此处的位移为 16 位位移,进行的是段内近转移;
- 16位位移的范围为 -32768~32767,用补码表示
- 16位位移由编译程序在编译时算出
# 9.3 转移的 目的地址 在指令中的 jmp 指令
jmp 指令对应的机器指令没有转移的 目的地址,而是相对于当前 IP 的转移位移。
"jmp far ptr 标号"实现的是段间转移,又称为远转移。功能如下:
- (CS)= 标号所在段的段地址;
- (IP) = 标号在段中的偏移地址。
assume cs:codesg
codesg segment
start:mov ax,0
jmp far ptr s
db 256 dup(0)
s: add ax,1
inc ax
codesg ends
end start
2
3
4
5
6
7
8
9
将跳转到 CS:IP 所在的地址
# 9.4 转移指令在寄存器中的 jmp 指令
指令格式:jmp 16 位 reg
功能:(IP)=(16位 reg)
# 9.5 转移指令在内存中 jmp 指令
(1)jmp word ptr 内存单元地址(段内转移)
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
内存单元地址可用寻址方式的任一格式给出
mov ax,0123H
mov ds:[0],ax
jmp word ptr ds:[0]
执行后,(IP)= 0123H
比如:
mov ax,0123H
mov [bx],ax
jmp word ptr [bx]
执行后,(IP)= 0123H
2
3
4
5
6
7
8
9
(2)jmp dword ptr 内存单元地址(段间转移)
功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。
- (CS)=(内存单元地址+2)
- (IP)=(内存单元地址)
内存单元地址可用寻址方式的任一格式给出
mov ax,0123H
mov ds:[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]
执行后,(cs)= 0,(IP)= 0123H,CS:IP 指向 0000:0123
比如:
mov ax,0123H
mov [bx],ax
mov word ptr [bx+2],0
jmp dword ptr [bx]
执行后,(cs)= 0,(IP)= 0123H,CS:IP 指向 0000:0123
2
3
4
5
6
7
8
9
10
11
12
# 9.6 jcxz 指令
jcxz 指令为有条件转移指令,所有的有条件转移指令都是短转移,对应的机器码中包含转移的位移而不是目的地址。对 IP 的修改范围都为:-128 ~ 127
- 指令格式:jcxz 标号(如果(cx)= 0,转移到标号处执行)
- 操作:当(cx) = 0 时,(IP)= (IP)+8位位移;
- 8位位移 = 标号处的地址 - jcxz指令后的第一个字节的地址;
- 8位位移由编译程序在编译时算出。
- 当(cx)不等于0时,什么也不做,程序向下执行
- jcxz 标号相当于
if((cx) == 0),jmp short 标号;
# 补全编程,利用 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 star
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 9.7 loop 指令
loop指令为循环指令,所有的循环指令都是短转移,对应的机器码中包含转移的位移,而不是目的地址。对 IP 的修改范围都为:-128 ~ 127。
指令格式:loop 标号 ((cx) = (cx) - 1),如果 (cx) ≠ 0,转移到标号处执行。
操作:
- (cx)=(cx)-1;
- 如果(cx)≠ 0,(IP)=(IP)+ 8位位移。
- 8位位移 = 标号处的地址 - loop 指令后的第一个字节的地址;
- 8位位移的范围为 -128~127,用补码表示;
- 8位位移由编译程序在编译时算出。
如果(cx)= 0,什么也不做(程序向下执行)。
loop 标号相当于
(cx)--; if((cx) ≠ 0 jmp short 标号);
;************************************************************************
;利用 loop 指令,实现在内存 2000H 段中查找第一个值为零的 byte,找到后
;将它的偏移地址存储到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 # 当cx为0,然后加一
inc bx
loop s # 这边会减一,然后当cx等于0 就会直接跳到下一步ok
ok:
dec bx
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23