From 3c1146f2c5a7eef2fe1a45be21bb68ad89170dd8 Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 17 Oct 2022 21:22:18 +0200 Subject: [PATCH] libc: Implement setjmp() and longjmp() --- apps/src/init.c | 10 ++++++++-- libs/libc/include/setjmp.h | 21 +++++++++++++++------ libs/libc/src/setjmp.asm | 36 ++++++++++++++++++++++++++++++++++++ libs/libc/src/setjmp.cpp | 18 ++++-------------- 4 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 libs/libc/src/setjmp.asm diff --git a/apps/src/init.c b/apps/src/init.c index 2f998fa5..6ceb235e 100644 --- a/apps/src/init.c +++ b/apps/src/init.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -167,11 +168,16 @@ int main() perror("execv"); return 1; } + else { printf("Success!! Got PID %ld\n", child); } + + jmp_buf env; + int val = setjmp(env); + if (val == 0) { printf("Returning from setjmp!\n"); } else { - printf("Success!! Got PID %ld\n", child); + printf("Returning from longjmp! val=%d\n", val); return 0; } - return 0; + longjmp(env, 3); } diff --git a/libs/libc/include/setjmp.h b/libs/libc/include/setjmp.h index edfb2f3c..d42054aa 100644 --- a/libs/libc/include/setjmp.h +++ b/libs/libc/include/setjmp.h @@ -2,19 +2,28 @@ #define _SETJMP_H #include +#include -typedef int jmp_buf[1]; -typedef int sigjmp_buf[1]; +typedef uintptr_t jmp_buf[8]; +typedef uintptr_t sigjmp_buf[8]; #ifdef __cplusplus extern "C" { #endif - int setjmp(jmp_buf env); // Not implemented. - int sigsetjmp(sigjmp_buf env, int savesigs); // Not implemented. - __lc_noreturn void longjmp(jmp_buf env, int val); // Not implemented. - __lc_noreturn void siglongjmp(sigjmp_buf env, int val); // Not implemented. + /* Saves the current execution state in env. Returns 0 when called from the first time, or nonzero when returning + * from longjmp. */ + int setjmp(jmp_buf env); + + /* Right now, does the exact same as setjmp() (savesigs is ignored), since signals are not implemented. */ + int sigsetjmp(sigjmp_buf env, int savesigs); + + /* Restores the execution state saved in env by a setjmp() call. */ + __lc_noreturn void longjmp(jmp_buf env, int val); + + /* Right now, does the exact same as longjmp(), since signals are not implemented. */ + __lc_noreturn void siglongjmp(sigjmp_buf env, int val); #ifdef __cplusplus } diff --git a/libs/libc/src/setjmp.asm b/libs/libc/src/setjmp.asm new file mode 100644 index 00000000..21526397 --- /dev/null +++ b/libs/libc/src/setjmp.asm @@ -0,0 +1,36 @@ +global _setjmp +global setjmp +_setjmp: +setjmp: + mov rsi, 0 + mov [rdi], rbx + mov [rdi+8], r12 + mov [rdi+16], r13 + mov [rdi+24], r14 + mov [rdi+32], r15 + mov [rdi+40], rbp + mov [rdi+48], rsp + mov rax, [rsp] + mov [rdi+56], rax + xor rax, rax + ret + +global _longjmp +global longjmp +_longjmp: +longjmp: + mov rax, rsi + cmp rax, 0 + jne .nonzero + mov rax, 1 +.nonzero: + mov rbx, [rdi] + mov r12, [rdi+8] + mov r13, [rdi+16] + mov r14, [rdi+24] + mov r15, [rdi+32] + mov rbp, [rdi+40] + mov rsp, [rdi+48] + mov rcx, [rdi+56] + mov [rsp], rcx + ret \ No newline at end of file diff --git a/libs/libc/src/setjmp.cpp b/libs/libc/src/setjmp.cpp index 6a9f8041..d7d0e226 100644 --- a/libs/libc/src/setjmp.cpp +++ b/libs/libc/src/setjmp.cpp @@ -3,23 +3,13 @@ extern "C" { - int setjmp(jmp_buf) + int sigsetjmp(sigjmp_buf env, int) { - NOT_IMPLEMENTED("setjmp"); + return setjmp(env); } - int sigsetjmp(sigjmp_buf, int) + __lc_noreturn void siglongjmp(sigjmp_buf env, int val) { - NOT_IMPLEMENTED("sigsetjmp"); - } - - __lc_noreturn void longjmp(jmp_buf, int) - { - NOT_IMPLEMENTED("longjmp"); - } - - __lc_noreturn void siglongjmp(sigjmp_buf, int) - { - NOT_IMPLEMENTED("siglongjmp"); + longjmp(env, val); } } \ No newline at end of file