Skip to content

Commit c41a647

Browse files
nickdesaulniersAlexisPerry
authored andcommitted
[libc][arm] implement a basic setjmp/longjmp (llvm#93220)
Note: our baremetal arm configuration compiles this as `--target=arm-none-eabi`, so this code is built in -marm mode. It could be smaller with `--target=armv7-none-eabi -mthumb`. The assembler is valid ARMv5, or THUMB2, but not THUMB(1).
1 parent 59f5ad4 commit c41a647

File tree

9 files changed

+178
-7
lines changed

9 files changed

+178
-7
lines changed

libc/config/baremetal/arm/entrypoints.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ set(TARGET_LIBC_ENTRYPOINTS
2626
# errno.h entrypoints
2727
libc.src.errno.errno
2828

29+
# setjmp.h entrypoints
30+
libc.src.setjmp.longjmp
31+
libc.src.setjmp.setjmp
32+
2933
# string.h entrypoints
3034
libc.src.string.bcmp
3135
libc.src.string.bcopy

libc/config/baremetal/arm/headers.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
set(TARGET_PUBLIC_HEADERS
22
libc.include.assert
33
libc.include.ctype
4-
libc.include.fenv
54
libc.include.errno
5+
libc.include.fenv
66
libc.include.float
7-
libc.include.stdint
87
libc.include.inttypes
98
libc.include.math
9+
libc.include.setjmp
1010
libc.include.stdfix
11+
libc.include.stdint
1112
libc.include.stdio
1213
libc.include.stdlib
1314
libc.include.string

libc/config/linux/arm/entrypoints.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ set(TARGET_LIBC_ENTRYPOINTS
2020
# errno.h entrypoints
2121
libc.src.errno.errno
2222

23+
# setjmp.h entrypoints
24+
libc.src.setjmp.longjmp
25+
libc.src.setjmp.setjmp
26+
2327
# string.h entrypoints
2428
libc.src.string.bcmp
2529
libc.src.string.bcopy

libc/config/linux/arm/headers.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
set(TARGET_PUBLIC_HEADERS
22
libc.include.ctype
3-
libc.include.fenv
43
libc.include.errno
4+
libc.include.fenv
55
libc.include.float
6-
libc.include.stdint
76
libc.include.inttypes
87
libc.include.math
9-
libc.include.stdckdint
8+
libc.include.search
9+
libc.include.setjmp
1010
libc.include.stdbit
11+
libc.include.stdckdint
12+
libc.include.stdint
1113
libc.include.stdlib
1214
libc.include.string
1315
libc.include.strings
14-
libc.include.search
15-
libc.include.wchar
1616
libc.include.uchar
17+
libc.include.wchar
1718

1819
# Disabled due to epoll_wait syscalls not being available on this platform.
1920
# libc.include.sys_epoll

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ typedef struct {
3232
#elif defined(__riscv_float_abi_single)
3333
#error "__jmp_buf not available for your target architecture."
3434
#endif
35+
#elif defined(__arm__)
36+
// r4, r5, r6, r7, r8, r9, r10, r11, r12, lr
37+
long opaque[10];
3538
#else
3639
#error "__jmp_buf not available for your target architecture."
3740
#endif

libc/include/setjmp.h.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_LIBC_SETJMP_H
1111

1212
#include "__llvm-libc-common.h"
13+
#include "llvm-libc-types/jmp_buf.h"
1314

1415
%%public_api()
1516

libc/src/setjmp/arm/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
add_entrypoint_object(
2+
setjmp
3+
SRCS
4+
setjmp.cpp
5+
HDRS
6+
../setjmp_impl.h
7+
DEPENDS
8+
libc.include.setjmp
9+
)
10+
11+
add_entrypoint_object(
12+
longjmp
13+
SRCS
14+
longjmp.cpp
15+
HDRS
16+
../longjmp.h
17+
DEPENDS
18+
libc.include.setjmp
19+
)

libc/src/setjmp/arm/longjmp.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
2+
//===-- Implementation of longjmp -----------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "src/setjmp/longjmp.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
#if defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 1
16+
17+
[[gnu::naked, gnu::target("thumb")]]
18+
LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
19+
asm(R"(
20+
# Reload r4, r5, r6, r7.
21+
ldmia r0!, {r4-r7}
22+
23+
# Reload r8, r9. They cannot appear in register lists so load them
24+
# into the lower registers, then move them into place.
25+
ldmia r0!, {r2-r3}
26+
mov r8, r2
27+
mov r9, r3
28+
29+
# Reload r10, r11. They cannot appear in register lists so load them
30+
# into the lower registers, then move them into place.
31+
ldmia r0!, {r2-r3}
32+
mov r10, r2
33+
mov r11, r3
34+
35+
# Reload sp, lr. They cannot appear in register lists so load them
36+
# into the lower registers, then move them into place.
37+
ldmia r0!, {r2-r3}
38+
mov sp, r2
39+
mov lr, r3
40+
41+
# return val ?: 1;
42+
movs r0, r1
43+
bne .Lret_val
44+
movs r0, #1
45+
46+
.Lret_val:
47+
bx lr)");
48+
}
49+
50+
#else // Thumb2 or ARM
51+
52+
// TODO(https://github.com/llvm/llvm-project/issues/94061): fp registers
53+
// (d0-d16)
54+
// TODO(https://github.com/llvm/llvm-project/issues/94062): pac+bti
55+
[[gnu::naked]]
56+
LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
57+
asm(R"(
58+
# While sp may appear in a register list for ARM mode, it may not for
59+
# Thumb2 mode. Just load the previous value of sp into r12 then move it
60+
# into sp, so that this code is portable between ARM and Thumb2.
61+
62+
ldm r0, {r4-r12, lr}
63+
mov sp, r12
64+
65+
# return val ?: 1;
66+
movs r0, r1
67+
it eq
68+
moveq r0, #1
69+
bx lr)");
70+
}
71+
72+
#endif
73+
74+
} // namespace LIBC_NAMESPACE

libc/src/setjmp/arm/setjmp.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
namespace LIBC_NAMESPACE {
13+
14+
#if defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 1
15+
16+
[[gnu::naked, gnu::target("thumb")]]
17+
LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
18+
asm(R"(
19+
# Store r4, r5, r6, and r7 into buf.
20+
stmia r0!, {r4-r7}
21+
22+
# Store r8, r9, r10, r11, sp, and lr into buf. Thumb(1) doesn't support
23+
# the high registers > r7 in stmia, so move them into lower GPRs first.
24+
# Thumb(1) also doesn't support using str with sp or lr, move them
25+
# together with the rest.
26+
mov r1, r8
27+
mov r2, r9
28+
mov r3, r10
29+
stmia r0!, {r1-r3}
30+
31+
mov r1, r11
32+
mov r2, sp
33+
mov r3, lr
34+
stmia r0!, {r1-r3}
35+
36+
# Return 0.
37+
movs r0, #0
38+
bx lr)");
39+
}
40+
41+
#else // Thumb2 or ARM
42+
43+
// TODO(https://github.com/llvm/llvm-project/issues/94061): fp registers
44+
// (d0-d16)
45+
// TODO(https://github.com/llvm/llvm-project/issues/94062): pac+bti
46+
[[gnu::naked]]
47+
LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
48+
asm(R"(
49+
# While sp may appear in a register list for ARM mode, it may not for
50+
# Thumb2 mode. Just move it into r12 then stm that, so that this code
51+
# is portable between ARM and Thumb2.
52+
mov r12, sp
53+
54+
# Store r4, r5, r6, r7, r8, r9, r10, r11, sp, and lr into buf.
55+
stm r0, {r4-r12, lr}
56+
57+
# Return zero.
58+
mov r0, #0
59+
bx lr)");
60+
}
61+
62+
#endif
63+
64+
} // namespace LIBC_NAMESPACE

0 commit comments

Comments
 (0)