diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index 1161ae260be2..fa62f4d290c3 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -201,6 +201,8 @@ if(LLVM_LIBC_FULL_BUILD) # setjmp.h entrypoints libc.src.setjmp.longjmp libc.src.setjmp.setjmp + libc.src.setjmp.siglongjmp + libc.src.setjmp.sigsetjmp ) endif() diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h index 2fec35dbc916..8a7d2839e21d 100644 --- a/libc/include/llvm-libc-types/jmp_buf.h +++ b/libc/include/llvm-libc-types/jmp_buf.h @@ -13,7 +13,7 @@ // Issue: https://github.com/llvm/llvm-project/issues/136358 #if defined(__linux__) #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ - defined(__riscv) + defined(__arm__) || defined(__riscv) #define __LIBC_HAS_SIGJMP_BUF #endif #endif diff --git a/libc/src/setjmp/arm/CMakeLists.txt b/libc/src/setjmp/arm/CMakeLists.txt index 55c80b0bede0..77f8471c06bb 100644 --- a/libc/src/setjmp/arm/CMakeLists.txt +++ b/libc/src/setjmp/arm/CMakeLists.txt @@ -8,6 +8,22 @@ add_entrypoint_object( libc.hdr.types.jmp_buf ) +if (TARGET libc.src.setjmp.sigsetjmp_epilogue) + 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 + ) +endif() + add_entrypoint_object( longjmp SRCS diff --git a/libc/src/setjmp/arm/sigsetjmp.cpp b/libc/src/setjmp/arm/sigsetjmp.cpp new file mode 100644 index 000000000000..41c86bda5d6c --- /dev/null +++ b/libc/src/setjmp/arm/sigsetjmp.cpp @@ -0,0 +1,65 @@ +//===-- 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 buf)) { +#if defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 1 + // Thumb1 does not support the high registers > r7 in stmia, so move them + // into lower GPRs first. + asm(R"( + tst r1, r1 + bne .Ldosave + b %c[setjmp] +.Ldosave: + str r4, [r0, #%c[extra]] + mov r4, lr + str r4, [r0, #%c[retaddr]] + mov r4, r0 + bl %c[setjmp] + mov r1, r0 + mov r0, r4 + ldr r4, [r0, #%c[retaddr]] + mov lr, r4 + ldr r4, [r0, #%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) + : "r0", "r1", "r4"); +#else + // Some thumb2 linkers do not support conditional branch to PLT. + // We branch to local labels instead. + asm(R"( + tst r1, r1 + bne .Ldosave + b %c[setjmp] +.Ldosave: + str r4, [r0, #%c[extra]] + str lr, [r0, #%c[retaddr]] + mov r4, r0 + bl %c[setjmp] + mov r1, r0 + mov r0, r4 + ldr lr, [r0, #%c[retaddr]] + ldr r4, [r0, #%c[extra]] + b %c[epilogue] + )" ::[retaddr] "i"(offsetof(__jmp_buf, sig_retaddr)), + [extra] "i"(offsetof(__jmp_buf, sig_extra)), [setjmp] "X"(setjmp), + [epilogue] "X"(sigsetjmp_epilogue) + : "r0", "r1", "r4"); +#endif +} +} // namespace LIBC_NAMESPACE_DECL