From 6fedf06150f645cc694195abe43147a833f27036 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 7 Aug 2024 17:03:26 +0300 Subject: [PATCH] LibC: Implement {sig,_,}{longjmp,setjmp} --- userspace/libraries/LibC/CMakeLists.txt | 3 ++ userspace/libraries/LibC/arch/i686/setjmp.S | 28 +++++++++++++++++++ userspace/libraries/LibC/arch/x86_64/setjmp.S | 23 +++++++++++++++ userspace/libraries/LibC/include/setjmp.h | 15 ++++++---- userspace/libraries/LibC/setjmp.cpp | 19 +++++++++++++ userspace/tests/CMakeLists.txt | 1 + userspace/tests/test-setjmp/CMakeLists.txt | 8 ++++++ userspace/tests/test-setjmp/main.cpp | 22 +++++++++++++++ 8 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 userspace/libraries/LibC/arch/i686/setjmp.S create mode 100644 userspace/libraries/LibC/arch/x86_64/setjmp.S create mode 100644 userspace/libraries/LibC/setjmp.cpp create mode 100644 userspace/tests/test-setjmp/CMakeLists.txt create mode 100644 userspace/tests/test-setjmp/main.cpp diff --git a/userspace/libraries/LibC/CMakeLists.txt b/userspace/libraries/LibC/CMakeLists.txt index 61086b3a..5a70dd51 100644 --- a/userspace/libraries/LibC/CMakeLists.txt +++ b/userspace/libraries/LibC/CMakeLists.txt @@ -13,6 +13,7 @@ set(LIBC_SOURCES printf_impl.cpp pwd.cpp scanf_impl.cpp + setjmp.cpp signal.cpp stdio.cpp stdlib.cpp @@ -32,6 +33,8 @@ set(LIBC_SOURCES unistd.cpp icxxabi.cpp + arch/${BANAN_ARCH}/setjmp.S + ../../../BAN/BAN/Assert.cpp ) diff --git a/userspace/libraries/LibC/arch/i686/setjmp.S b/userspace/libraries/LibC/arch/i686/setjmp.S new file mode 100644 index 00000000..8b025507 --- /dev/null +++ b/userspace/libraries/LibC/arch/i686/setjmp.S @@ -0,0 +1,28 @@ +// int setjmp(jmp_buf env) +.global setjmp +setjmp: + movl 4(%esp), %edx + + leal 4(%esp), %eax + movl %eax, 0(%edx) + + movl (%esp), %eax + movl %eax, 4(%edx) + + xorl %eax, %eax + + ret + +// void longjmp(jmp_buf env, int val) +.global longjmp +longjmp: + movl 4(%esp), %edx + + movl 8(%esp), %ecx + movl $1, %eax + testl %ecx, %ecx + cmovnzl %ecx, %eax + + movl 0(%edx), %esp + movl 4(%edx), %ecx + jmp *%ecx diff --git a/userspace/libraries/LibC/arch/x86_64/setjmp.S b/userspace/libraries/LibC/arch/x86_64/setjmp.S new file mode 100644 index 00000000..7bebf826 --- /dev/null +++ b/userspace/libraries/LibC/arch/x86_64/setjmp.S @@ -0,0 +1,23 @@ +// int setjmp(jmp_buf env) +.global setjmp +setjmp: + leaq 8(%rsp), %rax + movq %rax, 0(%rdi) + + movq (%rsp), %rax + movq %rax, 8(%rdi) + + xorq %rax, %rax + + ret + +// void longjmp(jmp_buf env, int val) +.global longjmp +longjmp: + movq $1, %rax + testq %rsi, %rsi + cmovnzq %rsi, %rax + + movq 0(%rdi), %rsp + movq 8(%rdi), %rcx + jmp *%rcx diff --git a/userspace/libraries/LibC/include/setjmp.h b/userspace/libraries/LibC/include/setjmp.h index 20f76ea8..ada6e58e 100644 --- a/userspace/libraries/LibC/include/setjmp.h +++ b/userspace/libraries/LibC/include/setjmp.h @@ -7,13 +7,16 @@ __BEGIN_DECLS -typedef int jmp_buf[1]; -typedef int sigjmp_buf[1]; +typedef long jmp_buf[2]; +typedef long sigjmp_buf[2 + 1 + (sizeof(long long) / sizeof(long))]; -void longjmp(jmp_buf env, int val); -void siglongjmp(sigjmp_buf env, int val); -int setjmp(jmp_buf env); -int sigsetjmp(sigjmp_buf env, int savemask); +#define _longjmp longjmp +void longjmp(jmp_buf env, int val); +void siglongjmp(sigjmp_buf env, int val); + +#define _setjmp setjmp +int setjmp(jmp_buf env); +int sigsetjmp(sigjmp_buf env, int savemask); __END_DECLS diff --git a/userspace/libraries/LibC/setjmp.cpp b/userspace/libraries/LibC/setjmp.cpp new file mode 100644 index 00000000..9fb94cc1 --- /dev/null +++ b/userspace/libraries/LibC/setjmp.cpp @@ -0,0 +1,19 @@ +#include +#include + +static_assert(sizeof(sigjmp_buf) == sizeof(jmp_buf) + sizeof(long) + sizeof(sigset_t)); + +void siglongjmp(sigjmp_buf env, int val) +{ + if (env[2]) + pthread_sigmask(SIG_SETMASK, reinterpret_cast(&env[3]), nullptr); + return longjmp(env, val); +} + +int sigsetjmp(sigjmp_buf env, int savemask) +{ + env[2] = savemask; + if (savemask) + pthread_sigmask(0, nullptr, reinterpret_cast(&env[3])); + return setjmp(env); +} diff --git a/userspace/tests/CMakeLists.txt b/userspace/tests/CMakeLists.txt index 90de8334..4d47941d 100644 --- a/userspace/tests/CMakeLists.txt +++ b/userspace/tests/CMakeLists.txt @@ -5,6 +5,7 @@ set(USERSPACE_TESTS test-mmap-shared test-mouse test-popen + test-setjmp test-sort test-tcp test-udp diff --git a/userspace/tests/test-setjmp/CMakeLists.txt b/userspace/tests/test-setjmp/CMakeLists.txt new file mode 100644 index 00000000..d6f3c185 --- /dev/null +++ b/userspace/tests/test-setjmp/CMakeLists.txt @@ -0,0 +1,8 @@ +set(SOURCES + main.cpp +) + +add_executable(test-setjmp ${SOURCES}) +banan_link_library(test-setjmp libc) + +install(TARGETS test-setjmp OPTIONAL) diff --git a/userspace/tests/test-setjmp/main.cpp b/userspace/tests/test-setjmp/main.cpp new file mode 100644 index 00000000..ee15d81e --- /dev/null +++ b/userspace/tests/test-setjmp/main.cpp @@ -0,0 +1,22 @@ +#include +#include + +jmp_buf env; + +void iterate() +{ + static volatile int count = 0; + if (count < 10) + { + count = count + 1; + longjmp(env, count); + } +} + +int main() +{ + printf("start\n"); + if (int ret = setjmp(env)) + printf("longjmp %d\n", ret); + iterate(); +}