diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h new file mode 100644 index 0000000..65fcce2 --- /dev/null +++ b/libc/include/setjmp.h @@ -0,0 +1,13 @@ +#ifndef _SETJMP_H +#define _SETJMP_H + +typedef struct { + void* _bp; // Base pointer + void* _sp; // Stack pointer + void* _pc; // Program counter +} jmp_buf; + +int setjmp(jmp_buf env); +void longjmp(jmp_buf env, int value); + +#endif diff --git a/libc/setjmp/setjmp.c b/libc/setjmp/setjmp.c new file mode 100644 index 0000000..4c58aa0 --- /dev/null +++ b/libc/setjmp/setjmp.c @@ -0,0 +1,26 @@ +#include + +int setjmp(jmp_buf env) { + __asm__ volatile ( + "mov %%ebp, %0\n" // Save BP + "mov %%esp, %1\n" // Save SP + "call 1f\n" // Call label to push PC to the stack + "pop %2\n" // Save PC + : "=m"(env._bp), "=m"(env._sp), "=m"(env._pc) // Locations + ); + return 0; +} + +void longjmp(jmp_buf env, int value) { + if (val == 0) return; + + __asm__ volatile ( + "mov %0, %%ebp\n" // Restore BP + "mov %1, %%esp\n" // Restore SP + "mov %2, %%eax\n" // Put return address into A + "jmp *%%eax\n" // Jump to A + :: "m"(env._bp), "m"(env._sp), "m"(env._pc) + ); + // This point is unreachable :) +} +