0x01 jmp指令

在CPU中有一个32位的寄存器EIP,EIP寄存器里面储存的是CPU要执行的下一条指令的地址。

JMP是汇编里面的无条件跳转指令,JMP指令的作用就是修改EIP寄存器。

虽然JMP是jump 跳的缩写,但是JMP和跳没有任何关系,JMP唯一的作用就是修改EIP寄存器。它实现跳转的方式就是通过修改EIP寄存器来实现的。汇编里面不允许使用mov指令修改EIP寄存器,假如可以用mov指令修改EIP寄存器,那么

1
2
mov eip,地址
jmp 地址

这两条指令最终实现的效果就是一样的。

jmp指令不影响堆栈,不修改其它寄存器,jmp指令唯一更改的就是eip寄存器。

0x02 call指令

call指令的作用也是修改EIP寄存器,但是call指令不仅会修改EIP寄存器。


call指令会把EIP寄存器的值修改为目标地址,然后,把call指令地址的下一个地址压入堆栈,”call指令地址的下一个地址”称之为返回地址。

例如,当前的堆栈和寄存器是这样的:

执行这一行指令:

1
call 40106c

目的地址是40106c,执行这一行指令以后,call指令就把目的地址储存到EIP寄存器。call指令地址是401040,call指令地址的下一个地址(返回地址)是401045,再看堆栈里面,已经把返回地址401045压入堆栈了。


call指令自身的地址加上call指令的长度就是返回地址。


由于call指令会压栈,所以call指令会影响esp寄存器。

0x03 ret指令

ret指令和call指令是成对出现的,ret指令同样会修改eip寄存器,ret指令是把call指令压入堆栈中的返回地址弹出到eip寄存器,让程序能继续执行下去。


所以ret指令相当于pop eip。


当一个函数调用完了,堆栈应该恢复到函数调用之前的状态,称之为堆栈平衡。


ret指令就是为了实现堆栈平衡。