以下内容只是本人的一些学习心得,如有谬误,希望诸位大神不吝赐教,菜鸟在此拜过各位大神。
这几天刚刚学了call和ret指令,call指令和ret指令是用来实现程序的跳转的,汇编程序中,主程序和子程序之间实现的跳转,是通过对cs和ip寄存器的值进行压栈或出栈实现的,本章中,我们的目标是实现类似于c语言中的printf函数的功能,不过在开始前,我们先来总结一下call和ret指令。
我们使用“()”将寄存器括起来的形式,表示该寄存器存储的值,比如(IP)表示偏移地址寄存器存储的值。
一、ret和retf指令:
1、ret指令用栈中的数据,修改ip的内容,实现近转移,下面是执行操作:
(1)(IP) = ((ss)*16 + (sp))
(2) (sp) = (sp) + 2
其实质等同于:pop IP
2、retf指令用栈中的数据,修改ip寄存器的内容,实现远转移,下面是执行操作:
(1) (IP) = ((ss)*16+(sp))
(2) (sp)= (sp)+2
(3) (cs)=((ss)*16+(sp))
(4) (sp)= (sp)+2
其实质等同于:pop IP
pop CS
二、call指令(注意:call指令不能实现段内短转移)
1、这里要对跳转指令进行必要的说明,所谓的跳转指令就是指jmp指令,下面我们来对jmp指令进行简要的说明:
如上图所示,囊括了jmp指令的大多数情况。
要了解以上列举的一系列内容,我们首先要知道jmp偏移位移的计算公式,什么是偏移位移,就是指IP寄存器值要加上的数值,就是偏移位移,计算公式如下图所示:
上图中的s和s0就是标号,现在我们就以jmp s0 和jmp s来进行说明,这两条指令都是段内短转移,短转移就是修改ip的值,短转移的修改范围为-128~127,也就是说以当前的jmp指令为基准,ip可以向后退128个字节或向前进127个字节,这个ip偏移位移是如何计算出来的呢,其实就是:
标号处地址-jmp指令后的第一个字节的偏移地址,比如mov bx,3(jmp s0后的第一条指令)的偏移地址为0001,而标号s0处的地址为0006,那么此时的偏移位移就是6-3=3,就是这么简单,注意,这里进行的是通过偏移位移进行跳转,而非通过目标地址进行跳转,这样做的好处是可以使程序更加灵活。
现在我们以jmp short 标号为例,进行一些简要的概括:
(1)jmp short 标号 -》(IP) = (IP) + 8位位移
(2)8位位移=标号处地址-jmp指令后的第一个字节的偏移地址
(3)short指令知名此处的位移为8位位移
(4)8位位移的范围为-128~127,用补码表示(这里的空间容量正好为2^8)
(5)8位位移由编译器在程序编译时算出。
由此可以类推jmp near ptr + 标号指令,这里near指的是jmp实现段内近转移,near表示ip的范围为-32768~32767,其他内容和jmp short 标号一致。
接下来我们来看看jmp +