1 /* Assembler macros for ARM.
2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library. If not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <sysdeps/generic/sysdep.h>
25 # include <arm-features.h>
28 /* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */
30 # ifdef __ARM_ARCH_2__
32 # elif defined (__ARM_ARCH_3__) || defined (__ARM_ARCH_3M__)
34 # elif defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__)
36 # elif defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5E__) \
37 || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \
38 || defined(__ARM_ARCH_5TEJ__)
40 # elif defined (__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
41 || defined (__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \
42 || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
44 # elif defined (__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
45 || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
46 || defined(__ARM_ARCH_7EM__)
49 # error unknown arm architecture
53 #if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__)
59 #if __ARM_ARCH > 6 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6ZK__)
60 # define ARCH_HAS_HARD_TP
62 #if __ARM_ARCH > 6 || defined (__ARM_ARCH_6T2__)
68 /* Syntactic details of assembler. */
70 #define ALIGNARG(log2) log2
71 #define ASM_SIZE_DIRECTIVE(name) .size name,.-name
73 #define PLTJMP(_x) _x##(PLT)
77 # define BXC(C, R) bx##C R
81 # define BLX(R) mov lr, pc; bx R
84 # define BX(R) mov pc, R
85 # define BXC(C, R) mov##C pc, R
86 # define BLX(R) mov lr, pc; mov pc, R
89 #define DO_RET(R) BX(R)
90 #define RETINSTR(C, R) BXC(C, R)
92 /* Define an entry point visible from C. */
94 .globl C_SYMBOL_NAME(name); \
95 .type C_SYMBOL_NAME(name),%function; \
102 #define CFI_SECTIONS \
103 .cfi_sections .debug_frame
108 ASM_SIZE_DIRECTIVE(name)
110 /* If compiled for profiling, call `mcount' at the start of each function. */
112 /* Call __gnu_mcount_nc (GCC >= 4.4). */
113 #define CALL_MCOUNT \
115 cfi_adjust_cfa_offset (4); \
116 cfi_rel_offset (lr, 0); \
118 cfi_adjust_cfa_offset (-4); \
121 #define CALL_MCOUNT /* Do nothing. */
124 /* Since C identifiers are not normally prefixed with an underscore
125 on this system, the asm identifier `syscall_error' intrudes on the
126 C name space. Make sure we use an innocuous name. */
127 #define syscall_error __syscall_error
128 #define mcount __gnu_mcount_nc
130 /* Tag_ABI_align8_preserved: This code preserves 8-byte
131 alignment in any callee. */
132 .eabi_attribute
25, 1
133 /* Tag_ABI_align8_needed: This code may require 8-byte alignment from
135 .eabi_attribute
24, 1
137 /* The thumb2 encoding is reasonably complete. Unless suppressed, use it. */
139 # if defined(__thumb2__) && !defined(NO_THUMB)
147 /* Load or store to/from address X + Y into/from R, (maybe) using T.
148 X or Y can use T freely; T can be R if OP is a load. The first
149 version eschews the two-register addressing mode, while the
150 second version uses it. */
151 # define LDST_INDEXED_NOINDEX(OP, R, T, X, Y) \
154 # define LDST_INDEXED_INDEX(OP, R, X, Y) \
157 # ifdef ARM_NO_INDEX_REGISTER
158 /* We're never using the two-register addressing mode, so this
159 always uses an intermediate add. */
160 # define LDST_INDEXED(OP, R, T, X, Y) LDST_INDEXED_NOINDEX (OP, R, T, X, Y)
161 # define LDST_PC_INDEXED(OP, R, T, X) LDST_INDEXED_NOINDEX (OP, R, T, pc, X)
163 /* The two-register addressing mode is OK, except on Thumb with pc. */
164 # define LDST_INDEXED(OP, R, T, X, Y) LDST_INDEXED_INDEX (OP, R, X, Y)
166 # define LDST_PC_INDEXED(OP, R, T, X) LDST_INDEXED_NOINDEX (OP, R, T, pc, X)
168 # define LDST_PC_INDEXED(OP, R, T, X) LDST_INDEXED_INDEX (OP, R, pc, X)
172 /* Load or store to/from a pc-relative EXPR into/from R, using T. */
174 # define LDST_PCREL(OP, R, T, EXPR) \
177 98: .word EXPR - 99f - PC_OFS; \
181 # elif defined (ARCH_HAS_T2) && ARM_PCREL_MOVW_OK
182 # define LDST_PCREL(OP, R, T, EXPR) \
183 movw T, #:lower16:EXPR - 99f - PC_OFS; \
184 movt T, #:upper16:EXPR - 99f - PC_OFS; \
185 99: LDST_PC_INDEXED (OP, R, T, T)
187 # define LDST_PCREL(OP, R, T, EXPR) \
190 98: .word EXPR - 99f - PC_OFS; \
195 /* Load from a global SYMBOL + CONSTANT into R, using T. */
196 # if defined (ARCH_HAS_T2) && !defined (PIC)
197 # define LDR_GLOBAL(R, T, SYMBOL, CONSTANT) \
198 movw T, #:lower16:SYMBOL; \
199 movt T, #:upper16:SYMBOL; \
200 ldr R, [T, $CONSTANT]
201 # elif defined (ARCH_HAS_T2) && defined (PIC) && ARM_PCREL_MOVW_OK
202 # define LDR_GLOBAL(R, T, SYMBOL, CONSTANT) \
203 movw R, #:lower16:_GLOBAL_OFFSET_TABLE_ - 97f - PC_OFS; \
204 movw T, #:lower16:99f - 98f - PC_OFS; \
205 movt R, #:upper16:_GLOBAL_OFFSET_TABLE_ - 97f - PC_OFS; \
206 movt T, #:upper16:99f - 98f - PC_OFS; \
207 .pushsection .rodata.cst4, "aM", %progbits, 4; \
209 99: .word SYMBOL##(GOT); \
212 98: LDST_PC_INDEXED (ldr, T, T, T); \
213 LDST_INDEXED (ldr, R, T, R, T); \
214 ldr R, [R, $CONSTANT]
216 # define LDR_GLOBAL(R, T, SYMBOL, CONSTANT) \
222 99: .word _GLOBAL_OFFSET_TABLE_ - 98b - PC_OFS; \
223 100: .word SYMBOL##(GOT); \
225 ldr R, [T, $CONSTANT]
228 /* This is the same as LDR_GLOBAL, but for a SYMBOL that is known to
229 be in the same linked object (as for one with hidden visibility).
230 We can avoid the GOT indirection in the PIC case. For the pure
231 static case, LDR_GLOBAL is already optimal. */
233 # define LDR_HIDDEN(R, T, SYMBOL, CONSTANT) \
234 LDST_PCREL (ldr, R, T, SYMBOL + CONSTANT)
236 # define LDR_HIDDEN(R, T, SYMBOL, CONSTANT) \
237 LDR_GLOBAL (R, T, SYMBOL, CONSTANT)
240 /* Cope with negative memory offsets, which thumb can't encode.
241 Use NEGOFF_ADJ_BASE to (conditionally) alter the base register,
242 and then NEGOFF_OFF1 to use 0 for thumb and the offset for arm,
243 or NEGOFF_OFF2 to use A-B for thumb and A for arm. */
245 # define NEGOFF_ADJ_BASE(R, OFF) add R, R, $OFF
246 # define NEGOFF_ADJ_BASE2(D, S, OFF) add D, S, $OFF
247 # define NEGOFF_OFF1(R, OFF) [R]
248 # define NEGOFF_OFF2(R, OFFA, OFFB) [R, $((OFFA) - (OFFB))]
250 # define NEGOFF_ADJ_BASE(R, OFF)
251 # define NEGOFF_ADJ_BASE2(D, S, OFF) mov D, S
252 # define NEGOFF_OFF1(R, OFF) [R, $OFF]
253 # define NEGOFF_OFF2(R, OFFA, OFFB) [R, $OFFA]
256 /* Helper to get the TLS base pointer. The interface is that TMP is a
257 register that may be used to hold the LR, if necessary. TMP may be
258 LR itself to indicate that LR need not be saved. The base pointer
259 is returned in R0. Only R0 and TMP are modified. */
261 # ifdef ARCH_HAS_HARD_TP
262 /* If the cpu has cp15 available, use it. */
263 # define GET_TLS(TMP) mrc p15, 0, r0, c13, c0, 3
265 /* At this generic level we have no tricks to pull. Call the ABI routine. */
266 # define GET_TLS(TMP) \
267 push { r1, r2, r3, lr }; \
268 cfi_remember_state; \
269 cfi_adjust_cfa_offset (16); \
270 cfi_rel_offset (r1, 0); \
271 cfi_rel_offset (r2, 4); \
272 cfi_rel_offset (r3, 8); \
273 cfi_rel_offset (lr, 12); \
274 bl __aeabi_read_tp; \
275 pop { r1, r2, r3, lr }; \
277 # endif /* ARCH_HAS_HARD_TP */
279 /* These are the directives used for EABI unwind info.
280 Wrap them in macros so another configuration's sysdep.h
281 file can define them away if it doesn't use EABI unwind info. */
282 # define eabi_fnstart .fnstart
283 # define eabi_fnend .fnend
284 # define eabi_save(...) .save __VA_ARGS__
285 # define eabi_cantunwind .cantunwind
286 # define eabi_pad(n) .pad n
288 #endif /* __ASSEMBLER__ */
290 /* This number is the offset from the pc at the current location. */