汇编语言笔记9转移指令的原理

汇编语言笔记9转移指令的原理

0x00 转移指令的类型

可以修改ip或者同时修改cs和ip的指令统称为转移指令

​ 8086cpu的转移指令有以下几类:

​ (1)只修改ip的 比如段内转移,jmp ax

​ (2)同时修改cs和ip 称为段间转移 比如 jmp 1000:0

​ 由于转移指令对ip的修改范围不同,段内转移又分为:短转移和近转移

​ (1)短转移ip的修改范围-128-127(相对)

​ (2)近转移修改范围-32768-32767

​ 8086cpu转移指令分为以下几类:

​ (1)无条件转移指令 jmp

​ (2)条件转移指令 jcxz

​ (3)循环指令

​ (4)过程

​ (5)中断

0x01 操作符offset

​ offset是伪指令,由编译器处理,他的功能是取得标号的偏移地址比如:

assume cs:code
code segment
start:	mov ax,offset start
s:		mov ax,offset s
code ends
end start

​ 在上面程序中 offset取得了start和s的偏移地址 分别是0和3(和所在指令偏移地址相同)

QQ截图20200601094939

assume cs:code
code segment
s:		mov ax,bx
		mov si,offset s
		mov di,offset s0
		mov ax,cs:[si]
		mov cs:[di],ax
s0:		nop
		nop
code ends
end start

QQ截图20200601095332

​ 上述代码运行正确

0x02 jmp指令深入

​ jmp指令为无条件转移指令,可以只修改ip,也可以同时修改cs和ip

​ jmp指令要给出两种信息:(1)转移的目的地址 (2)转移的距离

​ 不同的给出目的地址的方法和不同的转移位置,对应由不同格式的jmp指令

保存相对地址的jmp指令

jmp short 标号 这种格式的jmp指令实现的是段内短转移,它对ip的相对修改范围为-128-127

assume cs:code
code segment
start:	mov ax,0
		jmp short s
		add ax,1
s:		inc ax
code ends
end start

QQ截图20200601100143

对其机器码进行分析 jmp short s 中并没有s标号的偏移地址08h 是eb03h,原因在于它实际上只保存了相对的地址03h为什么相对地址会是03h呢?因为当执行到jmp这句时,ip已经指向了下一条语句add ax,1了 而这条语句的偏移地址是05h,与要跳转的08h只相差03h

jmp near ptr 标号 类似 不过修改的相对范围是-32768-32767 同样是保存的16为的相对修改地址而不是偏移地址

保存目的地址的jmp指令

jmp far ptr 标号 实现的是段间的转移,又称远转移,其修改cs为标号所在段的地址 修改ip为标号所在段的偏移地址

assume cs:code
code segment
start:	mov ax,0
		jmp far ptr s
		db 256 dup (0)
s:		add ax,1
		inc ax
code ends
end start

QQ截图20200601101313

​ 通过对应的机器码可以知道保存的是标号的物理地址

转移地址在寄存器中的jmp指令

jmp 16位reg 直接修改ip位寄存器中的内容

转移地址在内存中的jmp指令

​ (1)jmp word ptr 内存单元地址(段内转移) 修改ip为内存单元的内容

​ (2)jmp dword ptr 内存单元地址 (段间转移) 同时修改cs和ip 内存单元的高字节对应cs 地直接对应ip

QQ截图20200601102027

​ jmp word ptr [..]指令只修改ip因此要想指向第一条指令,即ip要为0 那么[bx+1]对应的 ds:[1]这个字节要为0

​ 因此data 区 db 0,0即可

QQ截图20200601102306

​ 要使cs:ip指向第一条程序 那么ds:[0] 这个字应该是 ip 0000h ds:[2]这个字对应的是cs 但是我们没有cs 只知道ds 那么 我们知道 cs=ds+1 (因为data区不满16字节 所以填充到16),那么 我们可以让 ds:[2]为ds ds:[0]为 10h 这样物理地址也是一样的

​ 所以答案是

QQ截图20200601085718

​ 该程序运行正确,这里就不放截图了

0x03 jcxz指令

​ jcxz是有条件转移指令 ,所有有条件转移指令都是短转移,机器码中只包含相对位移,不是目的地址

jcxz 标号 如果cx=0就转移到标号执行 否则就不跳转继续执行下面的

QQ截图20200601103114

QQ截图20200601103126

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

QQ截图20200601103733

​ 2000:0h处的数据设置

QQ截图20200601103802

​ 运行结果正确

0x04 loop指令

loop 标号 作用 在执行到loop时 cx先自减1 再判断cx是否为0 不为零跳转到标号,为0不跳转执行下面的代码

​ 所有的循环指令都是短转移,对应的机器码只包含相对位移,不包含目的地址

QQ截图20200601104148

QQ截图20200601104200

假如 2000:0处是1 那么到横线之前cl为1 cx为1 如果横线处不补充代码,那么loop前cx为1 到loop时cx先减一 cx为0 就跳转到了ok 这样bx就为0 认为2000:0处 是第一个0,而实际上为1 所以呢 横线处应该让cx加一 所以是 inc cx

0x05 为什么使用相对位移以及跳转越界检测

QQ截图20200601104710

​ 简单来说使用先对位移是为了代码的可移植性和鲁棒性

QQ截图20200601104748

​ 注意 jmp 2000:0没有这种写法 我们可以 jmp dword ptr [bx] 让ds指向2000 bx指向0 这样才可以