`
wodamazi
  • 浏览: 1418167 次
文章分类
社区版块
存档分类
最新评论

读书笔记_CALL和RET指令

 
阅读更多

CALL指令是x86CPU中专门用作函数调用的指令,它的作用就是将当前的程序指针(EIP寄存器)值保存到栈中(称为linking information),然后转移到(branch to)目标操作数所指定的函数(被调用过程)继续执行。

根据被调用过程是否位于同一个代码段,CALL调用被分为近调用(Near Call)和远调用(Far Call)两种。在近调用中CPU的操作如下:

A. 将EIP寄存器的当前值压入到栈中供返回时使用

B. 将被调用过程的偏移(相对于当前段)加载到EIP寄存器中

C. 开始执行被调用过程

对于远调用,CPU执行的操作如下:

A. 将CS寄存器的当前值压入到栈中供返回时使用

B. 将EIP寄存器的当前值压入到栈中返回时使用

C. 将包含被调用过程的代码段的段选择子加载到CS寄存器

D. 被调用过程的偏移加载到EIP寄存器

E. 开始执行被调用过程

可以看出近调用和远调用的差异在于是否处理段寄存器,因为近调用发生在一个代码内的调用,因此不需要向栈中压入和切换代码段,而远调用因为发生在不同的代码段间,因此需要保存和切换代码段。但对于NT系列的windows,因为使用了平坦内存,在同一进程内的代码都是在一个大的4GB段中,因此不必再考虑段的差异,几乎所有时候使用的都是近调用。

下面来看RET指令,RET指令用于从被调用过程返回到发起调用的过程,RET指令可以有一个可选的参数n,用于指定ESP寄存器要递增的字节数,ESP递增n个字节相当于从栈中弹出n个字节,经常用来释放压在栈上的参数。相对于近调用的返回称为近返回(Near Return),相对于远调用的被称为远返回(Far Return)。

对于近返回,CPU所执行的操作如下:

1. 将位于栈顶的数据弹出到EIP寄存器,这个值应该是发起近调用时CALL指令压入的返回地址。

2. 如果RET指令包含参数n,那么便将ESP寄存器的字节数递增n。

3. 继续执行程序指针所指向的指令,通常就是父函数中调用指令的下一条指令。

而对于远返回,在第一步和第二步之间,CPU会弹出执行远调用时压入的CS寄存器。所以,RET指令只是单纯地返回到执行这条指令时栈顶所保存的地址,如果栈寄存器(ESP)没有指向合适的位置或栈上的地址被破坏了,那么RET指令就返回到其他地方。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics