diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt index 70c888aec064c..11fd9bda04b17 100644 --- a/libc/config/darwin/arm/entrypoints.txt +++ b/libc/config/darwin/arm/entrypoints.txt @@ -70,6 +70,9 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.inttypes.strtoimax libc.src.inttypes.strtoumax + # setjmp.h entrypoints + libc.src.setjmp.sigsetjmp + # stdlib.h entrypoints libc.src.stdlib.abs libc.src.stdlib.atoi diff --git a/libc/src/setjmp/darwin/CMakeLists.txt b/libc/src/setjmp/darwin/CMakeLists.txt new file mode 100644 index 0000000000000..63cfc11115488 --- /dev/null +++ b/libc/src/setjmp/darwin/CMakeLists.txt @@ -0,0 +1,12 @@ +add_object_library( + sigsetjmp_epilogue + HDRS + ../sigsetjmp_epilogue.h + SRCS + sigsetjmp_epilogue.cpp + DEPENDS + libc.src.__support.common + libc.src.__support.OSUtil.osutil + libc.hdr.types.jmp_buf + libc.hdr.types.sigset_t +) \ No newline at end of file diff --git a/libc/src/setjmp/darwin/X86_64/sigsetjmp.cpp b/libc/src/setjmp/darwin/X86_64/sigsetjmp.cpp new file mode 100644 index 0000000000000..b358e5d95525d --- /dev/null +++ b/libc/src/setjmp/darwin/X86_64/sigsetjmp.cpp @@ -0,0 +1,44 @@ +//===-- Implementation of sigsetjmp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/setjmp/sigsetjmp.h" +#include "hdr/offsetof_macros.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/setjmp_impl.h" +#include "src/setjmp/sigsetjmp_epilogue.h" +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) +#error "Invalid file include" +#endif +namespace LIBC_NAMESPACE_DECL { + +[[gnu::naked]] +LLVM_LIBC_FUNCTION(int, sigsetjmp, (sigjmp_buf buf, int save_mask)) { + asm(R"( + test %%esi, %%esi + jz .Lnosave + + pop %c[retaddr](%%rdi) // pop the return address into the buffer + mov %%rbx, %c[extra](%%rdi) // move the value in %rbx to the 'extra' field in the buffer + mov %%rdi, %%rbx // move the buffer address to %rbx + call %P[setjmp] // call setjmp + push %c[retaddr](%%rbx) // push return address back into buffer + mov %%rbx, %%rdi // move buffer address back into %rdi + mov %%eax, %%esi // move setjmp return value to %esi (for save_mask) + mov %c[extra](%%rdi), %%rbx // restore the extra field + jmp %P[epilogue] // jump to epilogue + +.Lnosave: + jmp %P[setjmp] // jump directly to setjmp if no save mask is provided + )" :: [retaddr] "i"(offsetof(__jmp_buf, sig_retaddr)), + [extra] "i"(offsetof(__jmp_buf, sig_extra)), [setjmp] "X"(setjmp), + [epilogue] "X"(sigsetjmp_epilogue) + : "rax", "rbx", "rdi", "rsi"); +} + +} // namespace LIBC_NAMESPACE_DECL \ No newline at end of file diff --git a/libc/src/setjmp/darwin/arm/sigsetjmp.cpp b/libc/src/setjmp/darwin/arm/sigsetjmp.cpp new file mode 100644 index 0000000000000..734591b2aca4c --- /dev/null +++ b/libc/src/setjmp/darwin/arm/sigsetjmp.cpp @@ -0,0 +1,36 @@ +//===-- Implementation of sigsetjmp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/setjmp/sigsetjmp.h" +#include "hdr/offsetof_macros.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/setjmp_impl.h" +#include "src/setjmp/sigsetjmp_epilogue.h" + +namespace LIBC_NAMESPACE_DECL { +[[gnu::naked]] +LLVM_LIBC_FUNCTION(int, sigsetjmp, (sigjmp_buf, int)) { + asm(R"( + cbz w1, %c[setjmp] + + str x30, [x0, %c[retaddr]] + str x19, [x0, %c[extra]] + mov x19, x0 + bl %c[setjmp] + + mov w1, w0 + mov x0, x19 + ldr x30, [x0, %c[retaddr]] + ldr x19, [x0, %c[extra]] + b %c[epilogue])" ::[retaddr] "i"(offsetof(__jmp_buf, sig_retaddr)), + [extra] "i"(offsetof(__jmp_buf, sig_extra)), [setjmp] "i"(setjmp), + [epilogue] "i"(sigsetjmp_epilogue) + : "x0", "x1", "x19", "x30"); +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/darwin/sigsetjmp_epilogue.cpp b/libc/src/setjmp/darwin/sigsetjmp_epilogue.cpp new file mode 100644 index 0000000000000..4f8e4c39af413 --- /dev/null +++ b/libc/src/setjmp/darwin/sigsetjmp_epilogue.cpp @@ -0,0 +1,25 @@ +//===-- Implementation of sigsetjmp_epilogue ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/setjmp/sigsetjmp_epilogue.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/common.h" +#include "src/signal/sigprocmask.h" + +namespace LIBC_NAMESPACE_DECL { +[[gnu::returns_twice]] int sigsetjmp_epilogue(jmp_buf buffer, int retval) { + if (retval) { + // Restore signal mask from the buffer using syscall_impl for macOS + syscall_impl(SYS_rt_sigprocmask, SIG_SETMASK, &buffer->sigmask, nullptr, sizeof(sigset_t)); + } else { + // Save the current signal mask to the buffer using syscall_impl for macOS + syscall_impl(SYS_rt_sigprocmask, SIG_BLOCK, nullptr, &buffer->sigmask, sizeof(sigset_t)); + } + return retval; +} +} // namespace LIBC_NAMESPACE_DECL