Cygwin: access: Fix X_OK behaviour for backup operators and admins
[newlib-cygwin.git] / newlib / libc / machine / arm / setjmp.S
blob0070f17cdcef9e1b70aeded257019a55d61f035e
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
13 #endif
15 #define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x)
17 #ifdef __ELF__
18 #define TYPE(x) .type SYM(x),function
19 #define SIZE(x) .size SYM(x), . - SYM(x)
20 #else
21 #define TYPE(x)
22 #define SIZE(x)
23 #endif
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
36    following:
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
45    be generated.
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
61    Thumb mode.
63    For Thumb-2 do everything in Thumb mode.  */
65         .syntax unified
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.  */
81 # if __ARM_FP
82         .fpu vfpxd
83 # endif
84 # if __ARM_FEATURE_MVE
85         .arch_extension mve
86 # endif
87 #endif
89 #if __ARM_ARCH_ISA_THUMB == 1 && !__ARM_ARCH_ISA_ARM
90 /* ARMv6-M-like has to be implemented in Thumb mode.  */
92 .thumb
93 .thumb_func
94         .globl SYM (setjmp)
95         TYPE (setjmp)
96 SYM (setjmp):
97         /* Save registers in jump buffer.  */
98         stmia   r0!, {r4, r5, r6, r7}
99         mov     r1, r8
100         mov     r2, r9
101         mov     r3, r10
102         mov     r4, fp
103         mov     r5, sp
104         mov     r6, lr
105         stmia   r0!, {r1, r2, r3, r4, r5, r6}
106         subs    r0, r0, #40
107         /* Restore callee-saved low regs.  */
108         ldmia   r0!, {r4, r5, r6, r7}
109         /* Return zero.  */
110         movs    r0, #0
111         bx lr
113 .thumb_func
114         .globl SYM (longjmp)
115         TYPE (longjmp)
116 SYM (longjmp):
117         /* Restore High regs.  */
118         adds    r0, r0, #16
119         ldmia   r0!, {r2, r3, r4, r5, r6}
120         mov     r8, r2
121         mov     r9, r3
122         mov     r10, r4
123         mov     fp, r5
124         mov     sp, r6
125         ldmia   r0!, {r3} /* lr */
126         /* Restore low regs.  */
127         subs    r0, r0, #40
128         ldmia   r0!, {r4, r5, r6, r7}
129         /* Return the result argument, or 1 if it is zero.  */
130         movs    r0, r1
131         bne     1f
132         movs    r0, #1
134         bx      r3
136 #else
138 #ifdef __APCS_26__
139 #define RET     movs            pc, lr
140 #elif defined(__thumb2__)
141 #define RET     bx lr
142 #else
143 #define RET     tst             lr, #1; \
144                 moveq           pc, lr ; \
145 .inst           0xe12fff1e      /* bx lr */
146 #endif
148 #ifdef __thumb2__
149 .macro COND where when
150         i\where \when
151 .endm
152 #else
153 .macro COND where when
154 .endm
155 #endif
157 #if defined(__thumb2__)
158 .macro MODE
159         .thumb
160         .thumb_func
161 .endm
162 .macro PROLOGUE name
163 .endm
165 #elif defined(__thumb__)
166 #define MODE            .thumb_func
167 .macro PROLOGUE name
168         .code 16
169         bx      pc
170         nop
171         .code 32
172 SYM (.arm_start_of.\name):
173 .endm
174 #else /* Arm */
175 #define MODE            .code 32
176 .macro PROLOGUE name
177 .endm
178 #endif
180 .macro FUNC_START name
181         .text
182         .align 2
183         MODE
184         .globl SYM (\name)
185         .fnstart
186         .cfi_sections .debug_frame
187         .cfi_startproc
188         TYPE (\name)
189 SYM (\name):
190         PROLOGUE \name
191 .endm
193 .macro FUNC_END name
194         RET
195         .cfi_endproc
196         .fnend
197         SIZE (\name)
198 .endm
200 /* --------------------------------------------------------------------
201                  int setjmp (jmp_buf);
202    -------------------------------------------------------------------- */
204         FUNC_START setjmp
206 #if __ARM_FEATURE_PAC_DEFAULT
207 # if __ARM_FEATURE_BTI_DEFAULT
208         pacbti  ip, lr, sp
209 # else
210         pac     ip, lr, sp
211 # endif /* __ARM_FEATURE_BTI_DEFAULT */
212         mov r3, ip
213         str r3, [r0, #JUMPBUF_PAC]
214         .cfi_register 143, 12
215 #else
216 # if __ARM_FEATURE_BTI_DEFAULT
217         bti
218 # endif /* __ARM_FEATURE_BTI_DEFAULT */
219 #endif /* __ARM_FEATURE_PAC_DEFAULT */
221         /* Save all the callee-preserved registers into the jump buffer.  */
222 #ifdef __thumb2__
223         mov             ip, sp
224         stmia           r0!, { r4-r10, fp, ip, lr }
225 #else
226         stmia           r0!, { r4-r10, fp, sp, lr }
227 #endif
228 #if defined __ARM_FP || defined __ARM_FEATURE_MVE
229         vstm            r0, { d8-d15 }
230 #endif
232         /* When setting up the jump buffer return 0.  */
233         mov             r0, #0
234 #if __ARM_FEATURE_PAC_DEFAULT
235         mov ip, r3
236         aut ip, lr, sp
237 #endif /* __ARM_FEATURE_PAC_DEFAULT */
239         FUNC_END setjmp
241 /* --------------------------------------------------------------------
242                 volatile void longjmp (jmp_buf, int);
243    -------------------------------------------------------------------- */
245         FUNC_START longjmp
247 #if __ARM_FEATURE_BTI_DEFAULT
248         bti
249 #endif /* __ARM_FEATURE_BTI_DEFAULT */
251 #if __ARM_FEATURE_PAC_DEFAULT
252         /* Keep original jmpbuf address for retrieving pac-code
253            for authentication.  */
254         mov     r2, r0
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.  */
260 #ifdef __thumb2__
261         ldmia           r0!, { r4-r10, fp, ip, lr }
262         mov             sp, ip
263 #else
264         ldmia           r0!, { r4-r10, fp, sp, lr }
265 #endif
266 #if defined __ARM_FP || defined __ARM_FEATURE_MVE
267         vldm            r0, { d8-d15 }
268 #endif
270         /* Put the return value into the integer result register.
271            But if it is zero then return 1 instead.  */
272         movs            r0, r1
273         it              eq
274         moveq           r0, #1
276 #if __ARM_FEATURE_PAC_DEFAULT
277         ldr ip, [r2, #JUMPBUF_PAC]
278         aut ip, lr, sp
279 #endif /* __ARM_FEATURE_PAC_DEFAULT */
281         FUNC_END longjmp
282 #endif