mirror of
https://github.com/intel/llvm.git
synced 2026-01-21 04:14:03 +08:00
[libc][arm] implement a basic setjmp/longjmp (#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).
This commit is contained in:
committed by
GitHub
parent
abad8455ab
commit
f1ce6a465d
@@ -26,6 +26,10 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
# errno.h entrypoints
|
||||
libc.src.errno.errno
|
||||
|
||||
# setjmp.h entrypoints
|
||||
libc.src.setjmp.longjmp
|
||||
libc.src.setjmp.setjmp
|
||||
|
||||
# string.h entrypoints
|
||||
libc.src.string.bcmp
|
||||
libc.src.string.bcopy
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
set(TARGET_PUBLIC_HEADERS
|
||||
libc.include.assert
|
||||
libc.include.ctype
|
||||
libc.include.fenv
|
||||
libc.include.errno
|
||||
libc.include.fenv
|
||||
libc.include.float
|
||||
libc.include.stdint
|
||||
libc.include.inttypes
|
||||
libc.include.math
|
||||
libc.include.setjmp
|
||||
libc.include.stdfix
|
||||
libc.include.stdint
|
||||
libc.include.stdio
|
||||
libc.include.stdlib
|
||||
libc.include.string
|
||||
|
||||
@@ -20,6 +20,10 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
# errno.h entrypoints
|
||||
libc.src.errno.errno
|
||||
|
||||
# setjmp.h entrypoints
|
||||
libc.src.setjmp.longjmp
|
||||
libc.src.setjmp.setjmp
|
||||
|
||||
# string.h entrypoints
|
||||
libc.src.string.bcmp
|
||||
libc.src.string.bcopy
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
set(TARGET_PUBLIC_HEADERS
|
||||
libc.include.ctype
|
||||
libc.include.fenv
|
||||
libc.include.errno
|
||||
libc.include.fenv
|
||||
libc.include.float
|
||||
libc.include.stdint
|
||||
libc.include.inttypes
|
||||
libc.include.math
|
||||
libc.include.stdckdint
|
||||
libc.include.search
|
||||
libc.include.setjmp
|
||||
libc.include.stdbit
|
||||
libc.include.stdckdint
|
||||
libc.include.stdint
|
||||
libc.include.stdlib
|
||||
libc.include.string
|
||||
libc.include.strings
|
||||
libc.include.search
|
||||
libc.include.wchar
|
||||
libc.include.uchar
|
||||
libc.include.wchar
|
||||
|
||||
# Disabled due to epoll_wait syscalls not being available on this platform.
|
||||
# libc.include.sys_epoll
|
||||
|
||||
@@ -32,6 +32,9 @@ typedef struct {
|
||||
#elif defined(__riscv_float_abi_single)
|
||||
#error "__jmp_buf not available for your target architecture."
|
||||
#endif
|
||||
#elif defined(__arm__)
|
||||
// r4, r5, r6, r7, r8, r9, r10, r11, r12, lr
|
||||
long opaque[10];
|
||||
#else
|
||||
#error "__jmp_buf not available for your target architecture."
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define LLVM_LIBC_SETJMP_H
|
||||
|
||||
#include "__llvm-libc-common.h"
|
||||
#include "llvm-libc-types/jmp_buf.h"
|
||||
|
||||
%%public_api()
|
||||
|
||||
|
||||
19
libc/src/setjmp/arm/CMakeLists.txt
Normal file
19
libc/src/setjmp/arm/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
add_entrypoint_object(
|
||||
setjmp
|
||||
SRCS
|
||||
setjmp.cpp
|
||||
HDRS
|
||||
../setjmp_impl.h
|
||||
DEPENDS
|
||||
libc.include.setjmp
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
longjmp
|
||||
SRCS
|
||||
longjmp.cpp
|
||||
HDRS
|
||||
../longjmp.h
|
||||
DEPENDS
|
||||
libc.include.setjmp
|
||||
)
|
||||
74
libc/src/setjmp/arm/longjmp.cpp
Normal file
74
libc/src/setjmp/arm/longjmp.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
//===-- Implementation of longjmp -----------------------------------------===//
|
||||
//
|
||||
// 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/longjmp.h"
|
||||
#include "src/__support/common.h"
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
#if defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 1
|
||||
|
||||
[[gnu::naked, gnu::target("thumb")]]
|
||||
LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
|
||||
asm(R"(
|
||||
# Reload r4, r5, r6, r7.
|
||||
ldmia r0!, {r4-r7}
|
||||
|
||||
# Reload r8, r9. They cannot appear in register lists so load them
|
||||
# into the lower registers, then move them into place.
|
||||
ldmia r0!, {r2-r3}
|
||||
mov r8, r2
|
||||
mov r9, r3
|
||||
|
||||
# Reload r10, r11. They cannot appear in register lists so load them
|
||||
# into the lower registers, then move them into place.
|
||||
ldmia r0!, {r2-r3}
|
||||
mov r10, r2
|
||||
mov r11, r3
|
||||
|
||||
# Reload sp, lr. They cannot appear in register lists so load them
|
||||
# into the lower registers, then move them into place.
|
||||
ldmia r0!, {r2-r3}
|
||||
mov sp, r2
|
||||
mov lr, r3
|
||||
|
||||
# return val ?: 1;
|
||||
movs r0, r1
|
||||
bne .Lret_val
|
||||
movs r0, #1
|
||||
|
||||
.Lret_val:
|
||||
bx lr)");
|
||||
}
|
||||
|
||||
#else // Thumb2 or ARM
|
||||
|
||||
// TODO(https://github.com/llvm/llvm-project/issues/94061): fp registers
|
||||
// (d0-d16)
|
||||
// TODO(https://github.com/llvm/llvm-project/issues/94062): pac+bti
|
||||
[[gnu::naked]]
|
||||
LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
|
||||
asm(R"(
|
||||
# While sp may appear in a register list for ARM mode, it may not for
|
||||
# Thumb2 mode. Just load the previous value of sp into r12 then move it
|
||||
# into sp, so that this code is portable between ARM and Thumb2.
|
||||
|
||||
ldm r0, {r4-r12, lr}
|
||||
mov sp, r12
|
||||
|
||||
# return val ?: 1;
|
||||
movs r0, r1
|
||||
it eq
|
||||
moveq r0, #1
|
||||
bx lr)");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
||||
64
libc/src/setjmp/arm/setjmp.cpp
Normal file
64
libc/src/setjmp/arm/setjmp.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
//===-- Implementation of setjmp ------------------------------------------===//
|
||||
//
|
||||
// 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/common.h"
|
||||
#include "src/setjmp/setjmp_impl.h"
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
#if defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 1
|
||||
|
||||
[[gnu::naked, gnu::target("thumb")]]
|
||||
LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
|
||||
asm(R"(
|
||||
# Store r4, r5, r6, and r7 into buf.
|
||||
stmia r0!, {r4-r7}
|
||||
|
||||
# Store r8, r9, r10, r11, sp, and lr into buf. Thumb(1) doesn't support
|
||||
# the high registers > r7 in stmia, so move them into lower GPRs first.
|
||||
# Thumb(1) also doesn't support using str with sp or lr, move them
|
||||
# together with the rest.
|
||||
mov r1, r8
|
||||
mov r2, r9
|
||||
mov r3, r10
|
||||
stmia r0!, {r1-r3}
|
||||
|
||||
mov r1, r11
|
||||
mov r2, sp
|
||||
mov r3, lr
|
||||
stmia r0!, {r1-r3}
|
||||
|
||||
# Return 0.
|
||||
movs r0, #0
|
||||
bx lr)");
|
||||
}
|
||||
|
||||
#else // Thumb2 or ARM
|
||||
|
||||
// TODO(https://github.com/llvm/llvm-project/issues/94061): fp registers
|
||||
// (d0-d16)
|
||||
// TODO(https://github.com/llvm/llvm-project/issues/94062): pac+bti
|
||||
[[gnu::naked]]
|
||||
LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
|
||||
asm(R"(
|
||||
# While sp may appear in a register list for ARM mode, it may not for
|
||||
# Thumb2 mode. Just move it into r12 then stm that, so that this code
|
||||
# is portable between ARM and Thumb2.
|
||||
mov r12, sp
|
||||
|
||||
# Store r4, r5, r6, r7, r8, r9, r10, r11, sp, and lr into buf.
|
||||
stm r0, {r4-r12, lr}
|
||||
|
||||
# Return zero.
|
||||
mov r0, #0
|
||||
bx lr)");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
||||
Reference in New Issue
Block a user