1 /* This is a simple version of setjmp and longjmp.
3 Nick Clifton, Cygnus Solutions, 13 June 1997. */
5 #include "arm-acle-compat.h"
7 /* ANSI concatenation macros. */
8 #define CONCAT(a, b) CONCAT2(a, b)
9 #define CONCAT2(a, b) a##b
11 #ifndef __USER_LABEL_PREFIX__
12 #error __USER_LABEL_PREFIX__ not defined
15 #define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x)
18 #define TYPE(x) .type SYM(x),function
19 #define SIZE(x) .size SYM(x), . - SYM(x)
25 /* Jump buffer allocation sizes. */
26 #define JUMPBUF_CORE_REGS_SIZE (10 * 4)
27 #define JUMPBUF_FP_REGS_SIZE (8 * 8)
28 #define JUMPBUF_PAC (JUMPBUF_CORE_REGS_SIZE + JUMPBUF_FP_REGS_SIZE + 0)
30 /* Arm/Thumb interworking support:
32 The interworking scheme expects functions to use a BX instruction
33 to return control to their parent. Since we need this code to work
34 in both interworked and non-interworked environments as well as with
35 older processors which do not have the BX instruction we do the
37 Test the return address.
38 If the bottom bit is clear perform an "old style" function exit.
39 (We know that we are in ARM mode and returning to an ARM mode caller).
40 Otherwise use the BX instruction to perform the function exit.
42 We know that we will never attempt to perform the BX instruction on
43 an older processor, because that kind of processor will never be
44 interworked, and a return address with the bottom bit set will never
47 In addition, we do not actually assemble the BX instruction as this would
48 require us to tell the assembler that the processor is an ARM7TDMI and
49 it would store this information in the binary. We want this binary to be
50 able to be linked with binaries compiled for older processors however, so
51 we do not want such information stored there.
53 If we are running using the APCS-26 convention however, then we never
54 test the bottom bit, because this is part of the processor status.
55 Instead we just do a normal return, since we know that we cannot be
56 returning to a Thumb caller - the Thumb does not support APCS-26.
58 Function entry is much simpler. If we are compiling for the Thumb we
59 just switch into ARM mode and then drop through into the rest of the
60 function. The function exit code will take care of the restore to
63 For Thumb-2 do everything in Thumb mode. */
67 /* GCC 12.1 and later will tell the assembler exactly which floating
68 point (or MVE) unit is required and we don't want to override
69 that. Conversely, older versions of the compiler don't pass this
70 information so we need to enable the VFP version that is most
71 appropriate. The choice here should support all suitable VFP
72 versions that the older toolchains can handle. */
73 #if __GNUC__ && __GNUC__ < 12
74 /* Ensure that FPU instructions are correctly compiled and, likewise,
75 the appropriate build attributes are added to the resulting object
76 file. Check whether the MVE extension is present and whether
77 we have support for hardware floating point-operations. VFPxd
78 covers all the cases we need in this file for hardware
79 floating-point and should be compatible with all required FPUs
80 that we need to support. */
84 # if __ARM_FEATURE_MVE
89 #if __ARM_ARCH_ISA_THUMB == 1 && !__ARM_ARCH_ISA_ARM
90 /* ARMv6-M-like has to be implemented in Thumb mode. */
97 /* Save registers in jump buffer. */
98 stmia r0!, {r4, r5, r6, r7}
105 stmia r0!, {r1, r2, r3, r4, r5, r6}
107 /* Restore callee-saved low regs. */
108 ldmia r0!, {r4, r5, r6, r7}
117 /* Restore High regs. */
119 ldmia r0!, {r2, r3, r4, r5, r6}
125 ldmia r0!, {r3} /* lr */
126 /* Restore low regs. */
128 ldmia r0!, {r4, r5, r6, r7}
129 /* Return the result argument, or 1 if it is zero. */
139 #define RET movs pc, lr
140 #elif defined(__thumb2__)
143 #define RET tst lr, #1; \
145 .inst 0xe12fff1e /* bx lr */
149 .macro COND where when
153 .macro COND where when
157 #if defined(__thumb2__)
165 #elif defined(__thumb__)
166 #define MODE .thumb_func
172 SYM (.arm_start_of.\name):
175 #define MODE .code 32
180 .macro FUNC_START name
186 .cfi_sections .debug_frame
200 /* --------------------------------------------------------------------
201 int setjmp (jmp_buf);
202 -------------------------------------------------------------------- */
206 #if __ARM_FEATURE_PAC_DEFAULT
207 # if __ARM_FEATURE_BTI_DEFAULT
211 # endif /* __ARM_FEATURE_BTI_DEFAULT */
213 str r3, [r0, #JUMPBUF_PAC]
214 .cfi_register 143, 12
216 # if __ARM_FEATURE_BTI_DEFAULT
218 # endif /* __ARM_FEATURE_BTI_DEFAULT */
219 #endif /* __ARM_FEATURE_PAC_DEFAULT */
221 /* Save all the callee-preserved registers into the jump buffer. */
224 stmia r0!, { r4-r10, fp, ip, lr }
226 stmia r0!, { r4-r10, fp, sp, lr }
228 #if defined __ARM_FP || defined __ARM_FEATURE_MVE
232 /* When setting up the jump buffer return 0. */
234 #if __ARM_FEATURE_PAC_DEFAULT
237 #endif /* __ARM_FEATURE_PAC_DEFAULT */
241 /* --------------------------------------------------------------------
242 volatile void longjmp (jmp_buf, int);
243 -------------------------------------------------------------------- */
247 #if __ARM_FEATURE_BTI_DEFAULT
249 #endif /* __ARM_FEATURE_BTI_DEFAULT */
251 #if __ARM_FEATURE_PAC_DEFAULT
252 /* Keep original jmpbuf address for retrieving pac-code
253 for authentication. */
255 #endif /* __ARM_FEATURE_PAC_DEFAULT */
257 /* If we have stack extension code it ought to be handled here. */
259 /* Restore the registers, retrieving the state when setjmp() was called. */
261 ldmia r0!, { r4-r10, fp, ip, lr }
264 ldmia r0!, { r4-r10, fp, sp, lr }
266 #if defined __ARM_FP || defined __ARM_FEATURE_MVE
270 /* Put the return value into the integer result register.
271 But if it is zero then return 1 instead. */
276 #if __ARM_FEATURE_PAC_DEFAULT
277 ldr ip, [r2, #JUMPBUF_PAC]
279 #endif /* __ARM_FEATURE_PAC_DEFAULT */