一、基础
1、可以修改IP,或同时修改CS和IP的指令称为转移指令。
2、8086CPU的转移 行为分为段内转移(只修改IP) 和 段间转移(同时修改CS和IP)。
3、段内转移分为短转移(IP修改范围-128~127) 和 近转移(IP修改范围-32768~32767)。
4、CPU转移指令分为:
①无条件转移指令(jmp)
②条件转移指令
③循环指令(loop)
④过程
⑤中断
二、操作符offset
1、offset是操作符,而不是一个指令,它是用来取得标号的偏移地址。
assume cs:codesg
codesg segment
start:mov ax,offset start #相当于 mov ax,0
s:mov ax,offset s #上面一条指令是3个字节,所以相当于 mov ax,3
codesg ends
end start
2、offset操作符取得的标号是相对于代码段的偏移地址,其段地址是CS。
三、依据位移进行转移的jmp指令
1、jmp short 标号(转到标号处执行指令)
2、上述的格式是使用jmp实现段内短转移,对IP修改范围是-128~127。指令中的short符号说明指令进行的是短转移。标号指明了指令要转移的目的地。
3、指令的实现原理:
assume cs:codesg
codesg segment IP: 指令对应的机器码
start:mov ax,0 0000: B800000
jmp short s 0003: EB03 #jmp 0008
add ax,1 0005: 050100
s:inc ax 0008: 40
codesg ends
end start
assume cs:codesg
codesg segment IP: 指令对应的机器码
start:mov ax,0 0000: B800000
mov bx,0 0003: BB0000
jmp short s 0006: EB03 #jmp 000B
add ax,1 0008: 050100
s:inc ax 000B: 40
codesg ends
end start
可以从上面两个代码中可以看出,jmp指令跳转到不同地址,但是都用了一个机器码EB03,这说明CPU在执行jmp指令的时候并不需要转移的目的地址。
CPU指令执行过程是:
①从CS:IP指向的内存空间取指令放入指令缓冲器。
②IP根据拿到的几个字节的指令进行自加。
③执行指令,然后再回到①重复进行。
分析第二个代码:
①IP = 0006H(准备执行jmp short s),从内存空间取出EB 03指令放入缓冲器。
②IP = 0006H + 2 = 0008H,CS:IP 指向 add ax,1
③执行EB 03代码,执行完成后,IP变成了 000BH
分析:
找规律:0008H 加3 变成了000BH,与EB03中的03对应。
想法:这里的03并不是给IP的绝对地址,而是给IP加上的一个值。
类比代码一:代码一中把EB03放入缓冲器后,IP变成了0005,执行后变成了0008,也是相差03,所以上述想法也满足代码一。
结论:jmp short 标号
指令对应的机器码中,并不包含转移的目的地地址,而是包含了转移的位移,即对当前的IP值加上一个位移值。short指明的是位移值的位数,这里的short表示位移值的位数是8位,支持-128~127,用补码表示。jmp near ptr 标号
实现的是段内近转移,转移值的位数是16。
四、转移的目的地址在指令中的用法
1、jmp far ptr 标号
实现的是段间转移(远转移),CS和IP变更为指令中携带的地址。
2、far ptr 指明了指令用标号的段地址和偏移地址修改CS和IP。
assume cs:codesg
codesg segment
start:mov ax,0 0000:B80000
mov bx,0 0003:BB0000
jmp far ptr s 0006:EA 0B01 BD08
db 256 dup(0) 000B:0000 #注意,这是条伪指令,在编译阶段完成,目的是在这个地方生成256个字节的空间,内容都是0。
s:add ax,1 #偏移地址是010BH,计算方法是000BH+256 = 010BH
inc ax
codesg ends
end start
jmp指令对应的机器码是 EA 0B01 BD08,0B01对应的是偏移地址IP(010BH),对应代码中s标号代码处的偏移地址;BD08对应的是段地址CS(08BD)。
五、转移地址在内存中
1、jmp word ptr 内存单元地址
:段内转移,只更改IP的值,直接更改成内存里的值。
mov ax,0123h
mov ds:[0],ax
jmp word ptr ds:[0]
执行后 (IP)=0123H
2、jmp dword ptr 内存单元地址
:段间转移,同时更改CS和IP,高地址的字是段地址,低地址是偏移地址
mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]
执行后,(CS)=0,(IP)=0123h
六、jcxz
1、jcxz 标号
是条件转移指令,段内的段转移,转移范围是-128~127。
2、当(CX)==0时,执行跳转,目的是标号所在位置。若不是,则执行下一条指令。
3、jcxz指令的机器码所携带的是8位位移地址,而非绝对地址,其由编译器在编译时算出。
4、其功能类似于
if((cx) == 0)
jmp short 标号;
5、利用jcxz,实现在内存2000H段中查找第一个值为0的字节,将其偏移地址放到dx中。
assume cs:code
code segment
start:mov ax,2000H
mov ds,ax
mov bx,0
s:mov ch,0
mov cl,[bx]
jcxz ok
inc bx ;这个要放到jcxz后面,因为ok后没有程序自减
jmp short s
ok:mov dx,bx
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
七、loop指令
1、loop 标号
指令实现的是段内短转移,范围是-128~127。
2、执行loop时:
①首先(CX)=(CX)-1
②如果(CX)==0,不跳转,执行下一条。如果(CX)≠0,跳转到目标标号。
3、其功能类似于
(cx)--;
if( (cx) != 0 )
jmp short 标号;
八、总结
1、利用相对位移作为转移地址的指令:
①jmp short 标号
:段内近转移,机器码包含8位的相对转移地址
②jmp near 标号
:段内远转移,机器码包含16位的相对转移地址
③jcxz 标号
: 段内近转移,机器码包含8位的相对转移地址,条件转移。
④loop 标号
: 段内近转移,机器码包含8位的相对转移地址,循环指令。
注意: 它们对IP的修改是根据 转移目的地址 和 转移起始地址 之间的位移来进行的,在编译阶段完成(其不包含绝对地址,包含的是到目标地址的位移)
2、包含转移的绝对地址的指令:
①jmp far ptr 标号
:段间转移,机器码共5字节,高4字节是标号的绝对地址,包含了段地址和IP的值。
②jmp cs:ip
:转移到CS:IP这个绝对地址,机器码5个字节,高4字节是标号的绝对地址,低2位是IP,高2位是CS,与①情况同。
3、机器码只和寄存器或者内存地址有关,和转移目标地址无关:
①jmp ax
:段内转移,只修改IP,机器码只有两个字节,只与寄存器有关系,与寄存器里面的值无关。
②jmp word ptr 内存单元地址
:从内存单元中拿数据来跳转,段内转移,只修改IP。机器码有4个字节,只和内存地址有关系,和内存地址里的值没有关系。2字节的内存偏移地址(ds是段地址)在机器码中。
③jmp dword ptr 内存单元地址
:从内存单元中拿数据来跳转,同时修改CS和IP,机器码还是4个字节,只与内存地址有关系,包含了两个字节的内存偏移地址。
注意:②和③都是从内存中取跳转地址,他们的机器码长度都是4字节,②的前两个字节是26ff,③的是2eff,后面两个字节都是内存中的地址。
疑问:在debug中直接敲程序,jmp word ptr [0]
和 jmp dword ptr[0]
生成的机器码都是26ff开头的,执行结果也是只修改IP。只有使用编译器时这两个才像上面那样分开!
4、编译器会对转移位移超界进行检测
assume cs:code
code segment
start:jmp short s
db 128 dup(0) ;最多偏移127
s:mov ax,0ffffh
code ends
end start