在别的语言中,程序进行跳转被看作是一种逻辑上的漏洞,想必学习过C语言的人都有这种认识,就是最好不要在程序中出现GOTO这个指令,不过,跳转在汇编语言中却是一种很重要的语法,理解跳转指令才能更好的驾驭汇编。
1.jmp指令
jmp指令是无条件的跳转指令,jmp分为3种跳转模式,一种是短转移,一种是近转移,最后是远转移。首先介绍一下前两种跳转:
jmp short 标号 ;短转移,程序跳转到标号标注的地方,和C语言中的goto指令类似
jmp near prt 标号 ;近转移,和短转移类似
这两种跳转指令是不需要加上跳转的地址的,他们属于段内跳转指令,也就是说,他们只能改变IP的指向,而不改变CS的指向,他们跳转依靠的是位移,这是编译器在编译的时候处理的事情,编译器会将你的标号地址减去jmp指令的地址,计算出之间位移,然后在翻译成机器语言。位移为正就是向下跳转,位移为负就是向上跳转。short和near prt之间的差别就是short跳转的极限是2^7(8位位移),near的极限是2^15(16位位移)。
jmp far prt 标号 ;远转移,和短转移意思类似,只是细节不同
远转移,又称为段间转移,它不仅仅会修改IP指向,还会修改CS的指向,这个跳转的依据就是实实在在的地址。
那么,现在请思考为什么计算机会提供3种跳转模式,或者说,为什么要出现依靠位移的跳转指令,全部依靠绝对地址来跳转难道不好吗?
工程师绝对不会做出费力不讨好的事情,那么出现依靠位移的跳转指令就一定有他的优势存在,思考以下情形,程序在内存中运行之时是需要被加载的,这个加载到的内存地址是不确定的,也就是说在这种情况之下,我们的远转移指令很有可能找寻不到我们想要找寻的地址,那这时,相等地址(位移)的优势就体现出来了,我们可以依靠位移来精确定位这个段中任意一个地址(在内存中的浮动装配),而不需要具体的地址,但是这也引发了一个很奇怪的程序,我们最后再来介绍。
2.loop,jcxz指令
loop指令,顾名思义,就是循环指令,语法和jmp指令类似:
loop 标号 ;跳转到标号处
还记得前面介绍的CX寄存器吗,这里就是轮到他大显生手的地方了,loop指令是依靠CX的值来判断循环次数的,只要CX不为0,那么loop就执行跳转,那么loop指令用伪代码来描述就是:
if(CX != 0) dec CX jmp 标号 ;dec是自减的意思
那么有了CX不为0,则跳转的指令,有没有另一个当CX等于0时,跳转的指令?当然,jcxz指令就是这种功能,看字面意思就是jmp (cx = zore),jcxz指令用法和jmp完全一致,只是jcxz执行之时首先会去检查CX寄存器的值。
3.一段奇怪的程序
好的,现在是不是很好奇之前所提到过的那个很奇怪的程序,那么我们现在开始介绍,想必在理解过这段奇怪的程序之后,你会对jmp这个指令有着更加深入的理解。
这是这本书的作者,王爽老师提供的程序,下面上图:
一个奇怪的程序现在思考,这个程序运行是怎么样运行?他能正常退出吗,也就是执行到程序退出的出口。
如果你认为它可以正常的退出,那么恭喜你,你已经理解jmp指令了,如果你认为它是在标号S1,S2处不断的循环,那么请仔细回顾一下一开始所说的短转移指令。
是的,这里的短转移指令最后翻译出来的意思是向上移动S2-S1(地址)个字节,于是程序最后就在标号S处向上跳转到了这个段的最开头,也就是程序的出口,成功退出。
网友评论