Skip to content

Commit 0f6fd1b

Browse files
[libc] Add support for setjmp and longjmp in riscv
This patch implements setjmp and longjmp in riscv using inline asm. The following changes were required: * Omit frame pointer: otherwise gcc won't allow us to use s0 * Use __attribute__((naked)): otherwise both gcc and clang will generate function prologue and epilogue in both functions. This doesn't happen in x86_64, so we guard it to only riscv Furthermore, using __attribute__((naked)) causes two problems: we can't use `return 0` (both gcc and clang) and the function arguments in the function body (clang only), so we had to use a0 and a1 directly. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D145584
1 parent 02885ef commit 0f6fd1b

File tree

11 files changed

+197
-28
lines changed

11 files changed

+197
-28
lines changed

clang/docs/tools/clang-formatted-files.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2594,6 +2594,7 @@ libc/include/llvm-libc-types/fexcept_t.h
25942594
libc/include/llvm-libc-types/FILE.h
25952595
libc/include/llvm-libc-types/float_t.h
25962596
libc/include/llvm-libc-types/imaxdiv_t.h
2597+
libc/include/llvm-libc-types/jmp_buf.h
25972598
libc/include/llvm-libc-types/ldiv_t.h
25982599
libc/include/llvm-libc-types/lldiv_t.h
25992600
libc/include/llvm-libc-types/mode_t.h

libc/config/linux/riscv64/entrypoints.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,10 @@ if(LLVM_LIBC_FULL_BUILD)
371371
# sched.h entrypoints
372372
libc.src.sched.__sched_getcpucount
373373

374+
# setjmp.h entrypoints
375+
libc.src.setjmp.longjmp
376+
libc.src.setjmp.setjmp
377+
374378
# stdio.h entrypoints
375379
libc.src.stdio.clearerr
376380
libc.src.stdio.clearerr_unlocked

libc/config/linux/riscv64/headers.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(TARGET_PUBLIC_HEADERS
1010
libc.include.sched
1111
libc.include.signal
1212
libc.include.spawn
13+
libc.include.setjmp
1314
libc.include.stdio
1415
libc.include.stdlib
1516
libc.include.string

libc/include/llvm-libc-types/jmp_buf.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@ typedef struct {
1919
__UINT64_TYPE__ r15;
2020
__UINTPTR_TYPE__ rsp;
2121
__UINTPTR_TYPE__ rip;
22+
#elif defined(__riscv)
23+
/* Program counter. */
24+
long int __pc;
25+
/* Callee-saved registers. */
26+
long int __regs[12];
27+
/* Stack pointer. */
28+
long int __sp;
29+
/* Callee-saved floating point registers. */
30+
#if __riscv_float_abi_double
31+
double __fpregs[12];
32+
#elif defined(__riscv_float_abi_single)
33+
#error "__jmp_buf not available for your target architecture."
34+
#endif
2235
#else
2336
#error "__jmp_buf not available for your target architecture."
2437
#endif

libc/src/setjmp/CMakeLists.txt

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
1+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
2+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
3+
endif()
4+
15
add_entrypoint_object(
26
setjmp
3-
SRCS
4-
setjmp.cpp
5-
HDRS
6-
setjmp_impl.h
7-
COMPILE_OPTIONS
8-
-O3 # We do not want any local variables in setjmp
9-
-fno-omit-frame-pointer # The implementation assumes frame pointer on to the stack
7+
ALIAS
108
DEPENDS
11-
libc.include.setjmp
9+
.${LIBC_TARGET_ARCHITECTURE}.setjmp
1210
)
1311

1412
add_entrypoint_object(
1513
longjmp
16-
SRCS
17-
longjmp.cpp
18-
HDRS
19-
longjmp.h
20-
COMPILE_OPTIONS
21-
-O3 # We do not want any local variables in longjmp
14+
ALIAS
2215
DEPENDS
23-
libc.include.setjmp
16+
.${LIBC_TARGET_ARCHITECTURE}.longjmp
2417
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
add_entrypoint_object(
2+
setjmp
3+
SRCS
4+
setjmp.cpp
5+
HDRS
6+
../setjmp_impl.h
7+
DEPENDS
8+
libc.include.setjmp
9+
COMPILE_OPTIONS
10+
-O3
11+
-fomit-frame-pointer
12+
)
13+
14+
add_entrypoint_object(
15+
longjmp
16+
SRCS
17+
longjmp.cpp
18+
HDRS
19+
../longjmp.h
20+
DEPENDS
21+
libc.include.setjmp
22+
COMPILE_OPTIONS
23+
-O3
24+
-fomit-frame-pointer
25+
)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===-- Implementation of longjmp -----------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/setjmp/longjmp.h"
10+
#include "src/__support/common.h"
11+
#include "src/__support/macros/properties/architectures.h"
12+
13+
#include <setjmp.h>
14+
15+
#if !defined(LIBC_TARGET_ARCH_IS_RISCV64)
16+
#error "Invalid file include"
17+
#endif
18+
19+
namespace __llvm_libc {
20+
21+
LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
22+
LIBC_INLINE_ASM("ld ra, %0\n\t" : : "m"(buf->__pc) :);
23+
LIBC_INLINE_ASM("ld s0, %0\n\t" : : "m"(buf->__regs[0]) :);
24+
LIBC_INLINE_ASM("ld s1, %0\n\t" : : "m"(buf->__regs[1]) :);
25+
LIBC_INLINE_ASM("ld s2, %0\n\t" : : "m"(buf->__regs[2]) :);
26+
LIBC_INLINE_ASM("ld s3, %0\n\t" : : "m"(buf->__regs[3]) :);
27+
LIBC_INLINE_ASM("ld s4, %0\n\t" : : "m"(buf->__regs[4]) :);
28+
LIBC_INLINE_ASM("ld s5, %0\n\t" : : "m"(buf->__regs[5]) :);
29+
LIBC_INLINE_ASM("ld s6, %0\n\t" : : "m"(buf->__regs[6]) :);
30+
LIBC_INLINE_ASM("ld s7, %0\n\t" : : "m"(buf->__regs[7]) :);
31+
LIBC_INLINE_ASM("ld s8, %0\n\t" : : "m"(buf->__regs[8]) :);
32+
LIBC_INLINE_ASM("ld s9, %0\n\t" : : "m"(buf->__regs[9]) :);
33+
LIBC_INLINE_ASM("ld s10, %0\n\t" : : "m"(buf->__regs[10]) :);
34+
LIBC_INLINE_ASM("ld s11, %0\n\t" : : "m"(buf->__regs[11]) :);
35+
LIBC_INLINE_ASM("ld sp, %0\n\t" : : "m"(buf->__sp) :);
36+
37+
#if __riscv_float_abi_double
38+
LIBC_INLINE_ASM("fld fs0, %0\n\t" : : "m"(buf->__fpregs[0]) :);
39+
LIBC_INLINE_ASM("fld fs1, %0\n\t" : : "m"(buf->__fpregs[1]) :);
40+
LIBC_INLINE_ASM("fld fs2, %0\n\t" : : "m"(buf->__fpregs[2]) :);
41+
LIBC_INLINE_ASM("fld fs3, %0\n\t" : : "m"(buf->__fpregs[3]) :);
42+
LIBC_INLINE_ASM("fld fs4, %0\n\t" : : "m"(buf->__fpregs[4]) :);
43+
LIBC_INLINE_ASM("fld fs5, %0\n\t" : : "m"(buf->__fpregs[5]) :);
44+
LIBC_INLINE_ASM("fld fs6, %0\n\t" : : "m"(buf->__fpregs[6]) :);
45+
LIBC_INLINE_ASM("fld fs7, %0\n\t" : : "m"(buf->__fpregs[7]) :);
46+
LIBC_INLINE_ASM("fld fs8, %0\n\t" : : "m"(buf->__fpregs[8]) :);
47+
LIBC_INLINE_ASM("fld fs9, %0\n\t" : : "m"(buf->__fpregs[9]) :);
48+
LIBC_INLINE_ASM("fld fs10, %0\n\t" : : "m"(buf->__fpregs[10]) :);
49+
LIBC_INLINE_ASM("fld fs11, %0\n\t" : : "m"(buf->__fpregs[11]) :);
50+
#elif defined(__riscv_float_abi_single)
51+
#error "longjmp implementation not available for the target architecture."
52+
#endif
53+
54+
val = val == 0 ? 1 : val;
55+
LIBC_INLINE_ASM("add a0, %0, zero\n\t" : : "r"(val) :);
56+
}
57+
58+
} // namespace __llvm_libc

libc/src/setjmp/riscv64/setjmp.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===-- Implementation of setjmp ------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/__support/common.h"
10+
#include "src/setjmp/setjmp_impl.h"
11+
12+
#include <setjmp.h>
13+
14+
#if !defined(LIBC_TARGET_ARCH_IS_RISCV64)
15+
#error "Invalid file include"
16+
#endif
17+
18+
namespace __llvm_libc {
19+
20+
LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
21+
LIBC_INLINE_ASM("sd ra, %0\n\t" : : "m"(buf->__pc) :);
22+
LIBC_INLINE_ASM("sd s0, %0\n\t" : : "m"(buf->__regs[0]) :);
23+
LIBC_INLINE_ASM("sd s1, %0\n\t" : : "m"(buf->__regs[1]) :);
24+
LIBC_INLINE_ASM("sd s2, %0\n\t" : : "m"(buf->__regs[2]) :);
25+
LIBC_INLINE_ASM("sd s3, %0\n\t" : : "m"(buf->__regs[3]) :);
26+
LIBC_INLINE_ASM("sd s4, %0\n\t" : : "m"(buf->__regs[4]) :);
27+
LIBC_INLINE_ASM("sd s5, %0\n\t" : : "m"(buf->__regs[5]) :);
28+
LIBC_INLINE_ASM("sd s6, %0\n\t" : : "m"(buf->__regs[6]) :);
29+
LIBC_INLINE_ASM("sd s7, %0\n\t" : : "m"(buf->__regs[7]) :);
30+
LIBC_INLINE_ASM("sd s8, %0\n\t" : : "m"(buf->__regs[8]) :);
31+
LIBC_INLINE_ASM("sd s9, %0\n\t" : : "m"(buf->__regs[9]) :);
32+
LIBC_INLINE_ASM("sd s10, %0\n\t" : : "m"(buf->__regs[10]) :);
33+
LIBC_INLINE_ASM("sd s11, %0\n\t" : : "m"(buf->__regs[11]) :);
34+
LIBC_INLINE_ASM("sd sp, %0\n\t" : : "m"(buf->__sp) :);
35+
36+
#if __riscv_float_abi_double
37+
LIBC_INLINE_ASM("fsd fs0, %0\n\t" : : "m"(buf->__fpregs[0]) :);
38+
LIBC_INLINE_ASM("fsd fs1, %0\n\t" : : "m"(buf->__fpregs[1]) :);
39+
LIBC_INLINE_ASM("fsd fs2, %0\n\t" : : "m"(buf->__fpregs[2]) :);
40+
LIBC_INLINE_ASM("fsd fs3, %0\n\t" : : "m"(buf->__fpregs[3]) :);
41+
LIBC_INLINE_ASM("fsd fs4, %0\n\t" : : "m"(buf->__fpregs[4]) :);
42+
LIBC_INLINE_ASM("fsd fs5, %0\n\t" : : "m"(buf->__fpregs[5]) :);
43+
LIBC_INLINE_ASM("fsd fs6, %0\n\t" : : "m"(buf->__fpregs[6]) :);
44+
LIBC_INLINE_ASM("fsd fs7, %0\n\t" : : "m"(buf->__fpregs[7]) :);
45+
LIBC_INLINE_ASM("fsd fs8, %0\n\t" : : "m"(buf->__fpregs[8]) :);
46+
LIBC_INLINE_ASM("fsd fs9, %0\n\t" : : "m"(buf->__fpregs[9]) :);
47+
LIBC_INLINE_ASM("fsd fs10, %0\n\t" : : "m"(buf->__fpregs[10]) :);
48+
LIBC_INLINE_ASM("fsd fs11, %0\n\t" : : "m"(buf->__fpregs[11]) :);
49+
#elif defined(__riscv_float_abi_single)
50+
#error "setjmp implementation not available for the target architecture."
51+
#endif
52+
53+
return 0;
54+
}
55+
56+
} // namespace __llvm_libc
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
add_entrypoint_object(
2+
setjmp
3+
SRCS
4+
setjmp.cpp
5+
HDRS
6+
../setjmp_impl.h
7+
DEPENDS
8+
libc.include.setjmp
9+
COMPILE_OPTIONS
10+
-O3
11+
-fno-omit-frame-pointer
12+
)
13+
14+
add_entrypoint_object(
15+
longjmp
16+
SRCS
17+
longjmp.cpp
18+
HDRS
19+
../longjmp.h
20+
DEPENDS
21+
libc.include.setjmp
22+
COMPILE_OPTIONS
23+
-O3
24+
-fno-omit-frame-pointer
25+
)

libc/src/setjmp/longjmp.cpp renamed to libc/src/setjmp/x86_64/longjmp.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88

99
#include "src/setjmp/longjmp.h"
1010
#include "src/__support/common.h"
11-
#include "src/__support/macros/properties/architectures.h"
1211

13-
#include <setjmp.h>
12+
#if !defined(LIBC_TARGET_ARCH_IS_X86_64)
13+
#error "Invalid file include"
14+
#endif
1415

1516
namespace __llvm_libc {
1617

1718
LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
18-
#ifdef LIBC_TARGET_ARCH_IS_X86_64
1919
register __UINT64_TYPE__ rbx __asm__("rbx");
2020
register __UINT64_TYPE__ rbp __asm__("rbp");
2121
register __UINT64_TYPE__ r12 __asm__("r12");
@@ -38,9 +38,6 @@ LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
3838
LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(r15) : "m"(buf->r15) :);
3939
LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rsp) : "m"(buf->rsp) :);
4040
LIBC_INLINE_ASM("jmp *%0\n\t" : : "m"(buf->rip));
41-
#else // LIBC_TARGET_ARCH_IS_X86_64
42-
#error "longjmp implementation not available for the target architecture."
43-
#endif
4441
}
4542

4643
} // namespace __llvm_libc

0 commit comments

Comments
 (0)