| //===-- 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" | |
| #include "src/__support/macros/config.h" | |
| namespace LIBC_NAMESPACE_DECL { | |
| #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)"); | |
| } | |
| #elif defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 2 | |
| // 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)"); | |
| } | |
| #else // 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"( | |
| # Store r4, r5, r6, r7, r8, r9, r10, r11, sp, and lr into buf. | |
| ldm r0, {r4-r11, sp, lr} | |
| # return val ?: 1; | |
| movs r0, r1 | |
| moveq r0, #1 | |
| bx lr)"); | |
| } | |
| #endif | |
| } // namespace LIBC_NAMESPACE_DECL |