Skip to content

[libc][setjmp][x86] implement setjmp in terms of out of line asm #88157

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

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions libc/src/__support/assembly.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- assembly.h - libc assembler support macros based on compiler-rt's -===//
//
// 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___SUPPORT_ASSEMBLY_H
#define LLVM_LIBC_SRC___SUPPORT_ASSEMBLY_H

#ifndef __ASSEMBLER__
#error "No not include assembly.h in non-asm sources"
#endif

#define GLUE2_(a, b) a##b
#define GLUE(a, b) GLUE2_(a, b)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)

#if defined(__ELF__) && (defined(__GNU__) || defined(__FreeBSD__) || \
defined(__Fuchsia__) || defined(__linux__))

// clang-format off
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack, "", @progbits
#define SYMBOL_IS_FUNC(name) .type SYMBOL_NAME(name), %function
#define END_FUNC(name) .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
// clang-format on

#else // !ELF
#define NO_EXEC_STACK_DIRECTIVE
#define SYMBOL_IS_FUNC(name)
#define END_FUNC(name)
#endif // ELF

#endif // LLVM_LIBC_SRC___SUPPORT_ASSEMBLY_H
7 changes: 1 addition & 6 deletions libc/src/setjmp/x86_64/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
add_entrypoint_object(
setjmp
SRCS
setjmp.cpp
setjmp.S
HDRS
../setjmp_impl.h
DEPENDS
libc.include.setjmp
COMPILE_OPTIONS
-O3
-fno-omit-frame-pointer
)

add_entrypoint_object(
Expand Down
42 changes: 42 additions & 0 deletions libc/src/setjmp/x86_64/setjmp.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===-- Implementation of setjmp --------------------------------*- ASM -*-===//
//
// 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/assembly.h"
#include "src/setjmp/x86_64/setjmp.h"

#define paste(ns) _ZN22 ## ns ## 6setjmpEP9__jmp_buf
Copy link
Member

Choose a reason for hiding this comment

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

I suggest an extern C name which includes the expansion of LIBC_NAMESPACE in the name, rather than manual C++ name-mangling. If you want to do C++ name-mangling you'll need to figure out how to generate the "22" since that needs to be the length of the namespace.

Copy link
Member Author

Choose a reason for hiding this comment

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

an extern C name which includes the expansion of LIBC_NAMESPACE in the name

I'm sorry I don't follow the suggestion. Can you please "break out the crayons" for me?

#define expand(x) paste(x)
#define LIBC_NAMESPACE_setjmp expand(LIBC_NAMESPACE)
// aka _ZN22__llvm_libc_19_0_0_git6setjmpEP9__jmp_buf
// aka __llvm_libc_19_0_0_git::setjmp(__jmp_buf*)

.global SYMBOL_NAME(setjmp)
.global SYMBOL_NAME(LIBC_NAMESPACE_setjmp)

SYMBOL_IS_FUNC(setjmp)
SYMBOL_IS_FUNC(LIBC_NAMESPACE_setjmp)

SYMBOL_NAME(setjmp):
SYMBOL_NAME(LIBC_NAMESPACE_setjmp):

mov %rbx, RBX_OFFSET(%rdi)
mov %rbp, RBP_OFFSET(%rdi)
mov %r12, R12_OFFSET(%rdi)
mov %r13, R13_OFFSET(%rdi)
mov %r14, R14_OFFSET(%rdi)
mov %r15, R15_OFFSET(%rdi)
lea 8(%rsp), %rax
mov %rax, RSP_OFFSET(%rdi)
mov (%rsp), %rax
mov %rax, RIP_OFFSET(%rdi)
xor %eax, %eax
ret
END_FUNC(setjmp)
END_FUNC(LIBC_NAMESPACE_setjmp)

NO_EXEC_STACK_DIRECTIVE
56 changes: 0 additions & 56 deletions libc/src/setjmp/x86_64/setjmp.cpp

This file was deleted.

28 changes: 28 additions & 0 deletions libc/src/setjmp/x86_64/setjmp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===-- setjmp.h - shared constants between C++ and asm sources (x86_64) --===//
//
// 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_X86_64_SETJMP_H
#define LLVM_LIBC_SRC_SETJMP_X86_64_SETJMP_H

#ifdef __ASSEMBLER__
#define UL(x) x
#else
#define UL(x) x##UL
#endif
Comment on lines +12 to +16
Copy link
Member Author

Choose a reason for hiding this comment

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

Will be useful again, move to assembly.h

Copy link
Member Author

Choose a reason for hiding this comment

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

hmm...maybe not. I do have a:

   11 #ifndef __ASSEMBLER__                                                                                                                                                                                                               
  12 #error "No not include assembly.h in non-asm sources"     ■ "No not include assembly.h in non-asm sources"                                                                                                                          
   13 #endif 

in assembly.h. Maybe I should change that so that it can be included in either sources. Or create yet another new header.


// Brittle! Changing the layout of __jmp_buf will break this!
#define RBX_OFFSET UL(0)
#define RBP_OFFSET UL(8)
#define R12_OFFSET UL(16)
#define R13_OFFSET UL(24)
#define R14_OFFSET UL(32)
#define R15_OFFSET UL(40)
#define RSP_OFFSET UL(48)
#define RIP_OFFSET UL(56)

#endif // LLVM_LIBC_SRC_SETJMP_X86_64_SETJMP_H
11 changes: 11 additions & 0 deletions libc/test/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,14 @@ add_libc_test(
DEPENDS
libc.include.llvm-libc-macros.stdckdint_macros
)

add_libc_test(
setjmp_test
SUITE
libc_include_tests
SRCS
setjmp_test.cpp
DEPENDS
libc.include.llvm-libc-macros.offsetof_macro
libc.include.llvm-libc-types.jmp_buf
)
30 changes: 30 additions & 0 deletions libc/test/include/setjmp_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===-- Unittests for setjmp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "include/llvm-libc-macros/offsetof-macro.h"
#include "include/llvm-libc-types/jmp_buf.h"
#include "src/setjmp/x86_64/setjmp.h"
#include "test/UnitTest/Test.h"

// If this test fails, then *_OFFSET macro definitions in
// libc/src/setjmp/x86_64/setjmp.S need to be fixed. This is a simple change
Copy link
Member Author

Choose a reason for hiding this comment

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

libc/src/setjmp/x86_64/setjmp.h is the updated source location

// detector.
TEST(LlvmLibcSetjmpTest, JmpBufLayout) {
#ifdef __x86_64__
ASSERT_EQ(offsetof(__jmp_buf, rbx), RBX_OFFSET);
ASSERT_EQ(offsetof(__jmp_buf, rbp), RBP_OFFSET);
ASSERT_EQ(offsetof(__jmp_buf, r12), R12_OFFSET);
ASSERT_EQ(offsetof(__jmp_buf, r13), R13_OFFSET);
ASSERT_EQ(offsetof(__jmp_buf, r14), R14_OFFSET);
ASSERT_EQ(offsetof(__jmp_buf, r15), R15_OFFSET);
ASSERT_EQ(offsetof(__jmp_buf, rsp), RSP_OFFSET);
ASSERT_EQ(offsetof(__jmp_buf, rip), RIP_OFFSET);
ASSERT_EQ(sizeof(__jmp_buf), 64UL);
ASSERT_EQ(alignof(__jmp_buf), 8UL);
#endif // __x86_64__
}