前言
今天说的几条指令跟程序指令执行跳转有点关系。JMP、CALL、RET、LEA这几条指令。搞懂这些,有利于理解C语言中的函数调用和函数返回。
JMP指令
在讲JMP指令前,先讲一下CPU是如何控制执行顺序的。CPU把执行程序运行到的指令的地址保存到EIP寄存器中,换句话说:EIP寄存器保存当前程序执行的位置的地址。OD用了很久了,如果细心的同学应该有发现。
既然这样,我们是否可以通过mov指令来修改EIP中的值,让CPU跳转到我们需要执行的位置。答案是不行的,OD中禁止使用mov指令修改EIP的值。
但是我们可以通过JMP指令来修改EIP中的值。
JMP指令的格式:JMP r/imm。后面直接跟内存地址就可以了。我们按F8运行,程序就会跳转到我们指定的位置。
CALL指令
CALL指令也会修改寄存器EIP的值,也就是说可以让程序跳转到其他指定的位置运行。但是它跟JMP指令有一个区别,就是它会把当前指令的下一个指令的地址压入到栈中。这有什么好处呢?好处就是:如果跳转后想返回原来的位置继续指令,只要把栈中的保存的值修改到EIP中,就可以让程序重新返回原的位置的下一行指令。
格式:CALL r/imm。CALL后面直接接地址就可以了。
测试:
执行CALL指令前。
执行CALL指令后
有人会问,怎样知道call的下一行指令的地址,这牵扯到硬编码了。不过可以说说,在OD中看第二列,CALL那一行的第二列是E8 0D000000,共5个字节,程序是这样计算下一行指令的地址的,当前指令的地址,加上本指令后面的字节数,所以有这里CALL指令的下一行地址就是0x00EA4F17加上5,得到0x00EA4F1C。所以在指令CALL指令时,会把0x00EA4F1C这个地址压入栈中,并且修改EIP中的值。
RET指令
RET指令跟CALL指令是成对存在的,RET指令的作用是返回到CALL指令的下一行指令。执行RET指令,程序会把栈顶的内容pop到EIP寄存器中。
测试:
执行RET指令前
执行RET指令后
说明:(以下内容仅仅给了解C语言的人看,没学过的可以忽略),CALL就是C语言中的函数调用,而RET指令就是C语言函数中的return,函数返回。
LEA指令
LEA指令(Load effect address)没什么好讲的,就是获取内存地址。这个指令很容易跟MOV指令混淆。LEA主要是获取地址。
测试:
测试前
测试后:
好了,今天就写到这。
写于2020.6.14 21:58