在没有内置函数或汇编的情况下用C实现setjmp和longjmp(获取错误的返回值) [英] Implementing setjmp and longjmp in C without built in functions or assembly (getting incorrect return values)

查看:146
本文介绍了在没有内置函数或汇编的情况下用C实现setjmp和longjmp(获取错误的返回值)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试测试2个类似于setjmp和longjmp的功课的函数-这非常困难,因为我们不允许使用内置函数或程序集asm()来实现longjmp和setjmp功能. (是的,这确实是任务.)

I'm trying to test 2 of my functions that sort of mimic setjmp and longjmp for a homework - which is pretty difficult since we're not allowed to use built in functions or assembly asm() to implement the longjmp and setjmp functions. (Yes, that's really the assignment.)

问题:我一直收到错误的返回值.简而言之,当main()调用foo()和foo()调用bar(),而bar()调用longjump()时,bar()不应返回foo(),而应setjmp()返回main,返回值为1,应显示错误"(请参见下面的main()).

Problem: I keep getting wrong return values. So, in short, when main() calls foo() and foo() calls bar(), and bar() calls longjump(), then bar() should not return to foo() but instead setjmp() should return to main with return value of 1 which should print "error" (see main() below).

相反,我的输出显示为:

Instead, my output comes out as:

start foo
start bar
segmentation fault

分段错误,我尝试通过使用malloc初始化指针* p进行修复,但这似乎无济于事.尽管细分会出错,但是这是为什么我无法获得正确的返回值的原因?

The segmentation fault, i tried fixing by initializing the pointer *p with malloc, but that didn't seem to do anything. Although, would the segmentation fault, be the reason why im not getting the correct return values?

代码:

#include <stdio.h>
#include <stdlib.h>

int setjmp(int v);
int longjmp(int v);
int foo(void);
int bar(void);
int *add;


int main(void) {

    int r;

    r = setjmp(r);
    if(r == 0) {
        foo();
        return(0);
    } else {
        printf("error\n");
        return(2);
    }

}

int _main(void) {
    return(0);
}

int setjmp(int v)
{
    add = &v;
    return(0);
}

int longjmp(int v)
{
    int *p;
    p = &v;
    *(p - 1) = *add;
    return(1);
}

int foo(void) {
    printf("start foo\n");
    bar();
    return(0);
}

int bar(void) {
    int d;
    printf("start bar\n");
    longjmp(d);
    return(0);
}

推荐答案

实现setjmp()longjmp()需要访问堆栈指针.不幸的是,您正在使用的分配已明确地禁止您使用每种明智的方法来执行此操作(即,使用汇编或使用编译器内置函数来访问堆栈指针).

Implementing setjmp() and longjmp() requires access to the stack pointer. Unfortunately, the assignment you're working from has explicitly banned you from using every sensible method to do this (i.e, using assembly, or using compiler builtins to access the stack pointer).

更糟糕的是,他们在示例代码中破坏了setjmp()longjmp()的定义.参数必须是可解析为数组的类型(例如typedef int jmp_buf[1]),而不是int

What's worse is, they've mangled the definition of setjmp() and longjmp() in their sample code. The argument needs to be a type that resolves to an array (e.g, typedef int jmp_buf[1]), not an int

无论如何.您需要某种方法来从C中的堆栈帧中可靠地找到旧的堆栈指针.可能的最佳方法是在堆栈上定义一个数组,然后在其后方看……

Anyways. You need some way to reliably find the old stack pointer from a stack frame in C. Probably the best way of doing this will be to define an array on the stack, then look "behind" it…

void get_sp(void) {
    int x[1];
    sp = x[-1]; // or -2 or -3, etc…

确切的偏移量取决于您使用的编译器,以及函数采用的参数以及函数具有的其他局部变量. 您需要做一些尝试才能做到这一点.在模拟器中运行您的应用程序,和/或查看生成的程序集,以确保您选择了正确的值.

The exact offset will depend on what compiler you're using, as well as possibly on what arguments your function takes and what other local variables the function has. You will need to experiment a bit to get this right. Run your application in the simulator, and/or look at the generated assembly, to make sure you're picking up the right value.

longjmp()返回"时,相同的技巧可能会设置堆栈指针.但是,某些编译器优化可能会使此操作变得困难,尤其是在具有链接寄存器的体系结构(例如MIPS)上.确保禁用编译器优化.如果所有其他方法均失败,则可能需要在longjmp()中调用伪函数,以强制编译器将链接寄存器保存在堆栈中,而不是将其保留在寄存器中(无法覆盖).

The same trick will probably work to set the stack pointer when "returning" from longjmp(). However, certain compiler optimizations may make this difficult, especially on architectures with a link register -- such as MIPS. Make sure compiler optimizations are disabled. If all else fails, you may need to call a dummy function in longjmp() to force the compiler to save the link register on the stack, rather than leaving it in a register (where it can't be overwritten).

这篇关于在没有内置函数或汇编的情况下用C实现setjmp和longjmp(获取错误的返回值)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆