xref: /aosp_15_r20/external/llvm-libc/src/setjmp/arm/longjmp.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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 #include "src/__support/macros/config.h"
13 
14 namespace LIBC_NAMESPACE_DECL {
15 
16 #if defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 1
17 
18 [[gnu::naked, gnu::target("thumb")]] LLVM_LIBC_FUNCTION(void, longjmp,
19                                                         (jmp_buf buf,
20                                                          int val)) {
21   asm(R"(
22       # Reload r4, r5, r6, r7.
23       ldmia r0!, {r4-r7}
24 
25       # Reload r8, r9. They cannot appear in register lists so load them
26       # into the lower registers, then move them into place.
27       ldmia r0!, {r2-r3}
28       mov r8, r2
29       mov r9, r3
30 
31       # Reload r10, r11. They cannot appear in register lists so load them
32       # into the lower registers, then move them into place.
33       ldmia r0!, {r2-r3}
34       mov r10, r2
35       mov r11, r3
36 
37       # Reload sp, lr. They cannot appear in register lists so load them
38       # into the lower registers, then move them into place.
39       ldmia r0!, {r2-r3}
40       mov sp, r2
41       mov lr, r3
42 
43       # return val ?: 1;
44       movs r0, r1
45       bne .Lret_val
46       movs r0, #1
47 
48     .Lret_val:
49       bx lr)");
50 }
51 
52 #else // Thumb2 or ARM
53 
54 // TODO(https://github.com/llvm/llvm-project/issues/94061): fp registers
55 // (d0-d16)
56 // TODO(https://github.com/llvm/llvm-project/issues/94062): pac+bti
57 [[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf buf, int val)) {
58   asm(R"(
59       # While sp may appear in a register list for ARM mode, it may not for
60       # Thumb2 mode. Just load the previous value of sp into r12 then move it
61       # into sp, so that this code is portable between ARM and Thumb2.
62 
63       ldm r0, {r4-r12, lr}
64       mov sp, r12
65 
66       # return val ?: 1;
67       movs r0, r1
68       it eq
69       moveq r0, #1
70       bx lr)");
71 }
72 
73 #endif
74 
75 } // namespace LIBC_NAMESPACE_DECL
76