1 /* Assembler macros for ARM.
2 Copyright (C) 1997, 1998, 2003 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #ifndef _LINUX_ARM_SYSDEP_H
20 #define _LINUX_ARM_SYSDEP_H 1
22 #include <common/sysdep.h>
23 #include <bits/arm_asm.h>
25 #include <sys/syscall.h>
26 /* For Linux we can use the system call table in the header file
27 /usr/include/asm/unistd.h
28 of the kernel. But these symbols do not follow the SYS_* syntax
29 so we have to redefine the `SYS_ify' macro here. */
31 #define SWI_BASE (0x900000)
32 #define SYS_ify(syscall_name) (__NR_##syscall_name)
36 /* Syntactic details of assembler. */
38 #define ALIGNARG(log2) log2
39 /* For ELF we need the `.type' directive to make shared libs work right. */
40 #define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg;
41 #define ASM_SIZE_DIRECTIVE(name) .size name,.-name
43 /* In ELF C symbols are asm symbols. */
45 #define NO_UNDERSCORES
47 #define PLTJMP(_x) _x##(PLT)
49 /* APCS-32 doesn't preserve the condition codes across function call. */
51 #define LOADREGS(cond, base, reglist...)\
52 ldm##cond base,reglist
54 #define RETINSTR(cond, reg) \
56 #define DO_RET(_reg) \
59 #define RETINSTR(cond, reg) \
61 #define DO_RET(_reg) \
65 #define LOADREGS(cond, base, reglist...) \
66 ldm##cond base,reglist^
67 #define RETINSTR(cond, reg) \
69 #define DO_RET(_reg) \
73 /* Define an entry point visible from C. */
75 ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
76 ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function) \
83 ASM_SIZE_DIRECTIVE(name)
85 /* If compiled for profiling, call `mcount' at the start of each function. */
92 #define CALL_MCOUNT /* Do nothing. */
96 /* Since C identifiers are not normally prefixed with an underscore
97 on this system, the asm identifier `syscall_error' intrudes on the
98 C name space. Make sure we use an innocuous name. */
99 #define syscall_error __syscall_error
100 #define mcount _mcount
102 /* Linux uses a negative return value to indicate syscall errors,
103 unlike most Unices, which use the condition codes' carry flag.
105 Since version 2.1 the return value of a system call might be
106 negative even if the call succeeded. E.g., the `lseek' system call
107 might return a large offset. Therefore we must not anymore test
108 for < 0, but test for a real error by making sure the value in R0
109 is a real error number. Linus said he will make sure the no syscall
110 returns a value in -1 .. -4095 as a valid result so we can safely
114 #define PSEUDO(name, syscall_name, args) \
117 DO_CALL (syscall_name, args); \
122 b PLTJMP(SYSCALL_ERROR)
124 #define ret PSEUDO_RET
127 #define PSEUDO_END(name) \
128 SYSCALL_ERROR_HANDLER \
131 #undef PSEUDO_NOERRNO
132 #define PSEUDO_NOERRNO(name, syscall_name, args) \
135 DO_CALL (syscall_name, args);
137 #define PSEUDO_RET_NOERRNO \
141 #define ret_NOERRNO PSEUDO_RET_NOERRNO
143 #undef PSEUDO_END_NOERRNO
144 #define PSEUDO_END_NOERRNO(name) \
147 /* The function has to return the error code. */
149 #define PSEUDO_ERRVAL(name, syscall_name, args) \
152 DO_CALL (syscall_name, args); \
155 #undef PSEUDO_END_ERRVAL
156 #define PSEUDO_END_ERRVAL(name) \
159 #define ret_ERRVAL PSEUDO_RET_NOERRNO
161 #if defined NOT_IN_libc
162 # define SYSCALL_ERROR __local_syscall_error
163 # ifdef RTLD_PRIVATE_ERRNO
164 # define SYSCALL_ERROR_HANDLER \
165 __local_syscall_error: \
168 0: str r0, [pc, r1]; \
171 1: .word C_SYMBOL_NAME(rtld_errno) - 0b - 8;
173 # define SYSCALL_ERROR_HANDLER \
174 __local_syscall_error: \
175 str lr, [sp, #-4]!; \
176 str r0, [sp, #-4]!; \
177 bl PLTJMP(C_SYMBOL_NAME(__errno_location)); \
185 # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
186 # define SYSCALL_ERROR __syscall_error
189 /* Linux takes system call args in registers:
190 syscall number in the SWI instruction
195 arg 5 r4 (this is different from the APCS convention)
199 The compiler is going to form a call by coming here, through PSEUDO, with
201 syscall number in the DO_CALL macro
210 We need to shuffle values between R4..R6 and the stack so that the
211 caller's v1..v3 and stack frame are not corrupted, and the kernel
212 sees the right arguments.
217 #if defined(__ARM_EABI__)
218 #define DO_CALL(syscall_name, args) \
221 ldr r7, =SYS_ify (syscall_name); \
226 #define DO_CALL(syscall_name, args) \
228 swi SYS_ify (syscall_name); \
232 #define DOARGS_0 /* nothing */
233 #define DOARGS_1 /* nothing */
234 #define DOARGS_2 /* nothing */
235 #define DOARGS_3 /* nothing */
236 #define DOARGS_4 /* nothing */
237 #define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4];
238 #define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5};
239 #define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6};
241 #define UNDOARGS_0 /* nothing */
242 #define UNDOARGS_1 /* nothing */
243 #define UNDOARGS_2 /* nothing */
244 #define UNDOARGS_3 /* nothing */
245 #define UNDOARGS_4 /* nothing */
246 #define UNDOARGS_5 ldr r4, [sp], $4;
247 #define UNDOARGS_6 ldmfd sp!, {r4, r5};
248 #define UNDOARGS_7 ldmfd sp!, {r4, r5, r6};
250 #else /* not __ASSEMBLER__ */
251 /* Define a macro which expands into the inline wrapper code for a system
253 #undef INLINE_SYSCALL
254 #define INLINE_SYSCALL(name, nr, args...) \
255 ({ unsigned int _inline_sys_result = INTERNAL_SYSCALL (name, , nr, args); \
256 if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_inline_sys_result, ), 0)) \
258 __set_errno (INTERNAL_SYSCALL_ERRNO (_inline_sys_result, )); \
259 _inline_sys_result = (unsigned int) -1; \
261 (int) _inline_sys_result; })
263 #undef INTERNAL_SYSCALL_DECL
264 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
266 #undef INTERNAL_SYSCALL_RAW
267 #if defined(__thumb__)
268 /* Hide the use of r7 from the compiler, this would be a lot
269 * easier but for the fact that the syscalls can exceed 255.
270 * For the moment the LOAD_ARG_7 is sacrificed.
271 * We can't use push/pop inside the asm because that breaks
272 * unwinding (ie. thread cancellation).
274 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
275 ({ unsigned int _internal_sys_result; \
278 register int __a1 __asm__ ("a1"); \
279 register int *_v3 __asm__ ("v3") = _sys_buf; \
280 LOAD_ARGS_##nr (args) \
281 *_v3 = (int) (name); \
282 __asm__ __volatile__ ("str r7, [v3, #4]\n" \
284 "\tswi 0 @ syscall " #name "\n" \
285 "\tldr r7, [v3, #4]" \
287 : "r" (_v3) ASM_ARGS_##nr \
289 _internal_sys_result = __a1; \
291 (int) _internal_sys_result; })
292 #elif defined(__ARM_EABI__)
293 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
294 ({unsigned int _internal_sys_result; \
296 register int __a1 __asm__ ("r0"), _nr __asm__ ("r7"); \
297 LOAD_ARGS_##nr (args) \
299 __asm__ __volatile__ ("swi 0x0 @ syscall " #name \
301 : "r" (_nr) ASM_ARGS_##nr \
303 _internal_sys_result = __a1; \
305 (int) _internal_sys_result; })
306 #else /* !defined(__ARM_EABI__) */
307 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
308 ({ unsigned int _internal_sys_result; \
310 register int __a1 __asm__ ("a1"); \
311 LOAD_ARGS_##nr (args) \
312 __asm__ __volatile__ ("swi %1 @ syscall " #name \
314 : "i" (name) ASM_ARGS_##nr \
316 _internal_sys_result = __a1; \
318 (int) _internal_sys_result; })
321 #undef INTERNAL_SYSCALL
322 #define INTERNAL_SYSCALL(name, err, nr, args...) \
323 INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args)
325 #undef INTERNAL_SYSCALL_ARM
326 #define INTERNAL_SYSCALL_ARM(name, err, nr, args...) \
327 INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args)
329 #undef INTERNAL_SYSCALL_ERROR_P
330 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
331 ((unsigned int) (val) >= 0xfffff001u)
333 #undef INTERNAL_SYSCALL_ERRNO
334 #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
336 #if defined(__ARM_EABI__)
337 #undef INTERNAL_SYSCALL_NCS
338 #define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
339 INTERNAL_SYSCALL_RAW(number, err, nr, args)
341 /* We can't implement non-constant syscalls directly since the syscall
342 number is normally encoded in the instruction. So use SYS_syscall. */
343 #undef INTERNAL_SYSCALL_NCS
344 #define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
345 INTERNAL_SYSCALL_NCS_##nr (number, err, args)
347 #define INTERNAL_SYSCALL_NCS_0(number, err, args...) \
348 INTERNAL_SYSCALL (syscall, err, 1, number, args)
349 #define INTERNAL_SYSCALL_NCS_1(number, err, args...) \
350 INTERNAL_SYSCALL (syscall, err, 2, number, args)
351 #define INTERNAL_SYSCALL_NCS_2(number, err, args...) \
352 INTERNAL_SYSCALL (syscall, err, 3, number, args)
353 #define INTERNAL_SYSCALL_NCS_3(number, err, args...) \
354 INTERNAL_SYSCALL (syscall, err, 4, number, args)
355 #define INTERNAL_SYSCALL_NCS_4(number, err, args...) \
356 INTERNAL_SYSCALL (syscall, err, 5, number, args)
357 #define INTERNAL_SYSCALL_NCS_5(number, err, args...) \
358 INTERNAL_SYSCALL (syscall, err, 6, number, args)
361 #endif /* __ASSEMBLER__ */
363 /* Pointer mangling is not yet supported for ARM. */
364 #define PTR_MANGLE(var) (void) (var)
365 #define PTR_DEMANGLE(var) (void) (var)
367 #endif /* linux/arm/sysdep.h */