可以修改IP,或同时修改CS和IP的指令统称为转移指令,即转移指令就是可以控制CPU执行内存中某处代码的指令
8086的转移行为有以下几类:
只修改IP时,称为段内转移,比如:jmp ax
同时修改CS和IP时,称为段间转移,比如:jmp 1000:0
由于转移指令对IP的修改范围不同,段内转移又分为:短转移和近转移
短转移:IP的修改范围为-128~127
近转移:IP的修改范围为-32768~32767
9.1 操作符 offset
操作符offset在汇编语言中是由编译器所处理的符号,它的功能是取得标号的偏移地址
如:
assume cs:code
code segment
start:mov ax,offset start ;相当于mov ax,0
s:mov ax,offset s ;相当于mov ax,3
code ends
end start
offset取得了标号start和s的偏移地址0和3
因为start是代码段中的标号,它所标记的指令是代码段中的第一条指令,所以偏移地址为0
s是代码段中的标号,它所标记的是第二条指令,第一条指令长度为3个字节,则s的偏移地址为3
9.2 jmp指令
jmp为无条件转移指令,可以只修改IP,也可同时修改CS和IP
jmp要给出的信息:
1,转移的目的地址
2,转移的距离(段间距离,段内短转移,段内近转移)
9.3 依据位移进行转移的jmp指令
jmp short 标号(转到标号处执行指令)
这种格式的jmp指令实现的是段内短转移,它对IP的修改范围为-128~127,即可以向前转移最多128个字节,向后最多越过127个字节。
jmp指令中的 short 符号,说明进行的是短转移,jmp指令中的 标号 是代码段中的标号,指明了指令要转移的目的地,指令转移结束后,CS:IP应该指向标号处的指令
CPU在执行jmp指令时并不需要转移的目的地址,jmp short 标号并不包含转移的目的地址,而包含的是转移的位移,这个位移,是汇编器根据汇编指令中的 标号 计算出来的
实际上,jmp short 标号 的功能为 IP = IP + 8位位移
1,8位位移 = 标号处的地址 - jmp指令后的第一个字节的地址
2,short表明此处的位移为8位位移
3,8位位移的范围为-128~127,用补码表示
3,8位位移由编译器在编译时算出
类似于jmp short 标号 功能的 jmp near ptr 标号,它实现的是段内近转移
near ptr指明位移为16位位移,范围为-32768~32767
9.4 转移的目的地址在指令中的jmp指令
jmp far ptr 标号 实现的是段间转移,又称为远转移
far ptr 指明了指令用标号的段地址和偏移地址修改了CS和IP
9.5 转移地址在寄存器中的jmp指令
指令格式:jmp 16位reg
功能:IP = (16位reg)
jmp某一合法寄存器指令的功能:用寄存器中的值修改IP
9.6 转移地址在内存中的jmp指令
转移地址在内存中的jmp指令有两种格式:
1,jmp word ptr 内存单元地址(段内转移)
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址
如:
mov ax,0123h
mov ds:[0],ax
jmp word ptr ds:[0]
执行后,(IP) = 0123h
2,jmp dword ptr 内存单元地址(段间转移)
功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址
如:
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
9.7 jcxz 指令
jcxz指令位 有条件转移指令,所有的条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址,对IP的修改范围都是-128~127
指令格式:jcxz 标号 (如果(cx) = 0,则转移到标号处执行)
操作:当cx = 0,IP=IP+8位位移
jcxz的功能用c叙述相当于:
if((cx) == 0) {
jmp short 标号;
}
9.8 loop 指令
loop指令为循环指令,所有的循环指令都是 短转移
指令格式: loop 标号 ((cx) =(cx) -1,如果(cx)不等于0,则转移到标号处执行)
操作:1,(cx) = (cx) -1
2,如果(cx)不等于0,(IP) = (IP) +8位位移
loop的功能用c叙述相当于:
(cx)--;
if((cx) != 0) {
jmp short 标号
}
9.9 根据位移进行转移的意义
对于
jmp short 标号
jmp near ptr 标号
jcxz 标号
loop 标号
等集中汇编指令,它们对IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的,在它们对应的机器码中不包含转移的目的地址,而包含的是目的地址的位移
这种设计,方便了程序段在内存中的 浮动装配
如:
mov cx,6
mov ax,10h
s:add ax,ax
loop s
这段程序在内存的不同位置都可以正确执行,因为loop s在执行时只涉及s的位移(此处为-4,向前4个字节),而不是s的地址,如果loop的机器码中包含的是s的地址,则就对程序段在内存中的偏移地址有了严格的限制,因为机器码中包含的是s的地址,如果s处的指令不在目的地址处,程序的执行就会出错
如果只指明转移的位移,就不存在该问题了,无论s处的指令的实际地址为多少,loop指令的转移位移是不变的
9.10 编译器对转移位移超界的检测
根据位移进行转移的指令,它们的转移范围受到转移位移的限制,如果在源程序中出现了转移范围超界的问题,编译时编译器将报错
start:jmp short s
db 128 dup(0)
s:mov ax,0ffffh
jmp short s的转移范围为-128~127,IP最多向后移动127字节,上述程序会报错
在debug中使用过的形如 jmp 2000:0100的转移指令,是属于debug的汇编指令,汇编编译器masm并不认识,如果在源程序中使用,编译时也会报错
实验9
转自:https://me.csdn.net/eagleatustb
assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!'
datasg ends
color segment
db 00000010B ;黑底绿字
db 00100100B ;绿底红字
db 01110001B ;白底蓝字
color ends
stack segment
dw 0,0,0,0, 0,0,0,0
stack ends
codesg segment
start:
mov ax,stack
mov ss,ax
mov sp,10H
mov ax,color
mov ds,ax
mov bx,2
mov cx,3
colorpush:
mov al,0
mov ah,[bx]
push ax
sub bx,1
loop colorpush
;计算第一个输出位置
mov bx,1824
mov ax,0B800H
mov ds,ax
mov ax,datasg
mov es,ax
mov cx,3
outputloop:
mov si,0
mov di,cx
pop dx;取得输出颜色
mov cx,16
outputline:;向输出位置输出数据
mov dl,es:[si]
mov [bx],dx;字符+属性
;计算下一个输出位置
inc si
add bx,2
loop outputline
mov cx,di
add bx,128
loop outputloop
mov ax,4c00H
int 21H
codesg ends
end start