]>
Commit | Line | Data |
---|---|---|
d80b3f3c | 1 | /* Assembler macros for ARM. |
568035b7 | 2 | Copyright (C) 1997-2013 Free Software Foundation, Inc. |
d80b3f3c UD |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
3214b89b AJ |
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. | |
d80b3f3c UD |
9 | |
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 | |
3214b89b | 13 | Lesser General Public License for more details. |
d80b3f3c | 14 | |
3214b89b | 15 | You should have received a copy of the GNU Lesser General Public |
ab84e3ff PE |
16 | License along with the GNU C Library. If not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
d80b3f3c UD |
18 | |
19 | #include <sysdeps/generic/sysdep.h> | |
94fd527b | 20 | #include <features.h> |
d80b3f3c | 21 | |
3377126b RH |
22 | /* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */ |
23 | #ifndef __ARM_ARCH | |
24 | # ifdef __ARM_ARCH_2__ | |
25 | # define __ARM_ARCH 2 | |
26 | # elif defined (__ARM_ARCH_3__) || defined (__ARM_ARCH_3M__) | |
27 | # define __ARM_ARCH 3 | |
28 | # elif defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__) | |
29 | # define __ARM_ARCH 4 | |
30 | # elif defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5E__) \ | |
31 | || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \ | |
32 | || defined(__ARM_ARCH_5TEJ__) | |
33 | # define __ARM_ARCH 5 | |
34 | # elif defined (__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ | |
35 | || defined (__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \ | |
36 | || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) | |
37 | # define __ARM_ARCH 6 | |
38 | # elif defined (__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ | |
39 | || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ | |
40 | || defined(__ARM_ARCH_7EM__) | |
41 | # define __ARM_ARCH 7 | |
42 | # else | |
43 | # error unknown arm architecture | |
44 | # endif | |
45 | #endif | |
46 | ||
47 | #if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) | |
48 | # define ARCH_HAS_BX | |
49 | #endif | |
50 | #if __ARM_ARCH > 4 | |
51 | # define ARCH_HAS_BLX | |
52 | #endif | |
79fd8731 RH |
53 | #if __ARM_ARCH > 6 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6ZK__) |
54 | # define ARCH_HAS_HARD_TP | |
55 | #endif | |
3377126b RH |
56 | #if __ARM_ARCH > 6 || defined (__ARM_ARCH_6T2__) |
57 | # define ARCH_HAS_T2 | |
47f0752a RM |
58 | #endif |
59 | ||
e0ebc3b2 | 60 | #ifdef __ASSEMBLER__ |
d80b3f3c UD |
61 | |
62 | /* Syntactic details of assembler. */ | |
63 | ||
0c56aa63 | 64 | #define ALIGNARG(log2) log2 |
d80b3f3c UD |
65 | #define ASM_SIZE_DIRECTIVE(name) .size name,.-name |
66 | ||
fe0955cd UD |
67 | #define PLTJMP(_x) _x##(PLT) |
68 | ||
3377126b | 69 | #ifdef ARCH_HAS_BX |
46dede0c RH |
70 | # define BX(R) bx R |
71 | # define BXC(C, R) bx##C R | |
3377126b | 72 | # ifdef ARCH_HAS_BLX |
46dede0c | 73 | # define BLX(R) blx R |
3377126b RH |
74 | # else |
75 | # define BLX(R) mov lr, pc; bx R | |
46dede0c | 76 | # endif |
644d8224 | 77 | #else |
46dede0c RH |
78 | # define BX(R) mov pc, R |
79 | # define BXC(C, R) mov##C pc, R | |
80 | # define BLX(R) mov lr, pc; mov pc, R | |
d80b3f3c UD |
81 | #endif |
82 | ||
46dede0c RH |
83 | #define DO_RET(R) BX(R) |
84 | #define RETINSTR(C, R) BXC(C, R) | |
85 | ||
d80b3f3c | 86 | /* Define an entry point visible from C. */ |
63cc0e75 RH |
87 | #define ENTRY(name) \ |
88 | .globl C_SYMBOL_NAME(name); \ | |
89 | .type C_SYMBOL_NAME(name),%function; \ | |
90 | .align ALIGNARG(4); \ | |
91 | C_LABEL(name) \ | |
92 | CFI_SECTIONS; \ | |
93 | cfi_startproc; \ | |
94 | CALL_MCOUNT | |
95 | ||
96 | #define CFI_SECTIONS \ | |
97 | .cfi_sections .debug_frame | |
f4564ff0 | 98 | |
d80b3f3c | 99 | #undef END |
63cc0e75 RH |
100 | #define END(name) \ |
101 | cfi_endproc; \ | |
102 | ASM_SIZE_DIRECTIVE(name) | |
d80b3f3c UD |
103 | |
104 | /* If compiled for profiling, call `mcount' at the start of each function. */ | |
105 | #ifdef PROF | |
84664590 JM |
106 | /* Call __gnu_mcount_nc if GCC >= 4.4. */ |
107 | #if __GNUC_PREREQ(4,4) | |
63cc0e75 | 108 | #define CALL_MCOUNT \ |
55668624 | 109 | push {lr}; \ |
63cc0e75 RH |
110 | cfi_adjust_cfa_offset (4); \ |
111 | cfi_rel_offset (lr, 0); \ | |
112 | bl PLTJMP(mcount); \ | |
113 | cfi_adjust_cfa_offset (-4); \ | |
114 | cfi_restore (lr) | |
94fd527b | 115 | #else /* else call _mcount */ |
63cc0e75 | 116 | #define CALL_MCOUNT \ |
55668624 | 117 | push {lr}; \ |
63cc0e75 RH |
118 | cfi_adjust_cfa_offset (4); \ |
119 | cfi_rel_offset (lr, 0); \ | |
120 | bl PLTJMP(mcount); \ | |
55668624 | 121 | pops {lr}; \ |
63cc0e75 RH |
122 | cfi_adjust_cfa_offset (-4); \ |
123 | cfi_restore (lr) | |
94fd527b | 124 | #endif |
d80b3f3c UD |
125 | #else |
126 | #define CALL_MCOUNT /* Do nothing. */ | |
127 | #endif | |
128 | ||
d80b3f3c UD |
129 | /* Since C identifiers are not normally prefixed with an underscore |
130 | on this system, the asm identifier `syscall_error' intrudes on the | |
131 | C name space. Make sure we use an innocuous name. */ | |
132 | #define syscall_error __syscall_error | |
84664590 | 133 | #if __GNUC_PREREQ(4,4) |
94fd527b MM |
134 | #define mcount __gnu_mcount_nc |
135 | #else | |
d80b3f3c UD |
136 | #define mcount _mcount |
137 | #endif | |
138 | ||
27489557 DG |
139 | /* Tag_ABI_align8_preserved: This code preserves 8-byte |
140 | alignment in any callee. */ | |
141 | .eabi_attribute 25, 1 | |
142 | /* Tag_ABI_align8_needed: This code may require 8-byte alignment from | |
143 | the caller. */ | |
144 | .eabi_attribute 24, 1 | |
27489557 | 145 | |
5ff5dfe7 RH |
146 | /* The thumb2 encoding is reasonably complete. Unless suppressed, use it. */ |
147 | .syntax unified | |
148 | # if defined(__thumb2__) && !defined(NO_THUMB) | |
149 | .thumb | |
150 | #else | |
151 | # undef __thumb__ | |
152 | # undef __thumb2__ | |
153 | .arm | |
154 | # endif | |
155 | ||
cd24e113 RH |
156 | /* Load or store to/from a pc-relative EXPR into/from R, using T. */ |
157 | # ifdef __thumb2__ | |
158 | # define LDST_PCREL(OP, R, T, EXPR) \ | |
159 | ldr T, 98f; \ | |
160 | .subsection 2; \ | |
161 | 98: .word EXPR - 99f - PC_OFS; \ | |
162 | .previous; \ | |
163 | 99: add T, T, pc; \ | |
164 | OP R, [T] | |
165 | # else | |
166 | # define LDST_PCREL(OP, R, T, EXPR) \ | |
167 | ldr T, 98f; \ | |
168 | .subsection 2; \ | |
169 | 98: .word EXPR - 99f - PC_OFS; \ | |
170 | .previous; \ | |
171 | 99: OP R, [pc, T] | |
172 | # endif | |
3ae44082 RH |
173 | |
174 | /* Cope with negative memory offsets, which thumb can't encode. | |
175 | Use NEGOFF_ADJ_BASE to (conditionally) alter the base register, | |
176 | and then NEGOFF_OFF1 to use 0 for thumb and the offset for arm, | |
177 | or NEGOFF_OFF2 to use A-B for thumb and A for arm. */ | |
178 | # ifdef __thumb2__ | |
179 | # define NEGOFF_ADJ_BASE(R, OFF) add R, R, $OFF | |
180 | # define NEGOFF_ADJ_BASE2(D, S, OFF) add D, S, $OFF | |
181 | # define NEGOFF_OFF1(R, OFF) [R] | |
182 | # define NEGOFF_OFF2(R, OFFA, OFFB) [R, $((OFFA) - (OFFB))] | |
183 | # else | |
184 | # define NEGOFF_ADJ_BASE(R, OFF) | |
185 | # define NEGOFF_ADJ_BASE2(D, S, OFF) mov D, S | |
186 | # define NEGOFF_OFF1(R, OFF) [R, $OFF] | |
187 | # define NEGOFF_OFF2(R, OFFA, OFFB) [R, $OFFA] | |
188 | # endif | |
5232b909 RH |
189 | |
190 | /* Helper to get the TLS base pointer. The interface is that TMP is a | |
191 | register that may be used to hold the LR, if necessary. TMP may be | |
192 | LR itself to indicate that LR need not be saved. The base pointer | |
79fd8731 | 193 | is returned in R0. Only R0 and TMP are modified. */ |
5232b909 | 194 | |
79fd8731 RH |
195 | # ifdef ARCH_HAS_HARD_TP |
196 | /* If the cpu has cp15 available, use it. */ | |
197 | # define GET_TLS(TMP) mrc p15, 0, r0, c13, c0, 3 | |
198 | # else | |
199 | /* At this generic level we have no tricks to pull. Call the ABI routine. */ | |
200 | # define GET_TLS(TMP) \ | |
5232b909 RH |
201 | push { r1, r2, r3, lr }; \ |
202 | cfi_remember_state; \ | |
203 | cfi_adjust_cfa_offset (16); \ | |
204 | cfi_rel_offset (r1, 0); \ | |
205 | cfi_rel_offset (r2, 4); \ | |
206 | cfi_rel_offset (r3, 8); \ | |
207 | cfi_rel_offset (lr, 12); \ | |
208 | bl __aeabi_read_tp; \ | |
209 | pop { r1, r2, r3, lr }; \ | |
210 | cfi_restore_state | |
79fd8731 | 211 | # endif /* ARCH_HAS_HARD_TP */ |
5232b909 | 212 | |
a7ac7522 RM |
213 | # ifndef ARM_SFI_MACROS |
214 | # define ARM_SFI_MACROS 1 | |
215 | /* This assembly macro is prepended to any load/store instruction, | |
216 | pulling the base register out of the addressing mode syntax and | |
217 | making it the first operand of the macro. For example: | |
218 | ldr r0, [r1] | |
219 | becomes: | |
220 | sfi_breg r1, ldr r0, [\B] | |
221 | The \B stands in for the base register that is the first operand | |
222 | to the macro, so we can avoid error-prone repetition of the base | |
223 | register in two places on the line. | |
224 | ||
225 | This is used for all memory access through a base register other | |
226 | than PC or SP. It's intended to support SFI schemes such as | |
227 | Native Client, where the OS will enforce that all load/store | |
228 | instructions use a special form. In any such configuration, | |
229 | another sysdep.h file will have defined ARM_SFI_MACROS and | |
230 | provided its own assembly macros with the same interface. */ | |
231 | ||
232 | .macro sfi_breg basereg, insn, operands:vararg | |
233 | .macro _sfi_breg_doit B | |
234 | \insn \operands | |
235 | .endm | |
236 | _sfi_breg_doit \basereg | |
237 | .purgem _sfi_breg_doit | |
238 | .endm | |
239 | ||
240 | /* This assembly macro replaces the "pld" instruction. | |
241 | The syntax: | |
242 | sfi_pld REGISTER, #OFFSET | |
243 | is exactly equivalent to: | |
244 | sfi_breg REGISTER, pld [\B, #OFFSET] | |
245 | (and ", #OFFSET" is optional). We have a separate macro | |
246 | only to work around a bug in GAS versions prior to 2.23.2, | |
247 | that misparses the sfi_breg macro expansion in this case. */ | |
248 | ||
249 | .macro sfi_pld basereg, offset=#0 | |
250 | pld [\basereg, \offset] | |
251 | .endm | |
252 | ||
1362a2aa RM |
253 | /* This macro precedes any instruction that directly changes the SP. |
254 | It's not needed for push/pop or for any kind of load or store that | |
255 | implicitly changes the SP via the ! syntax. */ | |
256 | # define sfi_sp /* Nothing to do. */ | |
257 | ||
a7ac7522 RM |
258 | # endif |
259 | ||
e0ebc3b2 | 260 | #endif /* __ASSEMBLER__ */ |
783a65c2 RH |
261 | |
262 | /* This number is the offset from the pc at the current location. */ | |
5ff5dfe7 | 263 | #ifdef __thumb__ |
783a65c2 RH |
264 | # define PC_OFS 4 |
265 | #else | |
266 | # define PC_OFS 8 | |
267 | #endif |