汇编09:转移指令的原理
转移指令的原理
可以修改IP,或同时修改CS和IP的指令统称为转移指令。
转移行为有很多种不同的分类方法:
根据只修改IP和同时修改CS和IP,可以分为段内转移(jmp ax)和段间转移(jmp 1000:0)
根据指令对IP的修改范围不同,段内转移又分为短转移(IP的修改范围为-128-127)和近转移(IP的修改范围-32768-32767)
8086CPU的转移指令分为以下几类:
1、无条件转移指令,如jmp
2、条件转移指令
3、循环指令,如loop
4、过程
5、中断
操作符offset
offset是一个伪指令,它的功能是取得标号的偏移地址,如:
assume cs:codesg
codesg segment
start: mov ax,offset start
s: mov ax,offset s
codesg ends
end start
第三行语句中的offset start就相当于0,因为start标号的偏移地址为0;第四句中的offset s就相当于3,因为s标号的偏移地址为3,这是由于第一条指令长度为3个字节。
有了offset我们就可以方便的取到标号的偏移地址了,我们可以先设置一个标号中放入nop(占1个字节的机器码):
s0: nop
nop
然后再将其他标号s处的指令直接复制过去:
mov si,offset s
mov di,offset s0
mov ax,cs:[si]
mov cs:[di],ax
jmp指令
jmp为无条件转移指令,它要给出两种信息:要转移的目的地址,或者要转移的距离。
转到标号处执行指令
使用格式:
jmp short 标号
它实现的是段内短转移,对IP的修改范围为-128-127,也就是说它向前转移时最多可以越过128个字节,向后转移时可以最多越过127个字节,转移指令结束后,CS:IP应该指向标号处的指令。
值得注意的是,这个指令对应的机器码中是没有转移的目的地址的,而是包含转移的位移,编译器根据两点的距离计算出位移量,然后修改IP寄存器中的值,在编译结束后的机器指令中就包含转移位移了。相当于该指令的作用其实是(IP)=(IP)+8位位移。
对应的段内近转移指令:
jmp near ptr 标号
他对IP的修改范围为-32768-32767.相当于(IP)=(IP)+16位位移。
对应的远转移指令(段间转移):
jmp far ptr 标号
这个指令对应的机器码中就包含了转移的目的地址了。
使用内存地址和寄存器
jmp可以直接加16位reg:
jmp 16位reg
它的意思就是修改IP寄存器的值,修改为对应寄存器中的值。
jmp命令中也可以直接包含地址,它有两种形式:
1、只修改IP的段内转移:
jmp word ptr ds:[0]
相当于把对应地址的值赋值给IP寄存器,完成转移。
2、同时修改IP和CS的段间转移:
jmp dword ptr ds:[0]
从对应内存地址单元中取出两个字,低地址的那个字赋值给IP,高地址的那个字赋值给CS,完成转移。
jcxz指令
jcxz为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改都是-128-127.
使用格式:
jcxz 标号
相当于如果cx寄存器中的值是0,就执行:
jmp short 标号
loop指令
loop指令是循环指令,所有的循环指令都是短转移,基本使用用法:
loop 标号
相当于:
(cx)--
if((cx)!=0)jmp short 标号
关于转移位移的讨论
在上述段内转移指令中,我们可以发现这些指令对应的机器码中只有转移的相对位移,而不包含转移的目的地址,这种设计是为了方便程序段在内存中的浮动装配。
如果我们自定义的程序要直接引用某个写好的目标文件,这个文件内部的转移写成段内转移,这样就可以保证在连接时不会出错,不会因为该目的地址有其他内容而覆盖。
此外还要注意位移超界的问题,如果转移范围出现超界,编译器会报错。