|
12 | 12 |
|
13 | 13 | namespace LIBC_NAMESPACE {
|
14 | 14 |
|
| 15 | +#if defined(__thumb__) && __ARM_ARCH_ISA_THUMB == 1 |
| 16 | + |
| 17 | +[[gnu::naked]] |
| 18 | +LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) { |
| 19 | + asm(R"( |
| 20 | + # Reload r4, r5, r6, r7. |
| 21 | + ldmia r0!, {r4, r5, r6, r7} |
| 22 | +
|
| 23 | + # Reload r8, r9, r10. They cannot appear in register lists so load them |
| 24 | + # into the lower registers, then move them into place. |
| 25 | + ldmia r0!, {r1, r2, r3} |
| 26 | + mov r8, r1 |
| 27 | + mov r9, r2 |
| 28 | + mov r10, r3 |
| 29 | +
|
| 30 | + # Reload r11, sp, lr. They cannot appear in register lists so load them |
| 31 | + # into the lower registers, then move them into place. |
| 32 | + ldmia r0!, {r1, r2, r3} |
| 33 | + mov r11, r1 |
| 34 | + mov sp, r2 |
| 35 | + mov lr, r3 |
| 36 | +
|
| 37 | + # return val ?: 1; |
| 38 | + movs r0, r1 |
| 39 | + beq .Lret_one |
| 40 | + bx lr |
| 41 | +
|
| 42 | + .Lret_one: |
| 43 | + movs r0, #1 |
| 44 | + bx lr)"); |
| 45 | +} |
| 46 | + |
| 47 | +#else // Thumb2 or ARM |
| 48 | + |
15 | 49 | [[gnu::naked]]
|
16 | 50 | LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
|
17 | 51 | asm(R"(
|
| 52 | + # While sp may appear in a register list for ARM mode, it may not for |
| 53 | + # Thumb2 mode. Just load the previous value of sp into r12 then move it |
| 54 | + # into sp, so that this code is portable between ARM and Thumb2. |
| 55 | +
|
18 | 56 | ldm r0, {r4-r12, lr}
|
19 | 57 | mov sp, r12
|
| 58 | +
|
| 59 | + # return val ?: 1; |
20 | 60 | movs r0, r1
|
21 | 61 | it eq
|
22 | 62 | moveq r0, #1
|
23 | 63 | bx lr)");
|
24 | 64 | }
|
25 | 65 |
|
| 66 | +#endif |
| 67 | + |
26 | 68 | } // namespace LIBC_NAMESPACE
|
0 commit comments