diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/user/app/tests/libc/setjmp.c | 31 | ||||
-rw-r--r-- | src/user/app/tests/tests.c | 1 | ||||
-rw-r--r-- | src/user/app/tests/tests.h | 1 | ||||
-rw-r--r-- | src/user/lib/include/setjmp.h | 13 | ||||
-rw-r--r-- | src/user/lib/setjmp.s | 39 |
5 files changed, 75 insertions, 10 deletions
diff --git a/src/user/app/tests/libc/setjmp.c b/src/user/app/tests/libc/setjmp.c new file mode 100644 index 0000000..0dded9d --- /dev/null +++ b/src/user/app/tests/libc/setjmp.c @@ -0,0 +1,31 @@ +#include "../tests.h" +#include <stdbool.h> +#include <setjmp.h> + +static void test_setjmp(void) { + jmp_buf env; + volatile bool inner; + int val; + inner = false; + if (!(val = setjmp(env))) { + inner = true; + longjmp(env, 1234); + test(0); + } else { + test(val == 1234); + test(inner); + } + inner = false; + if (!(val = setjmp(env))) { + inner = true; + longjmp(env, 0); + test(0); + } else { + test(val == 1); + test(inner); + } +} + +void r_libc_setjmp(void) { + run_test(test_setjmp); +} diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c index f9b085a..8cdf79f 100644 --- a/src/user/app/tests/tests.c +++ b/src/user/app/tests/tests.c @@ -19,6 +19,7 @@ int main(void) { r_k_path(); r_k_threads(); r_libc_esemaphore(); + r_libc_setjmp(); r_libc_string(); r_s_printf(); r_s_ringbuf(); diff --git a/src/user/app/tests/tests.h b/src/user/app/tests/tests.h index b47e9b9..63dd940 100644 --- a/src/user/app/tests/tests.h +++ b/src/user/app/tests/tests.h @@ -13,6 +13,7 @@ void r_k_miscsyscall(void); void r_k_path(void); void r_k_threads(void); void r_libc_esemaphore(void); +void r_libc_setjmp(void); void r_libc_string(void); void r_s_printf(void); void r_s_ringbuf(void); diff --git a/src/user/lib/include/setjmp.h b/src/user/lib/include/setjmp.h index 51c7fd2..298939c 100644 --- a/src/user/lib/include/setjmp.h +++ b/src/user/lib/include/setjmp.h @@ -1,24 +1,17 @@ #pragma once #include <user/lib/panic.h> -typedef char jmp_buf[1]; +typedef uint64_t jmp_buf[8]; /* rbx, rsp, rbp, r12, r13, r14, r15, rip */ typedef char sigjmp_buf[1]; -static inline int setjmp(jmp_buf env) { - (void)env; - return 0; -} +int setjmp(jmp_buf env); +_Noreturn void longjmp(jmp_buf env, int val); static inline int sigsetjmp(sigjmp_buf env, int savemask) { (void)env; (void)savemask; return 0; } -static inline _Noreturn void longjmp(jmp_buf env, int val) { - (void)env; (void)val; - __libc_panic("unimplemented"); -} - static inline _Noreturn void siglongjmp(sigjmp_buf env, int val) { (void)env; (void)val; __libc_panic("unimplemented"); diff --git a/src/user/lib/setjmp.s b/src/user/lib/setjmp.s new file mode 100644 index 0000000..29292da --- /dev/null +++ b/src/user/lib/setjmp.s @@ -0,0 +1,39 @@ +.section .text +.global setjmp +.type setjmp, @function +// int setjmp(jmp_buf env); +setjmp: + mov %rbx, 0(%rdi) + mov %rbp, 16(%rdi) + mov %r12, 24(%rdi) + mov %r13, 32(%rdi) + mov %r14, 40(%rdi) + mov %r15, 48(%rdi) + /* save registers as if after a ret */ + lea 8(%rsp), %rax + mov %rax, 8(%rdi) + mov (%rsp), %rax + mov %rax, 56(%rdi) + xor %rax, %rax + + mov 8(%rdi), %rsp + jmp *56(%rdi) + + ret + + +.global longjmp +.type longjmp, @function +// _Noreturn void longjmp(jmp_buf env, int val); +longjmp: + mov %rsi, %rax + cmp $1, %rax /* carry set as for %rax - 1 - so, 1 only if %rax == 0 */ + adc $0, %rax +1: mov 0(%rdi), %rbx + mov 8(%rdi), %rsp + mov 16(%rdi), %rbp + mov 24(%rdi), %r12 + mov 32(%rdi), %r13 + mov 40(%rdi), %r14 + mov 48(%rdi), %r15 + jmp *56(%rdi) |