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