2 * Copyright (c) 2009 ARM Ltd
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the company may not be used to endorse or promote
14 * products derived from this software without specific prior written
17 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "arm-acle-compat.h"
34 #if __ARM_ARCH >= 7 && defined (__ARM_ARCH_ISA_ARM)
38 #if __ARM_ARCH >= 6 && defined (__ARM_ARCH_ISA_ARM)
46 #if __ARM_ARCH >= 4 && __ARM_ARCH_ISA_THUMB >= 1
50 #if __ARM_ARCH >= 4 && __ARM_ARCH_ISA_THUMB == 0
55 #if __ARM_ARCH_ISA_THUMB >= 2
59 #if __ARM_ARCH_ISA_THUMB >= 1
63 /* Check whether leaf function PAC signing has been requested in the
64 -mbranch-protect compile-time option. */
65 #define LEAF_PROTECT_BIT 2
67 #ifdef __ARM_FEATURE_PAC_DEFAULT
68 # define HAVE_PAC_LEAF \
69 ((__ARM_FEATURE_PAC_DEFAULT & (1 << LEAF_PROTECT_BIT)) && 1)
71 # define HAVE_PAC_LEAF 0
74 /* Provide default parameters for PAC-code handling in leaf-functions. */
76 # ifndef PAC_LEAF_PUSH_IP
77 # define PAC_LEAF_PUSH_IP 1
79 #else /* !HAVE_PAC_LEAF */
80 # undef PAC_LEAF_PUSH_IP
81 # define PAC_LEAF_PUSH_IP 0
82 #endif /* HAVE_PAC_LEAF */
84 #define STACK_ALIGN_ENFORCE 0
88 /******************************************************************************
89 * Implementation of the prologue and epilogue assembler macros and their
90 * associated helper functions.
92 * These functions add support for the following:
94 * - M-profile branch target identification (BTI) landing-pads when compiled
95 * with `-mbranch-protection=bti'.
96 * - PAC-signing and verification instructions, depending on hardware support
97 * and whether the PAC-signing of leaf functions has been requested via the
98 * `-mbranch-protection=pac-ret+leaf' compiler argument.
99 * - 8-byte stack alignment preservation at function entry, defaulting to the
100 * value of STACK_ALIGN_ENFORCE.
103 * - Prologue stack alignment is implemented by detecting a push with an odd
104 * number of registers and prepending a dummy register to the list.
105 * - If alignment is attempted on a list containing r0, compilation will result
107 * - If alignment is attempted in a list containing r1, r0 will be prepended to
108 * the register list and r0 will be restored prior to function return. for
109 * functions with non-void return types, this will result in the corruption of
110 * the result register.
111 * - Stack alignment is enforced via the following helper macro call-chain:
113 * {prologue|epilogue} ->_align8 -> _preprocess_reglist ->
114 * _preprocess_reglist1 -> {_prologue|_epilogue}
116 * - Debug CFI directives are automatically added to prologues and epilogues,
117 * assisted by `cfisavelist' and `cfirestorelist', respectively.
122 * - first - If `last' specified, this serves as start of general-purpose
123 * register (GPR) range to push onto stack, otherwise represents
124 * single GPR to push onto stack. If omitted, no GPRs pushed
125 * onto stack at prologue.
126 * - last - If given, specifies inclusive upper-bound of GPR range.
127 * - push_ip - Determines whether IP register is to be pushed to stack at
128 * prologue. When pac-signing is requested, this holds the
129 * the pac-key. Either 1 or 0 to push or not push, respectively.
130 * Default behavior: Set to value of PAC_LEAF_PUSH_IP macro.
131 * - push_lr - Determines whether to push lr to the stack on function entry.
132 * Either 1 or 0 to push or not push, respectively.
133 * - align8 - Whether to enforce alignment. Either 1 or 0, with 1 requesting
138 * The epilogue should be called passing the same arguments as those passed to
139 * the prologue to ensure the stack is not corrupted on function return.
143 * prologue push_ip=1 -> push {ip}
144 * epilogue push_ip=1, align8=1 -> pop {r2, ip}
145 * prologue push_ip=1, push_lr=1 -> push {ip, lr}
146 * epilogue 1 -> pop {r1}
147 * prologue 1, align8=1 -> push {r0, r1}
148 * epilogue 1, push_ip=1 -> pop {r1, ip}
149 * prologue 1, 4 -> push {r1-r4}
150 * epilogue 1, 4 push_ip=1 -> pop {r1-r4, ip}
152 ******************************************************************************/
154 /* Emit .cfi_restore directives for a consecutive sequence of registers. */
155 .macro cfirestorelist first
, last
158 cfirestorelist
\first
, \last
-1
162 /* Emit .cfi_offset directives for a consecutive sequence of registers. */
163 .macro cfisavelist first
, last
, index
=1
164 .cfi_offset \last
, -4*(\index
)
166 cfisavelist
\first
, \last
-1, \index
+1
170 .macro _prologue first
=-1, last
=-1, push_ip
=PAC_LEAF_PUSH_IP
, push_lr
=0
171 .if \push_ip
& 1 != \push_ip
172 .error
"push_ip may be either 0 or 1"
174 .if \push_lr
& 1 != \push_lr
175 .error
"push_lr may be either 0 or 1"
179 /* Upper-bound not provided: Set upper = lower. */
180 _prologue
\first
, \first
, \push_ip
, \push_lr
185 #if __ARM_FEATURE_BTI_DEFAULT
189 #endif /* __ARM_FEATURE_BTI_DEFAULT */
190 .cfi_register
143, 12
192 #if __ARM_FEATURE_BTI_DEFAULT
194 #endif /* __ARM_FEATURE_BTI_DEFAULT */
195 #endif /* HAVE_PAC_LEAF */
199 .error
"SP cannot be in the save list"
203 /* Case 1: push register range, ip and lr registers. */
204 push
{r
\first
-r\last
, ip
, lr
}
205 .cfi_adjust_cfa_offset ((\last
-\first
)+3)*4
208 cfisavelist
\first
, \last
, 3
210 /* Case 2: push register range and ip register. */
211 push
{r
\first
-r\last
, ip
}
212 .cfi_adjust_cfa_offset ((\last
-\first
)+2)*4
214 cfisavelist
\first
, \last
, 2
218 /* Case 3: push register range and lr register. */
219 push
{r
\first
-r\last
, lr
}
220 .cfi_adjust_cfa_offset ((\last
-\first
)+2)*4
222 cfisavelist
\first
, \last
, 2
224 /* Case 4: push register range. */
225 push
{r
\first
-r\last
}
226 .cfi_adjust_cfa_offset ((\last
-\first
)+1)*4
227 cfisavelist
\first
, \last
, 1
230 .else // \last == \first
233 /* Case 5: push single GP register plus ip and lr registers. */
234 push
{r
\first
, ip
, lr
}
235 .cfi_adjust_cfa_offset
12
238 cfisavelist
\first
, \first
, 3
240 /* Case 6: push single GP register plus ip register. */
242 .cfi_adjust_cfa_offset
8
244 cfisavelist
\first
, \first
, 2
248 /* Case 7: push single GP register plus lr register. */
250 .cfi_adjust_cfa_offset
8
252 cfisavelist
\first
, \first
, 2
254 /* Case 8: push single GP register. */
256 .cfi_adjust_cfa_offset
4
257 cfisavelist
\first
, \first
, 1
261 .else // \first == -1
264 /* Case 9: push ip and lr registers. */
266 .cfi_adjust_cfa_offset
8
270 /* Case 10: push ip register. */
272 .cfi_adjust_cfa_offset
4
277 /* Case 11: push lr register. */
279 .cfi_adjust_cfa_offset
4
286 .macro _epilogue first
=-1, last
=-1, push_ip
=PAC_LEAF_PUSH_IP
, push_lr
=0
287 .if \push_ip
& 1 != \push_ip
288 .error
"push_ip may be either 0 or 1"
290 .if \push_lr
& 1 != \push_lr
291 .error
"push_lr may be either 0 or 1"
295 /* Upper-bound not provided: Set upper = lower. */
296 _epilogue
\first
, \first
, \push_ip
, \push_lr
301 .error
"SP cannot be in the save list"
305 /* Case 1: pop register range, ip and lr registers. */
306 pop
{r
\first
-r\last
, ip
, lr
}
308 .cfi_register
143, 12
309 cfirestorelist
\first
, \last
311 /* Case 2: pop register range and ip register. */
312 pop
{r
\first
-r\last
, ip
}
313 .cfi_register
143, 12
314 cfirestorelist
\first
, \last
318 /* Case 3: pop register range and lr register. */
319 pop
{r
\first
-r\last
, lr
}
321 cfirestorelist
\first
, \last
323 /* Case 4: pop register range. */
325 cfirestorelist
\first
, \last
328 .else // \last == \first
331 /* Case 5: pop single GP register plus ip and lr registers. */
332 pop
{r
\first
, ip
, lr
}
334 .cfi_register
143, 12
335 cfirestorelist
\first
, \first
337 /* Case 6: pop single GP register plus ip register. */
339 .cfi_register
143, 12
340 cfirestorelist
\first
, \first
344 /* Case 7: pop single GP register plus lr register. */
347 cfirestorelist
\first
, \first
349 /* Case 8: pop single GP register. */
351 cfirestorelist
\first
, \first
355 .else // \first == -1
358 /* Case 9: pop ip and lr registers. */
361 .cfi_register
143, 12
363 /* Case 10: pop ip register. */
365 .cfi_register
143, 12
369 /* Case 11: pop lr register. */
377 #endif /* HAVE_PAC_LEAF */
381 # clean up expressions in 'last'
382 .macro _preprocess_reglist1 first
:req
, last
:req
, push_ip
:req
, push_lr
:req
, reglist_op
:req
384 \reglist_op
\first
, 0, \push_ip
, \push_lr
386 \reglist_op
\first
, 1, \push_ip
, \push_lr
388 \reglist_op
\first
, 2, \push_ip
, \push_lr
390 \reglist_op
\first
, 3, \push_ip
, \push_lr
392 \reglist_op
\first
, 4, \push_ip
, \push_lr
394 \reglist_op
\first
, 5, \push_ip
, \push_lr
396 \reglist_op
\first
, 6, \push_ip
, \push_lr
398 \reglist_op
\first
, 7, \push_ip
, \push_lr
400 \reglist_op
\first
, 8, \push_ip
, \push_lr
402 \reglist_op
\first
, 9, \push_ip
, \push_lr
404 \reglist_op
\first
, 10, \push_ip
, \push_lr
406 \reglist_op
\first
, 11, \push_ip
, \push_lr
408 .error
"last (\last) out of range"
412 # clean up expressions in 'first'
413 .macro _preprocess_reglist first
:req
, last
, push_ip
=0, push_lr
=0, reglist_op
:req
415 _preprocess_reglist
\first
\first \push_ip \push_lr
418 .error
"last (\last) must be at least as great as first (\first)"
421 _preprocess_reglist1
0, \last
, \push_ip
, \push_lr
, \reglist_op
423 _preprocess_reglist1
1, \last
, \push_ip
, \push_lr
, \reglist_op
425 _preprocess_reglist1
2, \last
, \push_ip
, \push_lr
, \reglist_op
427 _preprocess_reglist1
3, \last
, \push_ip
, \push_lr
, \reglist_op
429 _preprocess_reglist1
4, \last
, \push_ip
, \push_lr
, \reglist_op
431 _preprocess_reglist1
5, \last
, \push_ip
, \push_lr
, \reglist_op
433 _preprocess_reglist1
6, \last
, \push_ip
, \push_lr
, \reglist_op
435 _preprocess_reglist1
7, \last
, \push_ip
, \push_lr
, \reglist_op
437 _preprocess_reglist1
8, \last
, \push_ip
, \push_lr
, \reglist_op
439 _preprocess_reglist1
9, \last
, \push_ip
, \push_lr
, \reglist_op
441 _preprocess_reglist1
10, \last
, \push_ip
, \push_lr
, \reglist_op
443 _preprocess_reglist1
11, \last
, \push_ip
, \push_lr
, \reglist_op
445 .error
"first (\first) out of range"
450 .macro _align8 first
, last
, push_ip
=0, push_lr
=0, reglist_op
=_prologue
453 .error
"can't have last (\last) without specifying first"
454 .else // \last not blank
455 .if ((\push_ip
+ \push_lr
) % 2) == 0
456 \reglist_op first
=-1, last
=-1, push_ip
=\push_ip
, push_lr
=\push_lr
458 .else // ((\push_ip + \push_lr) % 2) odd
459 _align8
2, 2, \push_ip
, \push_lr
, \reglist_op
461 .endif
// ((\push_ip + \push_lr) % 2) == 0
462 .endif
// .ifnb \last
463 .endif
// .ifb \first
466 _align8
\first
, \first
, \push_ip
, \push_lr
, \reglist_op
468 .if \push_ip
& 1 <> \push_ip
469 .error
"push_ip may be 0 or 1"
471 .if \push_lr
& 1 <> \push_lr
472 .error
"push_lr may be 0 or 1"
474 .ifeq (\last
- \first
+ \push_ip
+ \push_lr
) % 2
476 .error
"Alignment required and first register is r0"
479 _preprocess_reglist
\first
-1, \last
, \push_ip
, \push_lr
, \reglist_op
481 _preprocess_reglist
\first \last
, \push_ip
, \push_lr
, \reglist_op
486 .macro prologue first
, last
, push_ip
=PAC_LEAF_PUSH_IP
, push_lr
=0, align8
=STACK_ALIGN_ENFORCE
488 _align8
\first
, \last
, \push_ip
, \push_lr
, _prologue
490 _prologue first
=\first
, last
=\last
, push_ip
=\push_ip
, push_lr
=\push_lr
494 .macro epilogue first
, last
, push_ip
=PAC_LEAF_PUSH_IP
, push_lr
=0, align8
=STACK_ALIGN_ENFORCE
496 _align8
\first
, \last
, \push_ip
, \push_lr
, reglist_op
=_epilogue
498 _epilogue first
=\first
, last
=\last
, push_ip
=\push_ip
, push_lr
=\push_lr
502 #endif /* __ASSEMBLER__ */
504 #endif /* ARM_ASM__H */