Add Changelog ...
[glibc.git] / sysdeps / unix / sysv / linux / arm / sysdep.h
blob30fa599e0566c6b81ff813185ec4ecf8c0264381
1 /* Copyright (C) 1992-2012 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995.
4 ARM changes by Philip Blundell, <pjb27@cam.ac.uk>, May 1997.
6 The GNU C Library is free software; you can redistribute it and/or
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.
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
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library. If not, see
18 <http://www.gnu.org/licenses/>. */
20 #ifndef _LINUX_ARM_SYSDEP_H
21 #define _LINUX_ARM_SYSDEP_H 1
23 /* There is some commonality. */
24 #include <sysdeps/unix/arm/sysdep.h>
26 /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */
27 #include <dl-sysdep.h>
29 #include <tls.h>
31 /* In order to get __set_errno() definition in INLINE_SYSCALL. */
32 #ifndef __ASSEMBLER__
33 #include <errno.h>
34 #endif
36 /* For Linux we can use the system call table in the header file
37 /usr/include/asm/unistd.h
38 of the kernel. But these symbols do not follow the SYS_* syntax
39 so we have to redefine the `SYS_ify' macro here. */
40 #undef SYS_ify
41 #define SYS_ify(syscall_name) (__NR_##syscall_name)
43 #define _SYS_AUXV_H 1
44 #include <bits/hwcap.h>
46 #ifdef __ASSEMBLER__
48 /* Linux uses a negative return value to indicate syscall errors,
49 unlike most Unices, which use the condition codes' carry flag.
51 Since version 2.1 the return value of a system call might be
52 negative even if the call succeeded. E.g., the `lseek' system call
53 might return a large offset. Therefore we must not anymore test
54 for < 0, but test for a real error by making sure the value in R0
55 is a real error number. Linus said he will make sure the no syscall
56 returns a value in -1 .. -4095 as a valid result so we can safely
57 test with -4095. */
59 #undef PSEUDO
60 #define PSEUDO(name, syscall_name, args) \
61 .text; \
62 ENTRY (name); \
63 DO_CALL (syscall_name, args); \
64 cmn r0, $4096;
66 #define PSEUDO_RET \
67 RETINSTR(cc, lr); \
68 b PLTJMP(SYSCALL_ERROR)
69 #undef ret
70 #define ret PSEUDO_RET
72 #undef PSEUDO_END
73 #define PSEUDO_END(name) \
74 SYSCALL_ERROR_HANDLER; \
75 END (name)
77 #undef PSEUDO_NOERRNO
78 #define PSEUDO_NOERRNO(name, syscall_name, args) \
79 .text; \
80 ENTRY (name); \
81 DO_CALL (syscall_name, args);
83 #define PSEUDO_RET_NOERRNO \
84 DO_RET (lr);
86 #undef ret_NOERRNO
87 #define ret_NOERRNO PSEUDO_RET_NOERRNO
89 #undef PSEUDO_END_NOERRNO
90 #define PSEUDO_END_NOERRNO(name) \
91 END (name)
93 /* The function has to return the error code. */
94 #undef PSEUDO_ERRVAL
95 #define PSEUDO_ERRVAL(name, syscall_name, args) \
96 .text; \
97 ENTRY (name) \
98 DO_CALL (syscall_name, args); \
99 rsb r0, r0, #0
101 #undef PSEUDO_END_ERRVAL
102 #define PSEUDO_END_ERRVAL(name) \
103 END (name)
105 #define ret_ERRVAL PSEUDO_RET_NOERRNO
107 #if NOT_IN_libc
108 # define SYSCALL_ERROR __local_syscall_error
109 # if RTLD_PRIVATE_ERRNO
110 # define SYSCALL_ERROR_HANDLER \
111 __local_syscall_error: \
112 ldr r1, 1f; \
113 rsb r0, r0, #0; \
114 0: str r0, [pc, r1]; \
115 mvn r0, #0; \
116 DO_RET(lr); \
117 1: .word C_SYMBOL_NAME(rtld_errno) - 0b - 8;
118 # else
119 # if defined(__ARM_ARCH_4T__) && defined(__THUMB_INTERWORK__)
120 # define POP_PC \
121 ldr lr, [sp], #4; \
122 cfi_adjust_cfa_offset (-4); \
123 cfi_restore (lr); \
124 bx lr
125 # else
126 # define POP_PC \
127 ldr pc, [sp], #4
128 # endif
129 # define SYSCALL_ERROR_HANDLER \
130 __local_syscall_error: \
131 str lr, [sp, #-4]!; \
132 cfi_adjust_cfa_offset (4); \
133 cfi_rel_offset (lr, 0); \
134 str r0, [sp, #-4]!; \
135 cfi_adjust_cfa_offset (4); \
136 bl PLTJMP(C_SYMBOL_NAME(__errno_location)); \
137 ldr r1, [sp], #4; \
138 cfi_adjust_cfa_offset (-4); \
139 rsb r1, r1, #0; \
140 str r1, [r0]; \
141 mvn r0, #0; \
142 POP_PC;
143 # endif
144 #else
145 # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
146 # define SYSCALL_ERROR __syscall_error
147 #endif
149 /* The ARM EABI user interface passes the syscall number in r7, instead
150 of in the swi. This is more efficient, because the kernel does not need
151 to fetch the swi from memory to find out the number; which can be painful
152 with separate I-cache and D-cache. Make sure to use 0 for the SWI
153 argument; otherwise the (optional) compatibility code for APCS binaries
154 may be invoked. */
156 /* Linux takes system call args in registers:
157 arg 1 r0
158 arg 2 r1
159 arg 3 r2
160 arg 4 r3
161 arg 5 r4 (this is different from the APCS convention)
162 arg 6 r5
163 arg 7 r6
165 The compiler is going to form a call by coming here, through PSEUDO, with
166 arguments
167 syscall number in the DO_CALL macro
168 arg 1 r0
169 arg 2 r1
170 arg 3 r2
171 arg 4 r3
172 arg 5 [sp]
173 arg 6 [sp+4]
174 arg 7 [sp+8]
176 We need to shuffle values between R4..R6 and the stack so that the
177 caller's v1..v3 and stack frame are not corrupted, and the kernel
178 sees the right arguments.
182 /* We must save and restore r7 (call-saved) for the syscall number.
183 We never make function calls from inside here (only potentially
184 signal handlers), so we do not bother with doubleword alignment.
186 Just like the APCS syscall convention, the EABI syscall convention uses
187 r0 through r6 for up to seven syscall arguments. None are ever passed to
188 the kernel on the stack, although incoming arguments are on the stack for
189 syscalls with five or more arguments.
191 The assembler will convert the literal pool load to a move for most
192 syscalls. */
194 #undef DO_CALL
195 #define DO_CALL(syscall_name, args) \
196 DOARGS_##args; \
197 ldr r7, =SYS_ify (syscall_name); \
198 swi 0x0; \
199 UNDOARGS_##args
201 #undef DOARGS_0
202 #define DOARGS_0 \
203 .fnstart; \
204 str r7, [sp, #-4]!; \
205 cfi_adjust_cfa_offset (4); \
206 cfi_rel_offset (r7, 0); \
207 .save { r7 }
208 #undef DOARGS_1
209 #define DOARGS_1 DOARGS_0
210 #undef DOARGS_2
211 #define DOARGS_2 DOARGS_0
212 #undef DOARGS_3
213 #define DOARGS_3 DOARGS_0
214 #undef DOARGS_4
215 #define DOARGS_4 DOARGS_0
216 #undef DOARGS_5
217 #define DOARGS_5 \
218 .fnstart; \
219 stmfd sp!, {r4, r7}; \
220 cfi_adjust_cfa_offset (8); \
221 cfi_rel_offset (r4, 0); \
222 cfi_rel_offset (r7, 4); \
223 .save { r4, r7 }; \
224 ldr r4, [sp, #8]
225 #undef DOARGS_6
226 #define DOARGS_6 \
227 .fnstart; \
228 mov ip, sp; \
229 stmfd sp!, {r4, r5, r7}; \
230 cfi_adjust_cfa_offset (12); \
231 cfi_rel_offset (r4, 0); \
232 cfi_rel_offset (r5, 4); \
233 cfi_rel_offset (r7, 8); \
234 .save { r4, r5, r7 }; \
235 ldmia ip, {r4, r5}
236 #undef DOARGS_7
237 #define DOARGS_7 \
238 .fnstart; \
239 mov ip, sp; \
240 stmfd sp!, {r4, r5, r6, r7}; \
241 cfi_adjust_cfa_offset (16); \
242 cfi_rel_offset (r4, 0); \
243 cfi_rel_offset (r5, 4); \
244 cfi_rel_offset (r6, 8); \
245 cfi_rel_offset (r7, 12); \
246 .save { r4, r5, r6, r7 }; \
247 ldmia ip, {r4, r5, r6}
249 #undef UNDOARGS_0
250 #define UNDOARGS_0 \
251 ldr r7, [sp], #4; \
252 cfi_adjust_cfa_offset (-4); \
253 cfi_restore (r7); \
254 .fnend
255 #undef UNDOARGS_1
256 #define UNDOARGS_1 UNDOARGS_0
257 #undef UNDOARGS_2
258 #define UNDOARGS_2 UNDOARGS_0
259 #undef UNDOARGS_3
260 #define UNDOARGS_3 UNDOARGS_0
261 #undef UNDOARGS_4
262 #define UNDOARGS_4 UNDOARGS_0
263 #undef UNDOARGS_5
264 #define UNDOARGS_5 \
265 ldmfd sp!, {r4, r7}; \
266 cfi_adjust_cfa_offset (-8); \
267 cfi_restore (r4); \
268 cfi_restore (r7); \
269 .fnend
270 #undef UNDOARGS_6
271 #define UNDOARGS_6 \
272 ldmfd sp!, {r4, r5, r7}; \
273 cfi_adjust_cfa_offset (-12); \
274 cfi_restore (r4); \
275 cfi_restore (r5); \
276 cfi_restore (r7); \
277 .fnend
278 #undef UNDOARGS_7
279 #define UNDOARGS_7 \
280 ldmfd sp!, {r4, r5, r6, r7}; \
281 cfi_adjust_cfa_offset (-16); \
282 cfi_restore (r4); \
283 cfi_restore (r5); \
284 cfi_restore (r6); \
285 cfi_restore (r7); \
286 .fnend
288 #else /* not __ASSEMBLER__ */
290 /* Define a macro which expands into the inline wrapper code for a system
291 call. */
292 #undef INLINE_SYSCALL
293 #define INLINE_SYSCALL(name, nr, args...) \
294 ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \
295 if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0)) \
297 __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \
298 _sys_result = (unsigned int) -1; \
300 (int) _sys_result; })
302 #undef INTERNAL_SYSCALL_DECL
303 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
305 #if defined(__thumb__)
306 /* We can not expose the use of r7 to the compiler. GCC (as
307 of 4.5) uses r7 as the hard frame pointer for Thumb - although
308 for Thumb-2 it isn't obviously a better choice than r11.
309 And GCC does not support asms that conflict with the frame
310 pointer.
312 This would be easier if syscall numbers never exceeded 255,
313 but they do. For the moment the LOAD_ARGS_7 is sacrificed.
314 We can't use push/pop inside the asm because that breaks
315 unwinding (i.e. thread cancellation) for this frame. We can't
316 locally save and restore r7, because we do not know if this
317 function uses r7 or if it is our caller's r7; if it is our caller's,
318 then unwinding will fail higher up the stack. So we move the
319 syscall out of line and provide its own unwind information. */
320 # undef INTERNAL_SYSCALL_RAW
321 # define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
322 ({ \
323 register int _a1 asm ("a1"); \
324 int _nametmp = name; \
325 LOAD_ARGS_##nr (args) \
326 register int _name asm ("ip") = _nametmp; \
327 asm volatile ("bl __libc_do_syscall" \
328 : "=r" (_a1) \
329 : "r" (_name) ASM_ARGS_##nr \
330 : "memory", "lr"); \
331 _a1; })
332 #else /* ARM */
333 # undef INTERNAL_SYSCALL_RAW
334 # define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
335 ({ \
336 register int _a1 asm ("r0"), _nr asm ("r7"); \
337 LOAD_ARGS_##nr (args) \
338 _nr = name; \
339 asm volatile ("swi 0x0 @ syscall " #name \
340 : "=r" (_a1) \
341 : "r" (_nr) ASM_ARGS_##nr \
342 : "memory"); \
343 _a1; })
344 #endif
346 #undef INTERNAL_SYSCALL
347 #define INTERNAL_SYSCALL(name, err, nr, args...) \
348 INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args)
350 #undef INTERNAL_SYSCALL_ARM
351 #define INTERNAL_SYSCALL_ARM(name, err, nr, args...) \
352 INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args)
354 #undef INTERNAL_SYSCALL_ERROR_P
355 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
356 ((unsigned int) (val) >= 0xfffff001u)
358 #undef INTERNAL_SYSCALL_ERRNO
359 #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
361 #define LOAD_ARGS_0()
362 #define ASM_ARGS_0
363 #define LOAD_ARGS_1(a1) \
364 int _a1tmp = (int) (a1); \
365 LOAD_ARGS_0 () \
366 _a1 = _a1tmp;
367 #define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1)
368 #define LOAD_ARGS_2(a1, a2) \
369 int _a2tmp = (int) (a2); \
370 LOAD_ARGS_1 (a1) \
371 register int _a2 asm ("a2") = _a2tmp;
372 #define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2)
373 #define LOAD_ARGS_3(a1, a2, a3) \
374 int _a3tmp = (int) (a3); \
375 LOAD_ARGS_2 (a1, a2) \
376 register int _a3 asm ("a3") = _a3tmp;
377 #define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3)
378 #define LOAD_ARGS_4(a1, a2, a3, a4) \
379 int _a4tmp = (int) (a4); \
380 LOAD_ARGS_3 (a1, a2, a3) \
381 register int _a4 asm ("a4") = _a4tmp;
382 #define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4)
383 #define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
384 int _v1tmp = (int) (a5); \
385 LOAD_ARGS_4 (a1, a2, a3, a4) \
386 register int _v1 asm ("v1") = _v1tmp;
387 #define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1)
388 #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \
389 int _v2tmp = (int) (a6); \
390 LOAD_ARGS_5 (a1, a2, a3, a4, a5) \
391 register int _v2 asm ("v2") = _v2tmp;
392 #define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2)
393 #ifndef __thumb__
394 # define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \
395 int _v3tmp = (int) (a7); \
396 LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) \
397 register int _v3 asm ("v3") = _v3tmp;
398 # define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3)
399 #endif
401 /* For EABI, non-constant syscalls are actually pretty easy... */
402 #undef INTERNAL_SYSCALL_NCS
403 #define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
404 INTERNAL_SYSCALL_RAW (number, err, nr, args)
406 #endif /* __ASSEMBLER__ */
408 /* Pointer mangling is not yet supported for ARM. */
409 #define PTR_MANGLE(var) (void) (var)
410 #define PTR_DEMANGLE(var) (void) (var)
412 #endif /* linux/arm/sysdep.h */