Implementing setjmp and longjmp in C without built-in functions or assembly (getting invalid return values)

I am trying to test my two functions, such as mimic setjmp and longjmp for homework - this is quite difficult, because we are not allowed to use the built-in functions or the asm () assembly to implement the longjmp and setjmp functions. (Yes, this is really an appointment .)

Problem . I keep getting incorrect 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 a return value of 1, which should print "error" (see section main () below).

Instead, my output is output as:

start foo
start bar
segmentation fault

Segmentation error, I tried to fix it by initializing the * p pointer with malloc, but that didn't seem to do anything. Although, will there be a segmentation error, the reason why im is not getting the correct return values?

the code:

#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);
}
+4
source share
2 answers

Implementation setjmp()and longjmp()requires access to the stack pointer. Unfortunately, the purpose you are working with has explicitly forbidden you to use every sensible method to do this (for example, using assembly or using built-in compilers to access the stack pointer).

, setjmp() longjmp() . , (, typedef int jmp_buf[1]), int...

. - C. , - , "" ...

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

, , , . , . / , , .

, , , , "" longjmp(). , , - , MIPS. , . , longjmp(), , , ( ).

+3

, ( , , ).

arg3caller . , . args3, , , . , , . args3, .

, arg3caller longjmp, , , , , . args3 ( , longjmp), , .

setjmp , , . setjmp globals ( setjmp jmpbuf, setjmp longjmp , ), . longjmp , . , longjmp, . ( ), , setjmp ( ).

, , , @duskwuff. -S, , asm gcc, , ( ).

Edit:

MIPS gcc, this MIPS gcc 5.4. , , - lr fp , ( a0, gcc , ). setjmp , , setjmp -, lr . arg lr fp, ( ) 0. , longjmp, , lr , fp sp. longjmp, fp , lr fp. longjmp, fp sp lr fp , , setjmp. 1, setjmp , longjmp.

, ! , (-O0). - , setjmp longjmp . , , , . , undefined, gcc . ( gdb spim), , , .

struct jmpbuf {
    int lr;
    int fp;
    int *sp;
};

static struct jmpbuf ctx;

static void setjmp_leaf(void) { }

int setjmp(int arg)
{
    // call the leaf so that our lr is saved
    setjmp_leaf();

    // the address of our arg should be immediately
    // above the lr and fp
    ctx.sp = &arg;

    // lr is immediately below arg
    ctx.lr = (&arg)[-1];

    // fp is below that
    ctx.fp = (&arg)[-2];

    return 0;
}

static void longjmp_leaf(int arg)
{
    // overwrite the caller frame pointer
    (&arg)[-1] = (int)ctx.sp;
}

int longjmp(int arg)
{
    // call the leaf so that our lr is saved
    // but also to change our fp to the save sp
    longjmp_leaf(arg);

    // repopulate the new stack frame with the saved
    // lr and fp.  &arg is calculated relative to fp,
    // which was modified by longjmp_leaf.  &arg isn't
    // where it used to be!
    (&arg)[-1] = ctx.lr;
    (&arg)[-2] = ctx.fp;

    // this should restore the saved fp and lr
    // from the new frame, so it looks like we're
    // returning from setjmp
    return 1;
}

!

+1

Source: https://habr.com/ru/post/1678206/


All Articles