一、基础

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。

JMP 数据分析 jmp数据分析做CPK_talkingdata

四、转移的目的地址在指令中的用法

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

JMP 数据分析 jmp数据分析做CPK_IP_02