[libc-commits] [libc] Implement `sigsetjmp` and `siglongjmp` for darwin/aarch64 (PR #139555)

via libc-commits libc-commits at lists.llvm.org
Mon May 12 07:38:33 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Aly ElAshram (AlyElashram)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/139555.diff


7 Files Affected:

- (modified) libc/config/darwin/arm/entrypoints.txt (+4) 
- (modified) libc/config/darwin/arm/headers.txt (+1) 
- (added) libc/src/setjmp/darwin/aarch64/CMakeLists.txt (+51) 
- (added) libc/src/setjmp/darwin/aarch64/longjmp.cpp (+87) 
- (added) libc/src/setjmp/darwin/aarch64/setjmp.cpp (+87) 
- (added) libc/src/setjmp/darwin/aarch64/sigsetjmp.cpp (+40) 
- (added) libc/src/setjmp/darwin/aarch64/sigsetjmp_epilogue.cpp (+21) 


``````````diff
diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt
index 308fc49d681d7..07199db6d1ae6 100644
--- a/libc/config/darwin/arm/entrypoints.txt
+++ b/libc/config/darwin/arm/entrypoints.txt
@@ -20,6 +20,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     # errno.h entrypoints
     libc.src.errno.errno
 
+    # setjmp.h entrypoints
+    libc.src.setjmp
+
+
     # string.h entrypoints
     libc.src.string.memccpy
     libc.src.string.memchr
diff --git a/libc/config/darwin/arm/headers.txt b/libc/config/darwin/arm/headers.txt
index 86e7145972324..8f3d6029c9b6a 100644
--- a/libc/config/darwin/arm/headers.txt
+++ b/libc/config/darwin/arm/headers.txt
@@ -7,6 +7,7 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.inttypes
     libc.include.limits
     libc.include.math
+    libc.include.setjmp
     libc.include.stdlib
     libc.include.string
     libc.include.strings
diff --git a/libc/src/setjmp/darwin/aarch64/CMakeLists.txt b/libc/src/setjmp/darwin/aarch64/CMakeLists.txt
new file mode 100644
index 0000000000000..37058e9fb905e
--- /dev/null
+++ b/libc/src/setjmp/darwin/aarch64/CMakeLists.txt
@@ -0,0 +1,51 @@
+if(setjmp_config_options)
+    list(PREPEND setjmp_config_options "COMPILE_OPTIONS")
+endif()
+
+add_entrypoint_object(
+  setjmp
+  SRCS
+    setjmp.cpp
+  HDRS
+    ../../setjmp_impl.h
+  DEPENDS
+    libc.hdr.types.jmp_buf
+  ${setjmp_config_options}
+)
+
+add_entrypoint_object(
+  longjmp
+  SRCS
+    longjmp.cpp
+  HDRS
+    ../../longjmp.h
+  DEPENDS
+    libc.hdr.types.jmp_buf
+  ${setjmp_config_options}
+)
+
+add_entrypoint_object(
+  sigsetjmp
+  SRCS
+    sigsetjmp.cpp
+  HDRS
+    ../../sigsetjmp.h
+  DEPENDS
+    libc.hdr.types.jmp_buf
+    libc.hdr.types.sigset_t
+    libc.hdr.offsetof_macros
+    libc.src.setjmp.sigsetjmp_epilogue
+    libc.src.setjmp.setjmp
+)
+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/aarch64/longjmp.cpp b/libc/src/setjmp/darwin/aarch64/longjmp.cpp
new file mode 100644
index 0000000000000..eca4303f58034
--- /dev/null
+++ b/libc/src/setjmp/darwin/aarch64/longjmp.cpp
@@ -0,0 +1,87 @@
+//===-- Implementation of longjmp for AArch64 -----------------------------===//
+//
+// 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/longjmp.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// TODO: if MTE stack tagging is in use (-fsanitize=memtag-stack), we need to
+// iterate over the region between the old and new values of sp, using STG or
+// ST2G instructions to clear the memory tags on the invalidated region of the
+// stack. But this requires a means of finding out that we're in that mode, and
+// as far as I can see there isn't currently a predefined macro for that.
+//
+// (__ARM_FEATURE_MEMORY_TAGGING only indicates whether the target architecture
+// supports the MTE instructions, not whether the compiler is configured to use
+// them.)
+
+[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp,
+                                  ([[maybe_unused]] jmp_buf buf,
+                                   [[maybe_unused]] int val)) {
+  // If BTI branch protection is in use, the compiler will automatically insert
+  // a BTI here, so we don't need to make any extra effort to do so.
+
+  // If PAC branch protection is in use, there's no need to sign the return
+  // address at the start of longjmp, because we're not going to use it anyway!
+
+  asm(
+      // Reload the callee-saved GPRs, including fp and lr.
+      R"(
+        ldp x19, x20, [x0,  #0*16]
+        ldp x21, x22, [x0,  #1*16]
+        ldp x23, x24, [x0,  #2*16]
+        ldp x25, x26, [x0,  #3*16]
+        ldp x27, x28, [x0,  #4*16]
+        ldp x29, x30, [x0,  #5*16]
+      )"
+      // We would usually reload the platform register x18 here
+      // but due to the apple ABI we are not allowed to use the x18 register
+      // so we reload the stack pointer only.
+      // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Respect-the-purpose-of-specific-CPU-registers
+      R"(
+        ldr x2,       [x0,  #6*16]
+        mov sp, x2
+      )"
+
+#if __ARM_FP
+      // Reload the callee-saved FP registers.
+      R"(
+        ldp d8,  d9,  [x0,  #7*16]
+        ldp d10, d11, [x0,  #8*16]
+        ldp d12, d13, [x0,  #9*16]
+        ldp d14, d15, [x0, #10*16]
+      )"
+#endif
+
+      // Calculate the return value.
+      R"(
+        cmp w1, #0
+        cinc w0, w1, eq
+      )"
+
+#if (__ARM_FEATURE_PAC_DEFAULT & 7) == 5
+      // Authenticate the return address using the PAC A key, since the
+      // compilation options ask for PAC protection even on leaf functions.
+      R"(
+        autiasp
+      )"
+#elif (__ARM_FEATURE_PAC_DEFAULT & 7) == 6
+      // Same, but using the PAC B key.
+      R"(
+        autibsp
+      )"
+#endif
+
+      R"(
+        ret
+      )");
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/darwin/aarch64/setjmp.cpp b/libc/src/setjmp/darwin/aarch64/setjmp.cpp
new file mode 100644
index 0000000000000..2842590850217
--- /dev/null
+++ b/libc/src/setjmp/darwin/aarch64/setjmp.cpp
@@ -0,0 +1,87 @@
+//===-- Implementation of setjmp for darwin AArch64 -----------------------===//
+//
+// 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/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/setjmp/setjmp_impl.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+[[gnu::naked]] LLVM_LIBC_FUNCTION(int, setjmp, ([[maybe_unused]] jmp_buf buf)) {
+  // If BTI branch protection is in use, the compiler will automatically insert
+  // a BTI here, so we don't need to make any extra effort to do so.
+
+  asm(
+#if __ARM_FEATURE_PAC_DEFAULT & 1
+      // Sign the return address using the PAC A key.
+      R"(
+        paciasp
+      )"
+#elif __ARM_FEATURE_PAC_DEFAULT & 2
+      // Sign the return address using the PAC B key.
+      R"(
+        pacibsp
+      )"
+#endif
+
+      // Store all the callee-saved GPRs, including fp (x29) and also lr (x30).
+      // Of course lr isn't normally callee-saved (the call instruction itself
+      // can't help clobbering it), but we certainly need to save it for this
+      // purpose.
+      R"(
+        stp x19, x20, [x0,  #0*16]
+        stp x21, x22, [x0,  #1*16]
+        stp x23, x24, [x0,  #2*16]
+        stp x25, x26, [x0,  #3*16]
+        stp x27, x28, [x0,  #4*16]
+        stp x29, x30, [x0,  #5*16]
+      )"
+
+      // While we usually store the platform register x18
+      // the darwin ABI inhibts usage of it
+      // Store just the stack pointer.
+      R"(
+        add x1, sp, #0
+        str x1,       [x0,  #6*16]
+      )"
+
+#if __ARM_FP
+      // Store the callee-saved FP registers. AAPCS64 only requires the low 64
+      // bits of v8-v15 to be preserved, i.e. each of d8,...,d15.
+      R"(
+        stp d8,  d9,  [x0,  #7*16]
+        stp d10, d11, [x0,  #8*16]
+        stp d12, d13, [x0,  #9*16]
+        stp d14, d15, [x0, #10*16]
+      )"
+#endif
+
+      // Set up return value of zero.
+      R"(
+        mov x0, #0
+      )"
+
+#if (__ARM_FEATURE_PAC_DEFAULT & 7) == 5
+      // Authenticate the return address using the PAC A key, since the
+      // compilation options ask for PAC protection even on leaf functions.
+      R"(
+        autiasp
+      )"
+#elif (__ARM_FEATURE_PAC_DEFAULT & 7) == 6
+      // Same, but using the PAC B key.
+      R"(
+        autibsp
+      )"
+#endif
+
+      R"(
+        ret
+      )");
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/darwin/aarch64/sigsetjmp.cpp b/libc/src/setjmp/darwin/aarch64/sigsetjmp.cpp
new file mode 100644
index 0000000000000..88b5a28e1105d
--- /dev/null
+++ b/libc/src/setjmp/darwin/aarch64/sigsetjmp.cpp
@@ -0,0 +1,40 @@
+//===-- Implementation of darwin/aarch64 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)) {
+
+  // The difference between sigsetjmp and setjmp is storing the signal mask of
+  // the calling thread
+
+  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/aarch64/sigsetjmp_epilogue.cpp b/libc/src/setjmp/darwin/aarch64/sigsetjmp_epilogue.cpp
new file mode 100644
index 0000000000000..b2ca4d99ed82b
--- /dev/null
+++ b/libc/src/setjmp/darwin/aarch64/sigsetjmp_epilogue.cpp
@@ -0,0 +1,21 @@
+//===-- 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) {
+  syscall_impl<long>(sigprocmask, SIG_SETMASK,
+                     /* set= */ retval ? &buffer->sigmask : nullptr,
+                     /* old_set= */ retval ? nullptr : &buffer->sigmask);
+  return retval;
+}
+} // namespace LIBC_NAMESPACE_DECL

``````````

</details>


https://github.com/llvm/llvm-project/pull/139555


More information about the libc-commits mailing list