Skip to content

[libc] implement sigsetjmp/siglongjmp for x86-64 #136072

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 13 commits into from
Apr 23, 2025
2 changes: 2 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,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

# stdio.h entrypoints
libc.src.stdio.clearerr
Expand Down
9 changes: 9 additions & 0 deletions libc/hdr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,14 @@ add_proxy_header_library(
libc.include.wchar
)

# offsetof is a macro inside compiler resource header stddef.h
add_proxy_header_library(
offsetof_macros
HDRS
offsetof_macros.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-macros.offsetof_macro
)

add_subdirectory(types)
add_subdirectory(func)
23 changes: 23 additions & 0 deletions libc/hdr/offsetof_macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===-- Definition of macros for offsetof ---------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_HDR_OFFSETOF_MACROS_H
#define LLVM_LIBC_HDR_OFFSETOF_MACROS_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-macros/offsetof-macro.h"

#else // Overlay mode

#define __need_offsetof
#include <stddef.h>

#endif // LLVM_LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_OFFSETOF_MACROS_H
2 changes: 1 addition & 1 deletion libc/include/llvm-libc-types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ add_header(gid_t HDR gid_t.h)
add_header(uid_t HDR uid_t.h)
add_header(imaxdiv_t HDR imaxdiv_t.h)
add_header(ino_t HDR ino_t.h)
add_header(jmp_buf HDR jmp_buf.h)
add_header(mbstate_t HDR mbstate_t.h)
add_header(mode_t HDR mode_t.h)
add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type)
Expand Down Expand Up @@ -83,6 +82,7 @@ add_header(union_sigval HDR union_sigval.h)
add_header(siginfo_t HDR siginfo_t.h DEPENDS .union_sigval .pid_t .uid_t .clock_t)
add_header(sig_atomic_t HDR sig_atomic_t.h)
add_header(sigset_t HDR sigset_t.h DEPENDS libc.include.llvm-libc-macros.signal_macros)
add_header(jmp_buf HDR jmp_buf.h DEPENDS .sigset_t)
add_header(struct_sigaction HDR struct_sigaction.h DEPENDS .sigset_t .siginfo_t)
add_header(struct_timespec HDR struct_timespec.h DEPENDS .time_t)
add_header(
Expand Down
15 changes: 15 additions & 0 deletions libc/include/llvm-libc-types/jmp_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#ifndef LLVM_LIBC_TYPES_JMP_BUF_H
#define LLVM_LIBC_TYPES_JMP_BUF_H

#include "sigset_t.h"

typedef struct {
#ifdef __x86_64__
__UINT64_TYPE__ rbx;
Expand Down Expand Up @@ -49,9 +51,22 @@ typedef struct {
#endif
#else
#error "__jmp_buf not available for your target architecture."
#endif
// TODO: implement sigjmp_buf related functions for other architectures
// Issue: https://github.com/llvm/llvm-project/issues/136358
#if defined(__i386__) || defined(__x86_64__)
// return address
void *sig_retaddr;
// extra register buffer to avoid indefinite stack growth in sigsetjmp
void *sig_extra;
// signal masks
sigset_t sigmask;
#endif
} __jmp_buf;

typedef __jmp_buf jmp_buf[1];

#if defined(__i386__) || defined(__x86_64__)
typedef __jmp_buf sigjmp_buf[1];
#endif
#endif // LLVM_LIBC_TYPES_JMP_BUF_H
16 changes: 16 additions & 0 deletions libc/include/setjmp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,19 @@ functions:
- _Returns_twice
arguments:
- type: jmp_buf
- name: sigsetjmp
standards:
- POSIX
return_type: int
attributes:
- _Returns_twice
arguments:
- type: sigjmp_buf
- type: int
- name: siglongjmp
standards:
- POSIX
return_type: _Noreturn void
arguments:
- type: sigjmp_buf
- type: int
28 changes: 28 additions & 0 deletions libc/src/setjmp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()

add_object_library(
Copy link
Contributor

Choose a reason for hiding this comment

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

You can't do this, object libraries are built by default. Entrypoint libraries are only enabled if the corresponding entrypoint is present. This is why every target is now trying to build this and failing if it's not present.

sigsetjmp_epilogue
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.sigsetjmp_epilogue
)

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
endif()
Expand All @@ -15,3 +26,20 @@ add_entrypoint_object(
DEPENDS
.${LIBC_TARGET_ARCHITECTURE}.longjmp
)

add_entrypoint_object(
siglongjmp
SRCS
siglongjmp.cpp
HDRS
siglongjmp.h
DEPENDS
.longjmp
)

add_entrypoint_object(
sigsetjmp
ALIAS
DEPENDS
.${LIBC_TARGET_ARCHITECTURE}.sigsetjmp
)
12 changes: 12 additions & 0 deletions libc/src/setjmp/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
25 changes: 25 additions & 0 deletions libc/src/setjmp/linux/sigsetjmp_epilogue.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE_DECL {
[[gnu::returns_twice]] int sigsetjmp_epilogue(jmp_buf buffer, int retval) {
// If set is NULL, then the signal mask is unchanged (i.e., how is
// ignored), but the current value of the signal mask is nevertheless
// returned in oldset (if it is not NULL).
syscall_impl<long>(SYS_rt_sigprocmask, SIG_SETMASK,
/* set= */ retval ? &buffer->sigmask : nullptr,
/* old_set= */ retval ? nullptr : &buffer->sigmask,
sizeof(sigset_t));
return retval;
}
} // namespace LIBC_NAMESPACE_DECL
3 changes: 2 additions & 1 deletion libc/src/setjmp/setjmp_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ namespace LIBC_NAMESPACE_DECL {
#ifdef LIBC_COMPILER_IS_GCC
[[gnu::nothrow]]
#endif
__attribute__((returns_twice)) int setjmp(jmp_buf buf);
[[gnu::returns_twice]] int
setjmp(jmp_buf buf);

} // namespace LIBC_NAMESPACE_DECL

Expand Down
23 changes: 23 additions & 0 deletions libc/src/setjmp/siglongjmp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===-- Implementation of siglongjmp --------------------------------------===//
//
// 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/siglongjmp.h"
#include "src/__support/common.h"
#include "src/setjmp/longjmp.h"

namespace LIBC_NAMESPACE_DECL {

// siglongjmp is the same as longjmp. The additional recovery work is done in
// the epilogue of the sigsetjmp function.
// TODO: move this inside the TU of longjmp and making it an alias after
// sigsetjmp is implemented for all architectures.
LLVM_LIBC_FUNCTION(void, siglongjmp, (jmp_buf buf, int val)) {
return LIBC_NAMESPACE::longjmp(buf, val);
}

} // namespace LIBC_NAMESPACE_DECL
25 changes: 25 additions & 0 deletions libc/src/setjmp/siglongjmp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===-- Implementation header for siglongjmp --------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SETJMP_SIGLONGJMP_H
#define LLVM_LIBC_SRC_SETJMP_SIGLONGJMP_H

#include "hdr/types/jmp_buf.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/compiler.h"

namespace LIBC_NAMESPACE_DECL {

#ifdef LIBC_COMPILER_IS_GCC
[[gnu::nothrow]]
#endif
void siglongjmp(jmp_buf buf, int val);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_SETJMP_SIGLONGJMP_H
26 changes: 26 additions & 0 deletions libc/src/setjmp/sigsetjmp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===-- Implementation header for sigsetjmp ---------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SETJMP_SIGSETJMP_H
#define LLVM_LIBC_SRC_SETJMP_SIGSETJMP_H

#include "hdr/types/jmp_buf.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/compiler.h"

namespace LIBC_NAMESPACE_DECL {

#ifdef LIBC_COMPILER_IS_GCC
[[gnu::nothrow]]
#endif
[[gnu::returns_twice]] int
sigsetjmp(sigjmp_buf buf, int savesigs);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_SETJMP_SIGSETJMP_H
19 changes: 19 additions & 0 deletions libc/src/setjmp/sigsetjmp_epilogue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===-- Implementation header for sigsetjmp epilogue ------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SETJMP_SIGSETJMP_EPILOGUE_H
#define LLVM_LIBC_SRC_SETJMP_SIGSETJMP_EPILOGUE_H

#include "hdr/types/jmp_buf.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE_DECL {
[[gnu::returns_twice]] int sigsetjmp_epilogue(jmp_buf buffer, int retval);
} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_SETJMP_SIGSETJMP_EPILOGUE_H
20 changes: 15 additions & 5 deletions libc/src/setjmp/x86_64/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,22 @@ add_entrypoint_object(
HDRS
../setjmp_impl.h
DEPENDS
libc.hdr.offsetof_macros
libc.hdr.types.jmp_buf
COMPILE_OPTIONS
${libc_opt_high_flag}
)

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_entrypoint_object(
Expand All @@ -18,7 +31,4 @@ add_entrypoint_object(
../longjmp.h
DEPENDS
libc.hdr.types.jmp_buf
COMPILE_OPTIONS
${libc_opt_high_flag}
-fomit-frame-pointer
)
2 changes: 1 addition & 1 deletion libc/src/setjmp/x86_64/setjmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "include/llvm-libc-macros/offsetof-macro.h"
#include "hdr/offsetof_macros.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/setjmp/setjmp_impl.h"
Expand Down
Loading
Loading