]>
Commit | Line | Data |
---|---|---|
b168057a | 1 | /* Copyright (C) 2003-2015 Free Software Foundation, Inc. |
02a9f771 DJ |
2 | This file is part of the GNU C Library. |
3 | ||
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. | |
8 | ||
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. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
ab84e3ff PE |
15 | License along with the GNU C Library. If not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
02a9f771 DJ |
17 | |
18 | #include <sysdep.h> | |
19 | #include <tls.h> | |
20 | #ifndef __ASSEMBLER__ | |
21 | # include <nptl/pthreadP.h> | |
22 | #endif | |
23 | ||
4f41c682 | 24 | #if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt) |
02a9f771 DJ |
25 | |
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. */ | |
30 | ||
31 | # undef PSEUDO | |
32 | # define PSEUDO(name, syscall_name, args) \ | |
63cc0e75 | 33 | .text; \ |
63cc0e75 RH |
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); \ | |
02a9f771 | 40 | ENTRY (name); \ |
63cc0e75 RH |
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; \ | |
02a9f771 | 51 | .Lpseudo_cancel: \ |
63cc0e75 RH |
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 | |
02a9f771 | 66 | |
73886008 UW |
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 | |
e5b5ba47 | 69 | alignment, sometimes we must save an extra register. */ |
02a9f771 | 70 | |
63cc0e75 RH |
71 | # define RESTART_UNWIND \ |
72 | .fnend; \ | |
73 | .fnstart; \ | |
74 | .save {r7}; \ | |
75 | .save {lr} | |
76 | ||
77 | # define DOCARGS_0 \ | |
78 | .save {r7}; \ | |
55668624 | 79 | push {lr}; \ |
63cc0e75 RH |
80 | cfi_adjust_cfa_offset (4); \ |
81 | cfi_rel_offset (lr, 0); \ | |
82 | .save {lr} | |
02a9f771 | 83 | # define UNDOCARGS_0 |
63cc0e75 | 84 | # define RESTORE_LR_0 \ |
55668624 | 85 | pop {lr}; \ |
63cc0e75 RH |
86 | cfi_adjust_cfa_offset (-4); \ |
87 | cfi_restore (lr) | |
88 | ||
89 | # define DOCARGS_1 \ | |
90 | .save {r7}; \ | |
55668624 | 91 | push {r0, r1, lr}; \ |
63cc0e75 RH |
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 | |
102 | ||
103 | # define DOCARGS_2 \ | |
104 | .save {r7}; \ | |
55668624 | 105 | push {r0, r1, lr}; \ |
63cc0e75 RH |
106 | cfi_adjust_cfa_offset (12); \ |
107 | cfi_rel_offset (lr, 8); \ | |
108 | .save {lr}; \ | |
109 | .pad #8 | |
110 | # define UNDOCARGS_2 \ | |
55668624 | 111 | pop {r0, r1}; \ |
63cc0e75 RH |
112 | cfi_adjust_cfa_offset (-8); \ |
113 | RESTART_UNWIND | |
114 | # define RESTORE_LR_2 \ | |
115 | RESTORE_LR_0 | |
116 | ||
117 | # define DOCARGS_3 \ | |
118 | .save {r7}; \ | |
55668624 | 119 | push {r0, r1, r2, r3, lr}; \ |
63cc0e75 RH |
120 | cfi_adjust_cfa_offset (20); \ |
121 | cfi_rel_offset (lr, 16); \ | |
122 | .save {lr}; \ | |
123 | .pad #16 | |
124 | # define UNDOCARGS_3 \ | |
55668624 | 125 | pop {r0, r1, r2, r3}; \ |
63cc0e75 RH |
126 | cfi_adjust_cfa_offset (-16); \ |
127 | RESTART_UNWIND | |
128 | # define RESTORE_LR_3 \ | |
129 | RESTORE_LR_0 | |
130 | ||
131 | # define DOCARGS_4 \ | |
132 | .save {r7}; \ | |
55668624 | 133 | push {r0, r1, r2, r3, lr}; \ |
63cc0e75 RH |
134 | cfi_adjust_cfa_offset (20); \ |
135 | cfi_rel_offset (lr, 16); \ | |
136 | .save {lr}; \ | |
137 | .pad #16 | |
138 | # define UNDOCARGS_4 \ | |
55668624 | 139 | pop {r0, r1, r2, r3}; \ |
63cc0e75 RH |
140 | cfi_adjust_cfa_offset (-16); \ |
141 | RESTART_UNWIND | |
142 | # define RESTORE_LR_4 \ | |
143 | RESTORE_LR_0 | |
01b32e73 TS |
144 | |
145 | /* r4 is only stmfd'ed for correct stack alignment. */ | |
63cc0e75 RH |
146 | # define DOCARGS_5 \ |
147 | .save {r4, r7}; \ | |
55668624 | 148 | push {r0, r1, r2, r3, r4, lr}; \ |
63cc0e75 RH |
149 | cfi_adjust_cfa_offset (24); \ |
150 | cfi_rel_offset (lr, 20); \ | |
151 | .save {lr}; \ | |
152 | .pad #20 | |
153 | # define UNDOCARGS_5 \ | |
55668624 | 154 | pop {r0, r1, r2, r3}; \ |
63cc0e75 RH |
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 \ | |
55668624 | 162 | pop {r4, lr}; \ |
63cc0e75 RH |
163 | cfi_adjust_cfa_offset (-8); \ |
164 | /* r4 will be marked as restored later. */ \ | |
165 | cfi_restore (lr) | |
166 | ||
167 | # define DOCARGS_6 \ | |
168 | .save {r4, r5, r7}; \ | |
55668624 | 169 | push {r0, r1, r2, r3, lr}; \ |
63cc0e75 RH |
170 | cfi_adjust_cfa_offset (20); \ |
171 | cfi_rel_offset (lr, 16); \ | |
172 | .save {lr}; \ | |
173 | .pad #16 | |
174 | # define UNDOCARGS_6 \ | |
55668624 | 175 | pop {r0, r1, r2, r3}; \ |
63cc0e75 RH |
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 | |
e5b5ba47 | 183 | |
ce9f10f7 | 184 | # if IS_IN (libpthread) |
02a9f771 DJ |
185 | # define CENABLE bl PLTJMP(__pthread_enable_asynccancel) |
186 | # define CDISABLE bl PLTJMP(__pthread_disable_asynccancel) | |
187 | # define __local_multiple_threads __pthread_multiple_threads | |
4f41c682 | 188 | # elif IS_IN (libc) |
02a9f771 DJ |
189 | # define CENABLE bl PLTJMP(__libc_enable_asynccancel) |
190 | # define CDISABLE bl PLTJMP(__libc_disable_asynccancel) | |
191 | # define __local_multiple_threads __libc_multiple_threads | |
016afc75 | 192 | # elif IS_IN (librt) |
02a9f771 DJ |
193 | # define CENABLE bl PLTJMP(__librt_enable_asynccancel) |
194 | # define CDISABLE bl PLTJMP(__librt_disable_asynccancel) | |
195 | # else | |
196 | # error Unsupported library | |
197 | # endif | |
198 | ||
4f41c682 | 199 | # if IS_IN (libpthread) || IS_IN (libc) |
02a9f771 DJ |
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 \ | |
cd24e113 RH |
205 | LDST_PCREL(ldr, ip, ip, __local_multiple_threads); \ |
206 | teq ip, #0 | |
02a9f771 DJ |
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 | |
02a9f771 | 215 | # define SINGLE_THREAD_P \ |
55668624 | 216 | push {r0, lr}; \ |
63cc0e75 RH |
217 | cfi_adjust_cfa_offset (8); \ |
218 | cfi_rel_offset (lr, 4); \ | |
5232b909 | 219 | GET_TLS (lr); \ |
3ae44082 RH |
220 | NEGOFF_ADJ_BASE (r0, MULTIPLE_THREADS_OFFSET); \ |
221 | ldr ip, NEGOFF_OFF1 (r0, MULTIPLE_THREADS_OFFSET); \ | |
55668624 | 222 | pop {r0, lr}; \ |
63cc0e75 RH |
223 | cfi_adjust_cfa_offset (-8); \ |
224 | cfi_restore (lr); \ | |
225 | teq ip, #0 | |
02a9f771 DJ |
226 | # endif |
227 | # endif | |
228 | ||
229 | #elif !defined __ASSEMBLER__ | |
230 | ||
231 | /* For rtld, et cetera. */ | |
232 | # define SINGLE_THREAD_P 1 | |
233 | # define NO_CANCELLATION 1 | |
234 | ||
235 | #endif | |
80d6637f DJ |
236 | |
237 | #ifndef __ASSEMBLER__ | |
238 | # define RTLD_SINGLE_THREAD_P \ | |
239 | __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ | |
240 | header.multiple_threads) == 0, 1) | |
241 | #endif |