CALL 指令是否总是将 EIP 指向的地址压入堆栈?
Does CALL instruction ALWAYS push the address pointed by EIP to stack?
在 x86 架构中函数调用期间是否存在 return 地址未被压入堆栈的情况?
没有。根据定义,CALL
将在跳转到目标地址之前将 return 地址压入堆栈。 return地址是EIP
(或RIP
)+sizeof(call instruction)
(通常是5个字节。)
Volume 2 of the Intel® 64 and IA-32 Architectures Software Developer’s Manual 表示 CALL
:
Saves procedure linking information on the stack and branches to the called procedure specified using the target
operand.
这包括:
- Near Call — "A call to a procedure in the current code segment",其中 EIP 被压入堆栈。
- Far Call — "A call to a procedure located in a different segment than the current code segment",其中CS、EIP入栈。
不推送 return 地址的替代方法是 JMP
。
我熟悉的每个 C 编译器总是使用 CALL
指令在 x86 上实现函数调用,有一个例外:tail call,它可以用 JMP
实现].当一个函数 return 是另一个函数调用的结果时,尤其会发生这种情况。例如
int bar(int a, int b);
int foo(int a, int b)
{
if (a < b)
return 0;
return bar(a, b); // Will probably be: jmp bar
}
在 x86 架构中函数调用期间是否存在 return 地址未被压入堆栈的情况?
没有。根据定义,CALL
将在跳转到目标地址之前将 return 地址压入堆栈。 return地址是EIP
(或RIP
)+sizeof(call instruction)
(通常是5个字节。)
Volume 2 of the Intel® 64 and IA-32 Architectures Software Developer’s Manual 表示 CALL
:
Saves procedure linking information on the stack and branches to the called procedure specified using the target operand.
这包括:
- Near Call — "A call to a procedure in the current code segment",其中 EIP 被压入堆栈。
- Far Call — "A call to a procedure located in a different segment than the current code segment",其中CS、EIP入栈。
不推送 return 地址的替代方法是 JMP
。
我熟悉的每个 C 编译器总是使用 CALL
指令在 x86 上实现函数调用,有一个例外:tail call,它可以用 JMP
实现].当一个函数 return 是另一个函数调用的结果时,尤其会发生这种情况。例如
int bar(int a, int b);
int foo(int a, int b)
{
if (a < b)
return 0;
return bar(a, b); // Will probably be: jmp bar
}