在一系列函数调用中,例如
main() --> A() --> B()-->C();
当被调用函数完成时,它通常会返回到调用函数,例如C()
返回B()
,返回A()
,等等。
我想知道是否也可以直接返回到调用序列中的较早函数 所以C()
回到main()
,跳过B()
和A()
如果可能的话,我该怎么做?你能解释一下它是如何工作的,以及它何时在现实中使用吗?
这是我的代码
#include <stdio.h>
int A(void);
int B(void);
void main(void )
{
A();
}
int A()
{
printf("enter A()n");
B();
printf("exit A()n");
}
int B()
{
printf("enter B()n");
printf("exit B()n");
}
我想从B()
跳过返回到函数A()
,以便printf("exit A()n");
不会执行并给我这个结果:
enter A()
enter B()
exit B()
在一切检查之前@PeterCordes不仅仅是以某种方式回答问题
奥基让我们开始:
这种类型的东西可以使用称为long jump
的东西来完成,因此编辑后的代码将如下所示:
#include <stdio.h>
#include <setjmp.h>//c standard library header
jmp_buf env; // for saving longjmp environment
main()
{
int r, a=100;
printf("call setjmp to save environmentn");
if ((r=setjmp(env)) == 0){
A();
printf("normal returnn");
}
else
printf("back to main() via long jump, r=%d a=%dn", r, a);
}
int A()
{
printf("enter A()n");
B();
printf("exit A()n");
}
int B()
{
printf("enter B()n");
printf("long jump? (y|n) ");
if (getchar()=='y')
longjmp(env, 1234);
printf("exit B()n");
}
让我们了解刚刚发生的事情
在上面的程序中,setjmp()
将当前执行环境保存在一个jmp_buf
结构和returns 0
.
程序继续调用A()
,调用B()
。
而 在函数B()
中,如果用户选择不按long jump
返回,函数将 显示正常的返回顺序。
如果用户选择按longjmp(env,1234)
返回, 执行将返回到上次保存的环境,并带有nonzero
值。
在 在这种情况下,它会导致B()
直接返回到main()
,绕过A()
。
原理long jump
非常简单。当一个函数完成时,它返回的
(caller_EIP, caller_EBP)
在当前堆栈帧中, 如果我们用(caller_EIP, caller_EBP)
替换
早期函数的(saved_EIP, saved_EBP)
在调用序列中,执行将直接返回到该函数。
另外 对于(saved_EIP, saved_EBP)
,setjmp()
也可以保存CPU的通用寄存器和 原始ESP
,以便longjmp()
可以恢复返回的完整环境 功能。
跳远可用于中止调用序列中的函数,导致 执行以从之前保存的已知环境恢复。
虽然很少使用 在用户模式程序中,它是系统编程中的常用技术。
例如 它可以在信号捕获器中用于绕过导致的用户模式功能 异常或陷阱错误。
你可以检查这个也很好