1 /* Copyright (C) 2003, 2004, 2005, 2009 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/>. */
19 #include <tcb-offsets.h>
21 # include <pthreadP.h>
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. */
32 # define PSEUDO(name, syscall_name, args) \
35 .type __##syscall_name##_nocancel,%function; \
36 .globl __##syscall_name##_nocancel; \
37 __##syscall_name##_nocancel: \
38 cfi_sections(.debug_frame); \
40 DO_CALL (syscall_name, args); \
43 .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
47 bne .Lpseudo_cancel; \
49 DO_CALL (syscall_name, 0); \
56 DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \
58 mov ip, r0; /* put mask in safe place. */ \
59 UNDOCARGS_##args; /* restore syscall args. */ \
60 ldr r7, =SYS_ify (syscall_name); \
61 swi 0x0; /* do the call. */ \
62 .fnend; /* Past here we can't easily unwind. */ \
63 mov r7, r0; /* save syscall return value. */ \
64 mov r0, ip; /* get mask back. */ \
66 mov r0, r7; /* retrieve return value. */ \
71 /* DOARGS pushes four bytes on the stack for five arguments, eight bytes for
72 six arguments, and nothing for fewer. In order to preserve doubleword
73 alignment, sometimes we must save an extra register. */
75 # define RESTART_UNWIND \
81 stmfd sp!, {r7, lr}; \
82 cfi_adjust_cfa_offset (8); \
83 cfi_rel_offset (r7, 0); \
84 cfi_rel_offset (lr, 4); \
87 # define RESTORE_LR_0 \
88 ldmfd sp!, {r7, lr}; \
89 cfi_adjust_cfa_offset (-8); \
94 stmfd sp!, {r0, r1, r7, lr}; \
95 cfi_adjust_cfa_offset (16); \
96 cfi_rel_offset (r7, 8); \
97 cfi_rel_offset (lr, 12); \
100 # define UNDOCARGS_1 \
102 cfi_adjust_cfa_offset (-8); \
104 # define RESTORE_LR_1 \
108 stmfd sp!, {r0, r1, r7, lr}; \
109 cfi_adjust_cfa_offset (16); \
110 cfi_rel_offset (r7, 8); \
111 cfi_rel_offset (lr, 12); \
114 # define UNDOCARGS_2 \
115 ldmfd sp!, {r0, r1}; \
116 cfi_adjust_cfa_offset (-8); \
118 # define RESTORE_LR_2 \
122 stmfd sp!, {r0, r1, r2, r3, r7, lr}; \
123 cfi_adjust_cfa_offset (24); \
124 cfi_rel_offset (r7, 16); \
125 cfi_rel_offset (lr, 20); \
128 # define UNDOCARGS_3 \
129 ldmfd sp!, {r0, r1, r2, r3}; \
130 cfi_adjust_cfa_offset (-16); \
132 # define RESTORE_LR_3 \
136 stmfd sp!, {r0, r1, r2, r3, r7, lr}; \
137 cfi_adjust_cfa_offset (24); \
138 cfi_rel_offset (r7, 16); \
139 cfi_rel_offset (lr, 20); \
142 # define UNDOCARGS_4 \
143 ldmfd sp!, {r0, r1, r2, r3}; \
144 cfi_adjust_cfa_offset (-16); \
146 # define RESTORE_LR_4 \
149 /* r4 is only stmfd'ed for correct stack alignment. */
152 stmfd sp!, {r0, r1, r2, r3, r4, r7, lr}; \
153 cfi_adjust_cfa_offset (28); \
154 cfi_rel_offset (r7, 20); \
155 cfi_rel_offset (lr, 24); \
158 # define UNDOCARGS_5 \
159 ldmfd sp!, {r0, r1, r2, r3}; \
160 cfi_adjust_cfa_offset (-16); \
166 # define RESTORE_LR_5 \
167 ldmfd sp!, {r4, r7, lr}; \
168 cfi_adjust_cfa_offset (-12); \
169 /* r4 will be marked as restored later. */ \
175 stmfd sp!, {r0, r1, r2, r3, r7, lr}; \
176 cfi_adjust_cfa_offset (24); \
177 cfi_rel_offset (r7, 16); \
178 cfi_rel_offset (lr, 20); \
181 # define UNDOCARGS_6 \
182 ldmfd sp!, {r0, r1, r2, r3}; \
183 cfi_adjust_cfa_offset (-16); \
188 # define RESTORE_LR_6 \
191 # ifdef IS_IN_libpthread
192 # define CENABLE bl PLTJMP(__pthread_enable_asynccancel)
193 # define CDISABLE bl PLTJMP(__pthread_disable_asynccancel)
194 # define __local_multiple_threads __pthread_multiple_threads
195 # elif !defined NOT_IN_libc
196 # define CENABLE bl PLTJMP(__libc_enable_asynccancel)
197 # define CDISABLE bl PLTJMP(__libc_disable_asynccancel)
198 # define __local_multiple_threads __libc_multiple_threads
199 # elif defined IS_IN_librt
200 # define CENABLE bl PLTJMP(__librt_enable_asynccancel)
201 # define CDISABLE bl PLTJMP(__librt_disable_asynccancel)
203 # error Unsupported library
206 # if defined IS_IN_libpthread || !defined NOT_IN_libc
207 # ifndef __ASSEMBLER__
208 extern int __local_multiple_threads attribute_hidden;
209 # define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
211 # define SINGLE_THREAD_P \
216 # define PSEUDO_PROLOGUE \
217 1: .word __local_multiple_threads - 2f - 8;
220 /* There is no __local_multiple_threads for librt, so use the TCB. */
221 # ifndef __ASSEMBLER__
222 # define SINGLE_THREAD_P \
223 __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
224 header.multiple_threads) == 0, 1)
226 # define PSEUDO_PROLOGUE
227 # define SINGLE_THREAD_P \
228 stmfd sp!, {r0, lr}; \
229 cfi_adjust_cfa_offset (8); \
230 cfi_rel_offset (lr, 4); \
231 bl __aeabi_read_tp; \
232 ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \
233 ldmfd sp!, {r0, lr}; \
234 cfi_adjust_cfa_offset (-8); \
237 # define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
241 #elif !defined __ASSEMBLER__
243 /* For rtld, et cetera. */
244 # define SINGLE_THREAD_P 1
245 # define NO_CANCELLATION 1
249 #ifndef __ASSEMBLER__
250 # define RTLD_SINGLE_THREAD_P \
251 __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
252 header.multiple_threads) == 0, 1)