第九章
可以修改IP或者同时修改CS和IP的指令统称为转移指令
只修改IP的为段内转移,如:jmp ax
同时修改CS和IP的为段间转移,如:jmp 1000:0
段内转移又分为:短转移和近转移
短转移IP的修改范围为-128~127
近转IP的修改范围为-32768~32767
8086转移指令分类
· 无条件转移指令(如:jmp)
· 条件转移指令
· 循环指令(如:loop)
· 过程
· 中断
9.1 操作符offset
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
有如下程序段,将该程序中s处的一条指令复制到s0处
assume cs:codesg
codesg segment
s: mov ax,bx ; 机器码占两个字节
mov si,offset s
mov di,offset s0
mov ax,cs:[si]
mov cs:[di],ax
s0: nop
nop ; nop的机器码占两个字节
codesg ends
end s
9.2 jmp指令
jmp指令要给出两种信息
1、转移的目的地址
2、转移的距离
不同的方法有不同的jmp格式
9.3 依据位移进行转移的jmp指令
jmp short 标号(转到标号处执行指令)
这种格式实现段内短转移,对IP的修改范围为-128~127
如下程序,ax只进行了一次加1操作
assume cs:codesg
codesg segment
start: mov ax,0
jmp short s
add ax,1
s: inc ax
codesg ends
end start
一般的汇编指令中,立即数都会在对应的机器指令中出现,但是将上述代码翻译成机器语言,发现 jmp short s对应的机器码为EB03,修改程序
assume cs:codesg
codesg segment
start: mov ax,0
mov bx,0
jmp short s
add ax,1
s: inc ax
codesg ends
end start
修改后s的偏移地址与之前的位置不同,但 jmp short s对应的机器码仍然为EB03,结论是CPU在执行jmp指令的时候并不需要转移的目的地址,至于为什么是EB 03,因为当前地址为CS:0008H,目标地址为CS:000BH,所以将IP值加3就是目标指令,因为这两个程序jmp指令转移的位移相同,所以都为EB 03
因此 jmp short 标号指令所对应的机器码中,并不包含转移的目的地址,而包含转移的位移,是编译器根据汇编指令中的标号计算出来的
注意计算位移的方法,因为读取了jmp指令后,IP会指向下一条指令,所以位移是下一条指令地址与目标指令地址的差
该位移为8位,补码表示(所以范围为-128~127)
对应的 jmp near ptr实现段内近转移
位移为16位(范围-32768~32767)
9.4 转移的目的地址在指令中的jmp指令
jmp far ptr 标号实现段间转移,又称为远转移
far ptr指明了用标号的段地址和偏移地址修改CS和IP
(CS)=标号所在段的段地址 (IP)=标号在段中的偏移地址
9.5 转移地址在寄存器中的jmp指令
格式 jmp 16位reg
(IP)=(16位reg)
9.6 转移地址在内存中的jmp指令
jmp word ptr 内存单元地址(段内转移)
某内存单元地址处存放着一个字,是转移的目的偏移地址
内存单元地址可用寻址方式的任一格式给出
jmp word ptr ds:[0]
jmp word ptr [bx]
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
补全程序,使jmp指令执行后,CS:IP指向程序的第一条指令
assume 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],word ptr 0或mov [bx],offset start
mov [bx+2],cs ; mov [bx+2],code
jmp dword ptr ds:[0]
code ends
end start
9.7 jcxz指令
jcxz指令为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,对IP的修改范围是-128~127
格式:jcxz 标号(如果(cx)=0,转移到标号处执行)
当(cx) != 0,什么也不做,程序向下执行
功能等价于 if ((cx) == 0) jmp short 标号;
补全编程,利用jczx指令,实现在内存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
9.8 loop指令
所有的循环指令都是短转移,对应的机器码中包含转移的位移,对IP的修改范围是-128~127
指令格式 loop 标号((cx)=(cx)=1,如果(cx) != 0,转移到标号处执行)
等价于
(cx)–
if ((cx) != 0) jmp short 标号;
补全编程,利用jczx指令,实现在内存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 ; loop s处cx也会减一,因此如果cx为0,loop执行后
inc bx ; cx为-1,不能正常退出循环,因此先再加1
loop s
ok: dec bx ; dec效果与inc相反,自减
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
9.9 根据位移进行转移的意义
方便程序段在内存中的浮动装配,如
mov cx,6
mov ax,10h
s: add ax,ax
loop s
这段程序在内存的不同位置都可正确执行,无论s处的指令的实际地址是多少,loop指令的转移位移是不变的
9.10 编译器对转移位移超界的检测
assume cs:code
code segment
start: jmp short s
db 128 dup (0)
s: mov ax,0ffffh
code ends
end start
jmp short s的转移范围是-128~127,IP最多向后移动127个字节
在Debug中使用的指令如"jmp 2000:0100"的转移指令,编译时会报错,不能在源程序中使用