Content #
近调用的意思是被调用的目标过程位于当前代码段内,而非另一个不同的代码段,所以只需要得到偏移地址即可。
16 位相对近调用是三字节指令,操作码为0xE8,后跟16 位的操作数,因为是相对调用,故该操作数是当前call 指令相对于目标过程的偏移量。
计算过程如下:
- 用目标过程的汇编地址减去当前call 指令的汇编地址,
- 再减去当前call 指令以字节为单位的长度(3),保留16 位的结果。
举个例子:
call near proc_1
近调用的特征是在指令中使用关键字“near”。“proc_1”是程序中的一个标号。在编译阶段,编译器用标号proc_1 处的汇编地址减去本指令的汇编地址,再减去3,作为机器指令的操作数。
关键字“near”不是必需的,如果call 指令中没有提供任何关键字,则编译器认为该指令是近调用。因此,上面的指令与这条指令等效:
call proc_1
因为16 位相对近调用的操作数是两个汇编地址相减的相对量,所以,如果被调用过程在当前指令的前方,也就是说,论汇编地址,它比call 指令的要大,那么该相对量是一个正数;反之,就是一个负数。所以,它的机器指令操作数是一个16 位的有符号数。换句话说,被调用过程的首地址必须位于距离当前call 指令-32768~32767 字节的地方。
在指令执行阶段,处理器看到操作码0xE8,就知道它应当调用一个过程。其执行过程如下:
- 用指令指针寄存器IP 的当前内容加上指令中的操作数,再加上3,得到一个新的偏移地址。
- 将IP 的原有内容压入栈。
- 用刚才计算出的偏移地址取代IP 原有的内容。这直接导致处理器的执行流转移到目标位置处。
再看一个例子:
call 0x0500
在call 指令后跟一个数值,只是帮了编译器的忙,帮它省了一个转化步骤,它依然会用这个数值减去当前指令的汇编地址,来得到一个偏移量。