arm: Introduce and use LDST_PCREL
[glibc.git] / ports / sysdeps / unix / sysv / linux / arm / nptl / sysdep-cancel.h
blob8889369ae3eae57a4a7d47b8f592460ea2b506f1
1 /* Copyright (C) 2003-2013 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library. If not, see
16 <http://www.gnu.org/licenses/>. */
18 #include <sysdep.h>
19 #include <tls.h>
20 #ifndef __ASSEMBLER__
21 # include <nptl/pthreadP.h>
22 #endif
24 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
26 /* NOTE: We do mark syscalls with unwind annotations, for the benefit of
27 cancellation; but they're really only accurate at the point of the
28 syscall. The ARM unwind directives are not rich enough without adding
29 a custom personality function. */
31 # undef PSEUDO
32 # define PSEUDO(name, syscall_name, args) \
33 .text; \
34 ENTRY (__##syscall_name##_nocancel); \
35 CFI_SECTIONS; \
36 DO_CALL (syscall_name, args); \
37 cmn r0, $4096; \
38 PSEUDO_RET; \
39 END (__##syscall_name##_nocancel); \
40 ENTRY (name); \
41 SINGLE_THREAD_P; \
42 DOARGS_##args; \
43 bne .Lpseudo_cancel; \
44 cfi_remember_state; \
45 ldr r7, =SYS_ify (syscall_name); \
46 swi 0x0; \
47 UNDOARGS_##args; \
48 cmn r0, $4096; \
49 PSEUDO_RET; \
50 cfi_restore_state; \
51 .Lpseudo_cancel: \
52 .fnstart; /* matched by the .fnend in UNDOARGS below. */ \
53 DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \
54 CENABLE; \
55 mov ip, r0; /* put mask in safe place. */ \
56 UNDOCARGS_##args; /* restore syscall args. */ \
57 ldr r7, =SYS_ify (syscall_name); \
58 swi 0x0; /* do the call. */ \
59 mov r7, r0; /* save syscall return value. */ \
60 mov r0, ip; /* get mask back. */ \
61 CDISABLE; \
62 mov r0, r7; /* retrieve return value. */ \
63 RESTORE_LR_##args; \
64 UNDOARGS_##args; \
65 cmn r0, $4096
67 /* DOARGS pushes eight bytes on the stack for five arguments, twelve bytes for
68 six arguments, and four bytes for fewer. In order to preserve doubleword
69 alignment, sometimes we must save an extra register. */
71 # define RESTART_UNWIND \
72 .fnend; \
73 .fnstart; \
74 .save {r7}; \
75 .save {lr}
77 # define DOCARGS_0 \
78 .save {r7}; \
79 str lr, [sp, #-4]!; \
80 cfi_adjust_cfa_offset (4); \
81 cfi_rel_offset (lr, 0); \
82 .save {lr}
83 # define UNDOCARGS_0
84 # define RESTORE_LR_0 \
85 ldr lr, [sp], #4; \
86 cfi_adjust_cfa_offset (-4); \
87 cfi_restore (lr)
89 # define DOCARGS_1 \
90 .save {r7}; \
91 stmfd sp!, {r0, r1, lr}; \
92 cfi_adjust_cfa_offset (12); \
93 cfi_rel_offset (lr, 8); \
94 .save {lr}; \
95 .pad #8
96 # define UNDOCARGS_1 \
97 ldr r0, [sp], #8; \
98 cfi_adjust_cfa_offset (-8); \
99 RESTART_UNWIND
100 # define RESTORE_LR_1 \
101 RESTORE_LR_0
103 # define DOCARGS_2 \
104 .save {r7}; \
105 stmfd sp!, {r0, r1, lr}; \
106 cfi_adjust_cfa_offset (12); \
107 cfi_rel_offset (lr, 8); \
108 .save {lr}; \
109 .pad #8
110 # define UNDOCARGS_2 \
111 ldmfd sp!, {r0, r1}; \
112 cfi_adjust_cfa_offset (-8); \
113 RESTART_UNWIND
114 # define RESTORE_LR_2 \
115 RESTORE_LR_0
117 # define DOCARGS_3 \
118 .save {r7}; \
119 stmfd sp!, {r0, r1, r2, r3, lr}; \
120 cfi_adjust_cfa_offset (20); \
121 cfi_rel_offset (lr, 16); \
122 .save {lr}; \
123 .pad #16
124 # define UNDOCARGS_3 \
125 ldmfd sp!, {r0, r1, r2, r3}; \
126 cfi_adjust_cfa_offset (-16); \
127 RESTART_UNWIND
128 # define RESTORE_LR_3 \
129 RESTORE_LR_0
131 # define DOCARGS_4 \
132 .save {r7}; \
133 stmfd sp!, {r0, r1, r2, r3, lr}; \
134 cfi_adjust_cfa_offset (20); \
135 cfi_rel_offset (lr, 16); \
136 .save {lr}; \
137 .pad #16
138 # define UNDOCARGS_4 \
139 ldmfd sp!, {r0, r1, r2, r3}; \
140 cfi_adjust_cfa_offset (-16); \
141 RESTART_UNWIND
142 # define RESTORE_LR_4 \
143 RESTORE_LR_0
145 /* r4 is only stmfd'ed for correct stack alignment. */
146 # define DOCARGS_5 \
147 .save {r4, r7}; \
148 stmfd sp!, {r0, r1, r2, r3, r4, lr}; \
149 cfi_adjust_cfa_offset (24); \
150 cfi_rel_offset (lr, 20); \
151 .save {lr}; \
152 .pad #20
153 # define UNDOCARGS_5 \
154 ldmfd sp!, {r0, r1, r2, r3}; \
155 cfi_adjust_cfa_offset (-16); \
156 .fnend; \
157 .fnstart; \
158 .save {r4, r7}; \
159 .save {lr}; \
160 .pad #4
161 # define RESTORE_LR_5 \
162 ldmfd sp!, {r4, lr}; \
163 cfi_adjust_cfa_offset (-8); \
164 /* r4 will be marked as restored later. */ \
165 cfi_restore (lr)
167 # define DOCARGS_6 \
168 .save {r4, r5, r7}; \
169 stmfd sp!, {r0, r1, r2, r3, lr}; \
170 cfi_adjust_cfa_offset (20); \
171 cfi_rel_offset (lr, 16); \
172 .save {lr}; \
173 .pad #16
174 # define UNDOCARGS_6 \
175 ldmfd sp!, {r0, r1, r2, r3}; \
176 cfi_adjust_cfa_offset (-16); \
177 .fnend; \
178 .fnstart; \
179 .save {r4, r5, r7}; \
180 .save {lr};
181 # define RESTORE_LR_6 \
182 RESTORE_LR_0
184 # ifdef IS_IN_libpthread
185 # define CENABLE bl PLTJMP(__pthread_enable_asynccancel)
186 # define CDISABLE bl PLTJMP(__pthread_disable_asynccancel)
187 # define __local_multiple_threads __pthread_multiple_threads
188 # elif !defined NOT_IN_libc
189 # define CENABLE bl PLTJMP(__libc_enable_asynccancel)
190 # define CDISABLE bl PLTJMP(__libc_disable_asynccancel)
191 # define __local_multiple_threads __libc_multiple_threads
192 # elif defined IS_IN_librt
193 # define CENABLE bl PLTJMP(__librt_enable_asynccancel)
194 # define CDISABLE bl PLTJMP(__librt_disable_asynccancel)
195 # else
196 # error Unsupported library
197 # endif
199 # if defined IS_IN_libpthread || !defined NOT_IN_libc
200 # ifndef __ASSEMBLER__
201 extern int __local_multiple_threads attribute_hidden;
202 # define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
203 # else
204 # define SINGLE_THREAD_P \
205 LDST_PCREL(ldr, ip, ip, __local_multiple_threads); \
206 teq ip, #0
207 # endif
208 # else
209 /* There is no __local_multiple_threads for librt, so use the TCB. */
210 # ifndef __ASSEMBLER__
211 # define SINGLE_THREAD_P \
212 __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
213 header.multiple_threads) == 0, 1)
214 # else
215 # define SINGLE_THREAD_P \
216 stmfd sp!, {r0, lr}; \
217 cfi_adjust_cfa_offset (8); \
218 cfi_rel_offset (lr, 4); \
219 bl __aeabi_read_tp; \
220 ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \
221 ldmfd sp!, {r0, lr}; \
222 cfi_adjust_cfa_offset (-8); \
223 cfi_restore (lr); \
224 teq ip, #0
225 # define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
226 # endif
227 # endif
229 #elif !defined __ASSEMBLER__
231 /* For rtld, et cetera. */
232 # define SINGLE_THREAD_P 1
233 # define NO_CANCELLATION 1
235 #endif
237 #ifndef __ASSEMBLER__
238 # define RTLD_SINGLE_THREAD_P \
239 __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
240 header.multiple_threads) == 0, 1)
241 #endif