]>
Commit | Line | Data |
---|---|---|
64e65bc1 | 1 | /* Copyright (C) 1992, 1995, 1996, 2000, 2003, 2004, 2006, 2010, 2012 |
d32bff86 | 2 | Free Software Foundation, Inc. |
dd4b8913 | 3 | This file is part of the GNU C Library. |
bf7a24fc RM |
4 | Contributed by Brendan Kehoe (brendan@zen.org). |
5 | ||
dd4b8913 | 6 | The GNU C Library is free software; you can redistribute it and/or |
3214b89b AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
bf7a24fc | 10 | |
dd4b8913 UD |
11 | The GNU C Library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
3214b89b | 14 | Lesser General Public License for more details. |
bf7a24fc | 15 | |
3214b89b | 16 | You should have received a copy of the GNU Lesser General Public |
ab84e3ff PE |
17 | License along with the GNU C Library. If not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
bf7a24fc RM |
19 | |
20 | #include <sysdeps/unix/sysdep.h> | |
21 | ||
e0ebc3b2 | 22 | #ifdef __ASSEMBLER__ |
bf7a24fc | 23 | |
92172913 RM |
24 | #ifdef __linux__ |
25 | # include <alpha/regdef.h> | |
26 | #else | |
27 | # include <regdef.h> | |
28 | #endif | |
29 | ||
d5a256ad RM |
30 | #ifdef IS_IN_rtld |
31 | # include <dl-sysdep.h> /* Defines RTLD_PRIVATE_ERRNO. */ | |
32 | #endif | |
33 | ||
34 | ||
92172913 | 35 | #ifdef __STDC__ |
dd4b8913 | 36 | #define __LABEL(x) x##: |
92172913 | 37 | #else |
dd4b8913 UD |
38 | #define __LABEL(x) x/**/: |
39 | #endif | |
40 | ||
92172913 RM |
41 | #define LEAF(name, framesize) \ |
42 | .globl name; \ | |
def004d7 | 43 | .align 4; \ |
92172913 | 44 | .ent name, 0; \ |
dd4b8913 | 45 | __LABEL(name) \ |
92172913 | 46 | .frame sp, framesize, ra |
92172913 | 47 | |
bf7a24fc RM |
48 | #define ENTRY(name) \ |
49 | .globl name; \ | |
def004d7 | 50 | .align 4; \ |
92172913 | 51 | .ent name, 0; \ |
dd4b8913 | 52 | __LABEL(name) \ |
92172913 | 53 | .frame sp, 0, ra |
bf7a24fc | 54 | |
bb486e18 RM |
55 | /* Mark the end of function SYM. */ |
56 | #undef END | |
57 | #define END(sym) .end sym | |
58 | ||
dd4b8913 | 59 | #ifdef PROF |
d5a256ad RM |
60 | # define PSEUDO_PROLOGUE \ |
61 | .frame sp, 0, ra; \ | |
62 | ldgp gp,0(pv); \ | |
63 | .set noat; \ | |
64 | lda AT,_mcount; \ | |
65 | jsr AT,(AT),_mcount; \ | |
66 | .set at; \ | |
67 | .prologue 1 | |
aaadd842 | 68 | #elif defined PIC |
d5a256ad RM |
69 | # define PSEUDO_PROLOGUE \ |
70 | .frame sp, 0, ra; \ | |
71 | .prologue 0 | |
aaadd842 UD |
72 | #else |
73 | # define PSEUDO_PROLOGUE \ | |
74 | .frame sp, 0, ra; \ | |
75 | ldgp gp,0(pv); \ | |
76 | .prologue 1 | |
d5a256ad RM |
77 | #endif /* PROF */ |
78 | ||
79 | #if RTLD_PRIVATE_ERRNO | |
aaadd842 | 80 | # define SYSCALL_ERROR_LABEL $syscall_error |
d5a256ad | 81 | # define SYSCALL_ERROR_HANDLER \ |
94645659 | 82 | stl v0, rtld_errno(gp) !gprel; \ |
d5a256ad RM |
83 | lda v0, -1; \ |
84 | ret | |
aaadd842 | 85 | #elif defined(PIC) |
64e65bc1 RH |
86 | # define SYSCALL_ERROR_LABEL __syscall_error !samegp |
87 | # define SYSCALL_ERROR_HANDLER | |
d5a256ad | 88 | #else |
aaadd842 | 89 | # define SYSCALL_ERROR_LABEL $syscall_error |
6092f9e0 RH |
90 | # define SYSCALL_ERROR_HANDLER \ |
91 | jmp $31, __syscall_error | |
d5a256ad RM |
92 | #endif /* RTLD_PRIVATE_ERRNO */ |
93 | ||
aaadd842 UD |
94 | /* Overridden by specific syscalls. */ |
95 | #undef PSEUDO_PREPARE_ARGS | |
96 | #define PSEUDO_PREPARE_ARGS /* Nothing. */ | |
97 | ||
98 | #define PSEUDO(name, syscall_name, args) \ | |
d5a256ad RM |
99 | .globl name; \ |
100 | .align 4; \ | |
101 | .ent name,0; \ | |
dd4b8913 | 102 | __LABEL(name) \ |
d5a256ad | 103 | PSEUDO_PROLOGUE; \ |
7d983cbb | 104 | PSEUDO_PREPARE_ARGS \ |
d5a256ad RM |
105 | lda v0, SYS_ify(syscall_name); \ |
106 | call_pal PAL_callsys; \ | |
aaadd842 UD |
107 | bne a3, SYSCALL_ERROR_LABEL |
108 | ||
109 | #undef PSEUDO_END | |
110 | #if defined(PIC) && !RTLD_PRIVATE_ERRNO | |
d5a256ad | 111 | # define PSEUDO_END(sym) END(sym) |
bf7a24fc | 112 | #else |
d5a256ad | 113 | # define PSEUDO_END(sym) \ |
aaadd842 | 114 | $syscall_error: \ |
d5a256ad RM |
115 | SYSCALL_ERROR_HANDLER; \ |
116 | END(sym) | |
aaadd842 | 117 | #endif |
7d983cbb | 118 | |
98f7320f UD |
119 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ |
120 | .globl name; \ | |
121 | .align 4; \ | |
122 | .ent name,0; \ | |
123 | __LABEL(name) \ | |
124 | PSEUDO_PROLOGUE; \ | |
125 | PSEUDO_PREPARE_ARGS \ | |
126 | lda v0, SYS_ify(syscall_name); \ | |
127 | call_pal PAL_callsys; | |
128 | ||
129 | #undef PSEUDO_END_NOERRNO | |
130 | #define PSEUDO_END_NOERRNO(sym) END(sym) | |
131 | ||
132 | #define ret_NOERRNO ret | |
133 | ||
724bab37 UD |
134 | #define PSEUDO_ERRVAL(name, syscall_name, args) \ |
135 | .globl name; \ | |
136 | .align 4; \ | |
137 | .ent name,0; \ | |
138 | __LABEL(name) \ | |
139 | PSEUDO_PROLOGUE; \ | |
140 | PSEUDO_PREPARE_ARGS \ | |
141 | lda v0, SYS_ify(syscall_name); \ | |
142 | call_pal PAL_callsys; | |
143 | ||
144 | #undef PSEUDO_END_ERRVAL | |
145 | #define PSEUDO_END_ERRVAL(sym) END(sym) | |
146 | ||
147 | #define ret_ERRVAL ret | |
148 | ||
bf7a24fc RM |
149 | #define r0 v0 |
150 | #define r1 a4 | |
151 | ||
152 | #define MOVE(x,y) mov x,y | |
153 | ||
aaadd842 UD |
154 | #else /* !ASSEMBLER */ |
155 | ||
156 | /* ??? Linux needs to be able to override INLINE_SYSCALL for one | |
157 | particular special case. Make this easy. */ | |
158 | ||
259eb5cd | 159 | #undef INLINE_SYSCALL |
aaadd842 UD |
160 | #define INLINE_SYSCALL(name, nr, args...) \ |
161 | INLINE_SYSCALL1(name, nr, args) | |
162 | ||
163 | #define INLINE_SYSCALL1(name, nr, args...) \ | |
164 | ({ \ | |
165 | long _sc_ret, _sc_err; \ | |
d627d8fb | 166 | inline_syscall##nr(__NR_##name, args); \ |
ebcd2cd1 | 167 | if (__builtin_expect (_sc_err, 0)) \ |
aaadd842 UD |
168 | { \ |
169 | __set_errno (_sc_ret); \ | |
170 | _sc_ret = -1L; \ | |
171 | } \ | |
172 | _sc_ret; \ | |
173 | }) | |
174 | ||
175 | #define INTERNAL_SYSCALL(name, err_out, nr, args...) \ | |
176 | INTERNAL_SYSCALL1(name, err_out, nr, args) | |
177 | ||
178 | #define INTERNAL_SYSCALL1(name, err_out, nr, args...) \ | |
d627d8fb UD |
179 | INTERNAL_SYSCALL_NCS(__NR_##name, err_out, nr, args) |
180 | ||
181 | #define INTERNAL_SYSCALL_NCS(name, err_out, nr, args...) \ | |
aaadd842 UD |
182 | ({ \ |
183 | long _sc_ret, _sc_err; \ | |
184 | inline_syscall##nr(name, args); \ | |
185 | err_out = _sc_err; \ | |
186 | _sc_ret; \ | |
187 | }) | |
188 | ||
e544dcd5 RH |
189 | #define INTERNAL_SYSCALL_DECL(err) \ |
190 | long int err __attribute__((unused)) | |
191 | ||
f0a81bf3 RH |
192 | /* The normal Alpha calling convention sign-extends 32-bit quantties |
193 | no matter what the "real" sign of the 32-bit type. We want to | |
194 | preserve that when filling in values for the kernel. */ | |
195 | #define syscall_promote(arg) \ | |
196 | (sizeof(arg) == 4 ? (long)(int)(long)(arg) : (long)(arg)) | |
197 | ||
cce01cf0 RH |
198 | /* Make sure and "use" the variable that we're not returning, |
199 | in order to suppress unused variable warnings. */ | |
200 | #define INTERNAL_SYSCALL_ERROR_P(val, err) ((void)val, err) | |
201 | #define INTERNAL_SYSCALL_ERRNO(val, err) ((void)err, val) | |
aaadd842 UD |
202 | |
203 | #define inline_syscall_clobbers \ | |
204 | "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", \ | |
205 | "$22", "$23", "$24", "$25", "$27", "$28", "memory" | |
206 | ||
aaadd842 UD |
207 | /* It is moderately important optimization-wise to limit the lifetime |
208 | of the hard-register variables as much as possible. Thus we copy | |
209 | in/out as close to the asm as possible. */ | |
210 | ||
211 | #define inline_syscall0(name, args...) \ | |
212 | { \ | |
aaadd842 | 213 | register long _sc_19 __asm__("$19"); \ |
f0a81bf3 | 214 | register long _sc_0 = name; \ |
3de1f4af RM |
215 | __asm__ __volatile__ \ |
216 | ("callsys # %0 %1 <= %2" \ | |
f0a81bf3 RH |
217 | : "+v"(_sc_0), "=r"(_sc_19) \ |
218 | : : inline_syscall_clobbers, \ | |
3de1f4af | 219 | "$16", "$17", "$18", "$20", "$21"); \ |
aaadd842 UD |
220 | _sc_ret = _sc_0, _sc_err = _sc_19; \ |
221 | } | |
222 | ||
223 | #define inline_syscall1(name,arg1) \ | |
224 | { \ | |
f0a81bf3 RH |
225 | register long _tmp_16 = syscall_promote (arg1); \ |
226 | register long _sc_0 = name; \ | |
227 | register long _sc_16 __asm__("$16") = _tmp_16; \ | |
aaadd842 | 228 | register long _sc_19 __asm__("$19"); \ |
3de1f4af RM |
229 | __asm__ __volatile__ \ |
230 | ("callsys # %0 %1 <= %2 %3" \ | |
f0a81bf3 RH |
231 | : "+v"(_sc_0), "=r"(_sc_19), "+r"(_sc_16) \ |
232 | : : inline_syscall_clobbers, \ | |
3de1f4af | 233 | "$17", "$18", "$20", "$21"); \ |
aaadd842 UD |
234 | _sc_ret = _sc_0, _sc_err = _sc_19; \ |
235 | } | |
236 | ||
237 | #define inline_syscall2(name,arg1,arg2) \ | |
238 | { \ | |
f0a81bf3 RH |
239 | register long _tmp_16 = syscall_promote (arg1); \ |
240 | register long _tmp_17 = syscall_promote (arg2); \ | |
241 | register long _sc_0 = name; \ | |
242 | register long _sc_16 __asm__("$16") = _tmp_16; \ | |
243 | register long _sc_17 __asm__("$17") = _tmp_17; \ | |
aaadd842 | 244 | register long _sc_19 __asm__("$19"); \ |
3de1f4af RM |
245 | __asm__ __volatile__ \ |
246 | ("callsys # %0 %1 <= %2 %3 %4" \ | |
f0a81bf3 RH |
247 | : "+v"(_sc_0), "=r"(_sc_19), \ |
248 | "+r"(_sc_16), "+r"(_sc_17) \ | |
249 | : : inline_syscall_clobbers, \ | |
3de1f4af | 250 | "$18", "$20", "$21"); \ |
aaadd842 UD |
251 | _sc_ret = _sc_0, _sc_err = _sc_19; \ |
252 | } | |
253 | ||
254 | #define inline_syscall3(name,arg1,arg2,arg3) \ | |
255 | { \ | |
f0a81bf3 RH |
256 | register long _tmp_16 = syscall_promote (arg1); \ |
257 | register long _tmp_17 = syscall_promote (arg2); \ | |
258 | register long _tmp_18 = syscall_promote (arg3); \ | |
259 | register long _sc_0 = name; \ | |
260 | register long _sc_16 __asm__("$16") = _tmp_16; \ | |
261 | register long _sc_17 __asm__("$17") = _tmp_17; \ | |
262 | register long _sc_18 __asm__("$18") = _tmp_18; \ | |
aaadd842 | 263 | register long _sc_19 __asm__("$19"); \ |
3de1f4af RM |
264 | __asm__ __volatile__ \ |
265 | ("callsys # %0 %1 <= %2 %3 %4 %5" \ | |
f0a81bf3 RH |
266 | : "+v"(_sc_0), "=r"(_sc_19), "+r"(_sc_16), \ |
267 | "+r"(_sc_17), "+r"(_sc_18) \ | |
268 | : : inline_syscall_clobbers, "$20", "$21"); \ | |
aaadd842 UD |
269 | _sc_ret = _sc_0, _sc_err = _sc_19; \ |
270 | } | |
271 | ||
272 | #define inline_syscall4(name,arg1,arg2,arg3,arg4) \ | |
273 | { \ | |
f0a81bf3 RH |
274 | register long _tmp_16 = syscall_promote (arg1); \ |
275 | register long _tmp_17 = syscall_promote (arg2); \ | |
276 | register long _tmp_18 = syscall_promote (arg3); \ | |
277 | register long _tmp_19 = syscall_promote (arg4); \ | |
278 | register long _sc_0 = name; \ | |
279 | register long _sc_16 __asm__("$16") = _tmp_16; \ | |
280 | register long _sc_17 __asm__("$17") = _tmp_17; \ | |
281 | register long _sc_18 __asm__("$18") = _tmp_18; \ | |
282 | register long _sc_19 __asm__("$19") = _tmp_19; \ | |
3de1f4af RM |
283 | __asm__ __volatile__ \ |
284 | ("callsys # %0 %1 <= %2 %3 %4 %5 %6" \ | |
f0a81bf3 RH |
285 | : "+v"(_sc_0), "+r"(_sc_19), "+r"(_sc_16), \ |
286 | "+r"(_sc_17), "+r"(_sc_18) \ | |
287 | : : inline_syscall_clobbers, "$20", "$21"); \ | |
aaadd842 UD |
288 | _sc_ret = _sc_0, _sc_err = _sc_19; \ |
289 | } | |
290 | ||
291 | #define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5) \ | |
292 | { \ | |
f0a81bf3 RH |
293 | register long _tmp_16 = syscall_promote (arg1); \ |
294 | register long _tmp_17 = syscall_promote (arg2); \ | |
295 | register long _tmp_18 = syscall_promote (arg3); \ | |
296 | register long _tmp_19 = syscall_promote (arg4); \ | |
297 | register long _tmp_20 = syscall_promote (arg5); \ | |
298 | register long _sc_0 = name; \ | |
299 | register long _sc_16 __asm__("$16") = _tmp_16; \ | |
300 | register long _sc_17 __asm__("$17") = _tmp_17; \ | |
301 | register long _sc_18 __asm__("$18") = _tmp_18; \ | |
302 | register long _sc_19 __asm__("$19") = _tmp_19; \ | |
303 | register long _sc_20 __asm__("$20") = _tmp_20; \ | |
3de1f4af RM |
304 | __asm__ __volatile__ \ |
305 | ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7" \ | |
f0a81bf3 RH |
306 | : "+v"(_sc_0), "+r"(_sc_19), "+r"(_sc_16), \ |
307 | "+r"(_sc_17), "+r"(_sc_18), "+r"(_sc_20) \ | |
308 | : : inline_syscall_clobbers, "$21"); \ | |
aaadd842 UD |
309 | _sc_ret = _sc_0, _sc_err = _sc_19; \ |
310 | } | |
311 | ||
312 | #define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6) \ | |
313 | { \ | |
f0a81bf3 RH |
314 | register long _tmp_16 = syscall_promote (arg1); \ |
315 | register long _tmp_17 = syscall_promote (arg2); \ | |
316 | register long _tmp_18 = syscall_promote (arg3); \ | |
317 | register long _tmp_19 = syscall_promote (arg4); \ | |
318 | register long _tmp_20 = syscall_promote (arg5); \ | |
319 | register long _tmp_21 = syscall_promote (arg6); \ | |
320 | register long _sc_0 = name; \ | |
321 | register long _sc_16 __asm__("$16") = _tmp_16; \ | |
322 | register long _sc_17 __asm__("$17") = _tmp_17; \ | |
323 | register long _sc_18 __asm__("$18") = _tmp_18; \ | |
324 | register long _sc_19 __asm__("$19") = _tmp_19; \ | |
325 | register long _sc_20 __asm__("$20") = _tmp_20; \ | |
326 | register long _sc_21 __asm__("$21") = _tmp_21; \ | |
3de1f4af RM |
327 | __asm__ __volatile__ \ |
328 | ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7 %8" \ | |
f0a81bf3 RH |
329 | : "+v"(_sc_0), "+r"(_sc_19), "+r"(_sc_16), \ |
330 | "+r"(_sc_17), "+r"(_sc_18), "+r"(_sc_20), \ | |
331 | "+r"(_sc_21) \ | |
332 | : : inline_syscall_clobbers); \ | |
aaadd842 UD |
333 | _sc_ret = _sc_0, _sc_err = _sc_19; \ |
334 | } | |
335 | ||
12d4d227 UD |
336 | /* Pointer mangling support. Note that tls access is slow enough that |
337 | we don't deoptimize things by placing the pointer check value there. */ | |
338 | ||
339 | #include <stdint.h> | |
340 | ||
341 | #if defined NOT_IN_libc && defined IS_IN_rtld | |
342 | # ifdef __ASSEMBLER__ | |
343 | # define PTR_MANGLE(dst, src, tmp) \ | |
344 | ldah tmp, __pointer_chk_guard_local($29) !gprelhigh; \ | |
345 | ldq tmp, __pointer_chk_guard_local(tmp) !gprellow; \ | |
346 | xor src, tmp, dst | |
347 | # define PTR_MANGLE2(dst, src, tmp) \ | |
348 | xor src, tmp, dst | |
349 | # define PTR_DEMANGLE(dst, tmp) PTR_MANGLE(dst, dst, tmp) | |
350 | # define PTR_DEMANGLE2(dst, tmp) PTR_MANGLE2(dst, dst, tmp) | |
351 | # else | |
352 | extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden; | |
353 | # define PTR_MANGLE(var) \ | |
b834ecbd | 354 | (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local) |
12d4d227 UD |
355 | # define PTR_DEMANGLE(var) PTR_MANGLE(var) |
356 | # endif | |
357 | #elif defined PIC | |
358 | # ifdef __ASSEMBLER__ | |
359 | # define PTR_MANGLE(dst, src, tmp) \ | |
360 | ldq tmp, __pointer_chk_guard; \ | |
361 | xor src, tmp, dst | |
362 | # define PTR_MANGLE2(dst, src, tmp) \ | |
363 | xor src, tmp, dst | |
364 | # define PTR_DEMANGLE(dst, tmp) PTR_MANGLE(dst, dst, tmp) | |
365 | # define PTR_DEMANGLE2(dst, tmp) PTR_MANGLE2(dst, dst, tmp) | |
366 | # else | |
ee390edf | 367 | extern const uintptr_t __pointer_chk_guard attribute_relro; |
12d4d227 | 368 | # define PTR_MANGLE(var) \ |
ee390edf | 369 | (var) = (__typeof(var)) ((uintptr_t) (var) ^ __pointer_chk_guard) |
12d4d227 UD |
370 | # define PTR_DEMANGLE(var) PTR_MANGLE(var) |
371 | # endif | |
ee390edf RH |
372 | #else |
373 | /* There exists generic C code that assumes that PTR_MANGLE is always | |
374 | defined. When generating code for the static libc, we don't have | |
375 | __pointer_chk_guard defined. Nor is there any place that would | |
376 | initialize it if it were defined, so there's little point in doing | |
377 | anything more than nothing. */ | |
378 | # ifndef __ASSEMBLER__ | |
379 | # define PTR_MANGLE(var) | |
380 | # define PTR_DEMANGLE(var) | |
381 | # endif | |
12d4d227 UD |
382 | #endif |
383 | ||
13d54c34 | 384 | #endif /* ASSEMBLER */ |