Skip to content

[libc][AArch64] Add an AArch64 setjmp/longjmp. #101177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 31, 2024

Conversation

statham-arm
Copy link
Collaborator

Previously, building libc for AArch64 in LLVM_LIBC_FULL_BUILD mode would fail because no implementation of setjmp/longjmp was available. This was the only obstacle, so now a full AArch64 build of libc is possible.

This implementation automatically supports PAC and BTI if compiled with the appropriate options. I would have liked to do the same for MTE stack tagging, but as far as I can see there's currently no predefined macro that allows detection of -fsanitize=memtag-stack, so I've left that one as a TODO.

AAPCS64 delegates the x18 register to individual platform ABIs, and allows them to choose what it's used for, which may or may not require setjmp and longjmp to save and restore it. To accommodate this, I've introduced a libc configuration option. The default is on, because the only use of x18 I've so far encountered uses it to store information specific to the current stack frame (so longjmp does need to restore it), and this is also safe behavior in the default situation where the platform ABI specifies no use of x18 and it becomes a temporary register (restoring it to its previous value is no worse than any other way for a function call to clobber it). But if a platform ABI needs to use x18 in a way that requires longjmp to leave it alone, they can turn the option off.

Previously, building libc for AArch64 in `LLVM_LIBC_FULL_BUILD` mode
would fail because no implementation of setjmp/longjmp was available.
This was the only obstacle, so now a full AArch64 build of libc is
possible.

This implementation automatically supports PAC and BTI if compiled
with the appropriate options. I would have liked to do the same for
MTE stack tagging, but as far as I can see there's currently no
predefined macro that allows detection of `-fsanitize=memtag-stack`,
so I've left that one as a TODO.

AAPCS64 delegates the x18 register to individual platform ABIs, and
allows them to choose what it's used for, which may or may not require
setjmp and longjmp to save and restore it. To accommodate this, I've
introduced a libc configuration option. The default is on, because the
only use of x18 I've so far encountered uses it to store information
specific to the current stack frame (so longjmp does need to restore
it), and this is also safe behavior in the default situation where the
platform ABI specifies no use of x18 and it becomes a temporary
register (restoring it to its previous value is no worse than any
_other_ way for a function call to clobber it). But if a platform ABI
needs to use x18 in a way that requires longjmp to leave it alone,
they can turn the option off.
Copy link

github-actions bot commented Jul 30, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@SchrodingerZhu SchrodingerZhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR LGTM in general. I would like to have sth similar to https://android.googlesource.com/platform/bionic/+/master/libc/arch-arm64/bionic/setjmp.S which have checksum and MTE based stack space checking, but this is a good start point.

@llvmbot llvmbot added the libc label Jul 31, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 31, 2024

@llvm/pr-subscribers-libc

Author: Simon Tatham (statham-arm)

Changes

Previously, building libc for AArch64 in LLVM_LIBC_FULL_BUILD mode would fail because no implementation of setjmp/longjmp was available. This was the only obstacle, so now a full AArch64 build of libc is possible.

This implementation automatically supports PAC and BTI if compiled with the appropriate options. I would have liked to do the same for MTE stack tagging, but as far as I can see there's currently no predefined macro that allows detection of -fsanitize=memtag-stack, so I've left that one as a TODO.

AAPCS64 delegates the x18 register to individual platform ABIs, and allows them to choose what it's used for, which may or may not require setjmp and longjmp to save and restore it. To accommodate this, I've introduced a libc configuration option. The default is on, because the only use of x18 I've so far encountered uses it to store information specific to the current stack frame (so longjmp does need to restore it), and this is also safe behavior in the default situation where the platform ABI specifies no use of x18 and it becomes a temporary register (restoring it to its previous value is no worse than any other way for a function call to clobber it). But if a platform ABI needs to use x18 in a way that requires longjmp to leave it alone, they can turn the option off.


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

7 Files Affected:

  • (modified) libc/config/config.json (+6)
  • (modified) libc/config/linux/aarch64/entrypoints.txt (+4)
  • (modified) libc/docs/configure.rst (+2)
  • (modified) libc/include/llvm-libc-types/jmp_buf.h (+5)
  • (added) libc/src/setjmp/aarch64/CMakeLists.txt (+28)
  • (added) libc/src/setjmp/aarch64/longjmp.cpp (+90)
  • (added) libc/src/setjmp/aarch64/setjmp.cpp (+93)
diff --git a/libc/config/config.json b/libc/config/config.json
index 58641d583b3e1..538fea53cc704 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -82,5 +82,11 @@
       "value": "LIBC_QSORT_QUICK_SORT",
       "doc": "Configures sorting algorithm for qsort and qsort_r. Values accepted are LIBC_QSORT_QUICK_SORT, LIBC_QSORT_HEAP_SORT."
     }
+  },
+  "setjmp": {
+    "LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER": {
+      "value": true,
+      "doc": "Make setjmp save the value of x18, and longjmp restore it. The AArch64 ABI delegates this register to platform ABIs, which can choose whether to make it caller-saved."
+    }
   }
 }
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index cfc280da27f4b..f65a15b5aa6b4 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -722,6 +722,10 @@ if(LLVM_LIBC_FULL_BUILD)
     # sched.h entrypoints
     libc.src.sched.__sched_getcpucount
 
+    # setjmp.h entrypoints
+    libc.src.setjmp.longjmp
+    libc.src.setjmp.setjmp
+
     # stdio.h entrypoints
     libc.src.stdio.clearerr
     libc.src.stdio.clearerr_unlocked
diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index e386149ebf45b..950de0eee4c05 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -47,6 +47,8 @@ to learn about the defaults for your platform and target.
 * **"scanf" options**
     - ``LIBC_CONF_SCANF_DISABLE_FLOAT``: Disable parsing floating point values in scanf and friends.
     - ``LIBC_CONF_SCANF_DISABLE_INDEX_MODE``: Disable index mode in the scanf format string.
+* **"setjmp" options**
+    - ``LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER``: Make setjmp save the value of x18, and longjmp restore it. The AArch64 ABI delegates this register to platform ABIs, which can choose whether to make it caller-saved.
 * **"string" options**
     - ``LIBC_CONF_MEMSET_X86_USE_SOFTWARE_PREFETCHING``: Inserts prefetch for write instructions (PREFETCHW) for memset on x86 to recover performance when hardware prefetcher is disabled.
     - ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen.
diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index 8949be9fa0ab7..60e033c6c65a9 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -35,6 +35,11 @@ typedef struct {
 #elif defined(__arm__)
   // r4, r5, r6, r7, r8, r9, r10, r11, r12, lr
   long opaque[10];
+#elif defined(__aarch64__)
+  long opaque[14]; // x19-x29, lr, sp, optional x18
+#if __ARM_FP
+  long fopaque[8]; // d8-d15
+#endif
 #else
 #error "__jmp_buf not available for your target architecture."
 #endif
diff --git a/libc/src/setjmp/aarch64/CMakeLists.txt b/libc/src/setjmp/aarch64/CMakeLists.txt
new file mode 100644
index 0000000000000..47eeb1a5c0ea6
--- /dev/null
+++ b/libc/src/setjmp/aarch64/CMakeLists.txt
@@ -0,0 +1,28 @@
+if(LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER)
+  list(APPEND setjmp_config_options "-DLIBC_COPT_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER")
+endif()
+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.include.setjmp
+  ${setjmp_config_options}
+)
+
+add_entrypoint_object(
+  longjmp
+  SRCS
+    longjmp.cpp
+  HDRS
+    ../longjmp.h
+  DEPENDS
+    libc.include.setjmp
+  ${setjmp_config_options}
+)
diff --git a/libc/src/setjmp/aarch64/longjmp.cpp b/libc/src/setjmp/aarch64/longjmp.cpp
new file mode 100644
index 0000000000000..3207cf40368c4
--- /dev/null
+++ b/libc/src/setjmp/aarch64/longjmp.cpp
@@ -0,0 +1,90 @@
+//===-- 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, (__jmp_buf * buf, 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]
+      )"
+
+#if LIBC_COPT_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER
+      // Reload the stack pointer, and the platform register x18.
+      R"(
+        ldp x2,  x18, [x0,  #6*16]
+        mov sp, x2
+      )"
+#else
+      // Reload just the stack pointer.
+      R"(
+        ldr x2,       [x0,  #6*16]
+        mov sp, x2
+      )"
+#endif
+
+#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 & 1
+      // Authenticate the return address using the PAC A key.
+      R"(
+        autiasp
+      )"
+#elif __ARM_FEATURE_PAC_DEFAULT & 2
+      // Authenticate the return address using the PAC B key.
+      R"(
+        autibsp
+      )"
+#endif
+
+      R"(
+        ret
+      )");
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/aarch64/setjmp.cpp b/libc/src/setjmp/aarch64/setjmp.cpp
new file mode 100644
index 0000000000000..ba4dd645eaaa3
--- /dev/null
+++ b/libc/src/setjmp/aarch64/setjmp.cpp
@@ -0,0 +1,93 @@
+//===-- Implementation of setjmp 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/__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, (__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]
+      )"
+
+#if LIBC_COPT_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER
+      // Store the stack pointer, and the platform register x18.
+      R"(
+        add x1, sp, #0
+        stp x1, x18,  [x0,  #6*16]
+      )"
+#else
+      // Store just the stack pointer.
+      R"(
+        add x1, sp, #0
+        str x1,       [x0,  #6*16]
+      )"
+#endif
+
+#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

@SchrodingerZhu
Copy link
Contributor

Tests passed locally. Thank you for the patch.

@SchrodingerZhu SchrodingerZhu merged commit 2a6268d into llvm:main Jul 31, 2024
8 checks passed
@statham-arm statham-arm deleted the aarch64-setjmp-longjmp branch July 31, 2024 16:11
@llvm-ci
Copy link
Collaborator

llvm-ci commented Jul 31, 2024

LLVM Buildbot has detected a new failure on builder libc-aarch64-ubuntu-fullbuild-dbg running on libc-aarch64-ubuntu while building libc at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/71/builds/3441

Here is the relevant piece of the build log for the reference:

Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py ...' (failure)
...
[387/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.link.dir/link.cpp.o
[388/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.symlink.dir/symlink.cpp.o
[389/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.symlinkat.dir/symlinkat.cpp.o
[390/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.fork.dir/fork.cpp.o
[391/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.truncate.dir/truncate.cpp.o
[392/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.unlinkat.dir/unlinkat.cpp.o
[393/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.lseek.dir/lseek.cpp.o
[394/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.sysconf.dir/sysconf.cpp.o
[395/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.chdir.dir/chdir.cpp.o
[396/456] Building CXX object projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o
FAILED: projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o 
/usr/bin/clang++ -DLIBC_NAMESPACE=__llvm_libc_19_0_0_git -D_DEBUG -Iprojects/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc -isystem projects/libc/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -g -DLIBC_QSORT_IMPL=LIBC_QSORT_QUICK_SORT -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -idirafter/usr/include -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER -DLIBC_COPT_PUBLIC_PACKAGING -std=c++17 -MD -MT projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o -MF projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o.d -o projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o -c /home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/setjmp.cpp
/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/setjmp.cpp:15:61: error: unused parameter 'buf' [-Werror,-Wunused-parameter]
[[gnu::naked]] LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
                                                            ^
1 error generated.
[397/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.pathconf.dir/pathconf.cpp.o
[398/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.access.dir/access.cpp.o
[399/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.close.dir/close.cpp.o
[400/456] Building CXX object projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o
FAILED: projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o 
/usr/bin/clang++ -DLIBC_NAMESPACE=__llvm_libc_19_0_0_git -D_DEBUG -Iprojects/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc -isystem projects/libc/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -g -DLIBC_QSORT_IMPL=LIBC_QSORT_QUICK_SORT -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -idirafter/usr/include -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER -DLIBC_COPT_PUBLIC_PACKAGING -std=c++17 -MD -MT projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o -MF projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o.d -o projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o -c /home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/longjmp.cpp
/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/longjmp.cpp:25:63: error: unused parameter 'buf' [-Werror,-Wunused-parameter]
[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
                                                              ^
/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/longjmp.cpp:25:72: error: unused parameter 'val' [-Werror,-Wunused-parameter]
[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
                                                                       ^
2 errors generated.
[401/456] Building CXX object projects/libc/src/network/CMakeFiles/libc.src.network.htonl.dir/htonl.cpp.o
[402/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.read.dir/read.cpp.o
[403/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.pread.dir/pread.cpp.o
[404/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.fchdir.dir/fchdir.cpp.o
[405/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.unlink.dir/unlink.cpp.o
[406/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.rmdir.dir/rmdir.cpp.o
[407/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.signal.dir/signal.cpp.o
[408/456] Building CXX object projects/libc/src/compiler/generic/CMakeFiles/libc.src.compiler.generic.__stack_chk_fail.dir/__stack_chk_fail.cpp.o
[409/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.raise.dir/raise.cpp.o
[410/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.sigaction.dir/sigaction.cpp.o
[411/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.__restore.dir/__restore.cpp.o
[412/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.sigfillset.dir/sigfillset.cpp.o
[413/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.getcwd.dir/getcwd.cpp.o
ninja: build stopped: subcommand failed.
['ninja', 'libc'] exited with return code 1.
The build step threw an exception...
Traceback (most recent call last):
  File "../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py", line 164, in step
    yield
  File "../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py", line 121, in main
Step 6 (build libc) failure: build libc (failure)
...
[387/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.link.dir/link.cpp.o
[388/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.symlink.dir/symlink.cpp.o
[389/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.symlinkat.dir/symlinkat.cpp.o
[390/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.fork.dir/fork.cpp.o
[391/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.truncate.dir/truncate.cpp.o
[392/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.unlinkat.dir/unlinkat.cpp.o
[393/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.lseek.dir/lseek.cpp.o
[394/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.sysconf.dir/sysconf.cpp.o
[395/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.chdir.dir/chdir.cpp.o
[396/456] Building CXX object projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o
FAILED: projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o 
/usr/bin/clang++ -DLIBC_NAMESPACE=__llvm_libc_19_0_0_git -D_DEBUG -Iprojects/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc -isystem projects/libc/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -g -DLIBC_QSORT_IMPL=LIBC_QSORT_QUICK_SORT -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -idirafter/usr/include -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER -DLIBC_COPT_PUBLIC_PACKAGING -std=c++17 -MD -MT projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o -MF projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o.d -o projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.setjmp.dir/setjmp.cpp.o -c /home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/setjmp.cpp
/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/setjmp.cpp:15:61: error: unused parameter 'buf' [-Werror,-Wunused-parameter]
[[gnu::naked]] LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
                                                            ^
1 error generated.
[397/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.pathconf.dir/pathconf.cpp.o
[398/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.access.dir/access.cpp.o
[399/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.close.dir/close.cpp.o
[400/456] Building CXX object projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o
FAILED: projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o 
/usr/bin/clang++ -DLIBC_NAMESPACE=__llvm_libc_19_0_0_git -D_DEBUG -Iprojects/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64 -I/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc -isystem projects/libc/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -g -DLIBC_QSORT_IMPL=LIBC_QSORT_QUICK_SORT -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -idirafter/usr/include -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER -DLIBC_COPT_PUBLIC_PACKAGING -std=c++17 -MD -MT projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o -MF projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o.d -o projects/libc/src/setjmp/aarch64/CMakeFiles/libc.src.setjmp.aarch64.longjmp.dir/longjmp.cpp.o -c /home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/longjmp.cpp
/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/longjmp.cpp:25:63: error: unused parameter 'buf' [-Werror,-Wunused-parameter]
[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
                                                              ^
/home/libc-buildbot/libc-aarch64-ubuntu/libc-aarch64-ubuntu-fullbuild-dbg/llvm-project/libc/src/setjmp/aarch64/longjmp.cpp:25:72: error: unused parameter 'val' [-Werror,-Wunused-parameter]
[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
                                                                       ^
2 errors generated.
[401/456] Building CXX object projects/libc/src/network/CMakeFiles/libc.src.network.htonl.dir/htonl.cpp.o
[402/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.read.dir/read.cpp.o
[403/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.pread.dir/pread.cpp.o
[404/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.fchdir.dir/fchdir.cpp.o
[405/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.unlink.dir/unlink.cpp.o
[406/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.rmdir.dir/rmdir.cpp.o
[407/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.signal.dir/signal.cpp.o
[408/456] Building CXX object projects/libc/src/compiler/generic/CMakeFiles/libc.src.compiler.generic.__stack_chk_fail.dir/__stack_chk_fail.cpp.o
[409/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.raise.dir/raise.cpp.o
[410/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.sigaction.dir/sigaction.cpp.o
[411/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.__restore.dir/__restore.cpp.o
[412/456] Building CXX object projects/libc/src/signal/linux/CMakeFiles/libc.src.signal.linux.sigfillset.dir/sigfillset.cpp.o
[413/456] Building CXX object projects/libc/src/unistd/linux/CMakeFiles/libc.src.unistd.linux.getcwd.dir/getcwd.cpp.o
ninja: build stopped: subcommand failed.
['ninja', 'libc'] exited with return code 1.
The build step threw an exception...
Traceback (most recent call last):
  File "../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py", line 164, in step
    yield
  File "../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py", line 121, in main

@nickdesaulniers
Copy link
Member

thanks for the patch!

stephanosio pushed a commit to zephyrproject-rtos/llvm-project that referenced this pull request Oct 16, 2024
Previously, building libc for AArch64 in `LLVM_LIBC_FULL_BUILD` mode
would fail because no implementation of setjmp/longjmp was available.
This was the only obstacle, so now a full AArch64 build of libc is
possible.

This implementation automatically supports PAC and BTI if compiled with
the appropriate options. I would have liked to do the same for MTE stack
tagging, but as far as I can see there's currently no predefined macro
that allows detection of `-fsanitize=memtag-stack`, so I've left that
one as a TODO.

AAPCS64 delegates the x18 register to individual platform ABIs, and
allows them to choose what it's used for, which may or may not require
setjmp and longjmp to save and restore it. To accommodate this, I've
introduced a libc configuration option. The default is on, because the
only use of x18 I've so far encountered uses it to store information
specific to the current stack frame (so longjmp does need to restore
it), and this is also safe behavior in the default situation where the
platform ABI specifies no use of x18 and it becomes a temporary register
(restoring it to its previous value is no worse than any _other_ way for
a function call to clobber it). But if a platform ABI needs to use x18
in a way that requires longjmp to leave it alone, they can turn the
option off.
stephanosio pushed a commit to zephyrproject-rtos/llvm-project that referenced this pull request Oct 17, 2024
Previously, building libc for AArch64 in `LLVM_LIBC_FULL_BUILD` mode
would fail because no implementation of setjmp/longjmp was available.
This was the only obstacle, so now a full AArch64 build of libc is
possible.

This implementation automatically supports PAC and BTI if compiled with
the appropriate options. I would have liked to do the same for MTE stack
tagging, but as far as I can see there's currently no predefined macro
that allows detection of `-fsanitize=memtag-stack`, so I've left that
one as a TODO.

AAPCS64 delegates the x18 register to individual platform ABIs, and
allows them to choose what it's used for, which may or may not require
setjmp and longjmp to save and restore it. To accommodate this, I've
introduced a libc configuration option. The default is on, because the
only use of x18 I've so far encountered uses it to store information
specific to the current stack frame (so longjmp does need to restore
it), and this is also safe behavior in the default situation where the
platform ABI specifies no use of x18 and it becomes a temporary register
(restoring it to its previous value is no worse than any _other_ way for
a function call to clobber it). But if a platform ABI needs to use x18
in a way that requires longjmp to leave it alone, they can turn the
option off.
nashif pushed a commit to zephyrproject-rtos/llvm-project that referenced this pull request May 31, 2025
Previously, building libc for AArch64 in `LLVM_LIBC_FULL_BUILD` mode
would fail because no implementation of setjmp/longjmp was available.
This was the only obstacle, so now a full AArch64 build of libc is
possible.

This implementation automatically supports PAC and BTI if compiled with
the appropriate options. I would have liked to do the same for MTE stack
tagging, but as far as I can see there's currently no predefined macro
that allows detection of `-fsanitize=memtag-stack`, so I've left that
one as a TODO.

AAPCS64 delegates the x18 register to individual platform ABIs, and
allows them to choose what it's used for, which may or may not require
setjmp and longjmp to save and restore it. To accommodate this, I've
introduced a libc configuration option. The default is on, because the
only use of x18 I've so far encountered uses it to store information
specific to the current stack frame (so longjmp does need to restore
it), and this is also safe behavior in the default situation where the
platform ABI specifies no use of x18 and it becomes a temporary register
(restoring it to its previous value is no worse than any _other_ way for
a function call to clobber it). But if a platform ABI needs to use x18
in a way that requires longjmp to leave it alone, they can turn the
option off.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants