diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/csky/sysdep.h')
-rw-r--r-- | sysdeps/unix/sysv/linux/csky/sysdep.h | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/csky/sysdep.h b/sysdeps/unix/sysv/linux/csky/sysdep.h new file mode 100644 index 0000000000..cec6f95b2f --- /dev/null +++ b/sysdeps/unix/sysv/linux/csky/sysdep.h @@ -0,0 +1,534 @@ +/* Assembly macros for C-SKY. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _LINUX_CSKY_SYSDEP_H +#define _LINUX_CSKY_SYSDEP_H 1 + +/* There is some commonality. */ +#include <sysdeps/unix/sysv/linux/generic/sysdep.h> +#include <sysdeps/unix/sysv/linux/sysdep.h> +#include <sysdeps/csky/sysdep.h> + +/* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */ +#include <dl-sysdep.h> + +#include <tls.h> + +/* In order to get __set_errno() definition in INLINE_SYSCALL. */ +#ifndef __ASSEMBLER__ +# include <errno.h> +#endif + +#undef SYS_ify +#define SYS_ify(syscall_name) (__NR_##syscall_name) + +#ifdef __ASSEMBLER__ +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in R0 + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can safely + test with -4095. */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); + +# define GETGB \ + grs t0, .Lgetpc; \ +.Lgetpc: \ + lrw gb, .Lgetpc@GOTPC; \ + addu gb, t0; + +# if IS_IN (libc) +# ifdef __PIC__ +# define PSEUDO_RET \ + btsti a0, 31; \ + bf 1f; \ + subi sp, 8; \ + st.w lr, (sp); \ + st.w gb, (sp, 4); \ + GETGB; \ + lrw a2, SYSCALL_ERROR@PLT; \ + add a2, gb; \ + ld.w a2, (a2); \ + jsr a2; \ + ld.w lr, (sp); \ + ld.w gb, (sp, 4); \ + addi sp, 8; \ +1: \ + rts +# else +# define PSEUDO_RET \ + btsti a0, 31; \ + bf 1f; \ + jmpi SYSCALL_ERROR; \ +1: \ + rts +# endif +# else +# ifdef __PIC__ +# define PSEUDO_RET \ + btsti a0, 31; \ + bf 1f; \ + subi sp, 8; \ + st.w lr, (sp); \ + st.w gb, (sp, 4); \ + GETGB; \ + bsr SYSCALL_ERROR; \ + ld.w lr, (sp); \ + ld.w gb, (sp, 4); \ + addi sp, 8; \ +1: \ + rts +# else +# define PSEUDO_RET \ + btsti a0, 31; \ + bt SYSCALL_ERROR; \ + rts +# endif +# endif + +# undef ret +# define ret PSEUDO_RET + +# undef PSEUDO_END +# define PSEUDO_END(name) \ + .align 4; \ + SYSCALL_ERROR_HANDLER; \ + END (name) + +# undef PSEUDO_NOERRNO +# define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args) + +# define PSEUDO_RET_NOERRNO rts + +# undef ret_NOERRNO +# define ret_NOERRNO PSEUDO_RET_NOERRNO + +# undef PSEUDO_END_NOERRNO +# define PSEUDO_END_NOERRNO(name) END (name) + +/* The function has to return the error code. */ +# undef PSEUDO_ERRVAL +# define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + not a0; \ + addi a0, 1 + +# undef PSEUDO_END_ERRVAL +# define PSEUDO_END_ERRVAL(name) END (name) + +# define ret_ERRVAL rts + +# if !IS_IN (libc) +# define SYSCALL_ERROR __local_syscall_error +# if RTLD_PRIVATE_ERRNO +# ifdef __PIC__ +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + lrw a1, rtld_errno@PLT; \ + addu a1, gb; \ + ldw a1, (a1); \ + rsubi a0, 0; \ + stw a0, (a1); \ + bmaski a0, 0; \ + rts +# else /* __PIC__ */ +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + lrw a1, rtld_errno; \ + rsubi a0, 0; \ + stw a0, (a1); \ + bmaski a0, 0; \ + rts +# endif /* __PIC__ */ +# else /* !RTLD_PRIVATE_ERRNO */ +# ifdef __PIC__ +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + subi sp, 8; \ + stw a0, (sp, 0); \ + stw r15, (sp, 4); \ + lrw a1, __errno_location@PLT; \ + add a1, gb; \ + ldw a1, (a1); \ + jsr a1; \ + ldw a1, (sp, 0); /* load errno*/ \ + ldw r15, (sp, 4); \ + addi sp, 8; \ + movi a2, 0; \ + rsub a1, a1, a2; \ + stw a1, (a0); \ + bmaski a0, 0; \ + rts +# else +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + subi sp, 8; \ + stw a0, (sp, 0); \ + stw r15, (sp, 4); \ + lrw a1, __errno_location; \ + jsr a1; \ + ldw a1, (sp, 0); /* load errno */ \ + ldw r15, (sp, 4); \ + addi sp, 8; \ + movi a2, 0; \ + rsub a1, a1, a2; \ + stw a1, (a0); \ + bmaski a0, 0; \ + rts +# endif /* __PIC__ */ +# endif/* RTLD_PRIVATE_ERROR */ +# else +# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ +# define SYSCALL_ERROR __syscall_error +# endif/* IS_IN (libc) */ + +/* define DO_CALL */ +# undef DO_CALL +# define DO_CALL(syscall_name, args) \ + DOARGS_##args; \ + lrw r7, SYS_ify(syscall_name); \ + trap 0; \ + UNDOARGS_##args + +# undef DOARGS_0 +# define DOARGS_0 \ + subi sp, 8; \ + cfi_adjust_cfa_offset (8); \ + stw r7, (sp, 0); \ + cfi_rel_offset (r7, 0); + +# undef DOARGS_1 +# define DOARGS_1 DOARGS_0 +# undef DOARGS_2 +# define DOARGS_2 DOARGS_0 +# undef DOARGS_3 +# define DOARGS_3 DOARGS_0 +# undef DOARGS_4 +# define DOARGS_4 DOARGS_0 +# undef DOARGS_5 +# define DOARGS_5 \ + subi sp, 8; \ + cfi_adjust_cfa_offset (8); \ + stw r7, (sp, 0); \ + cfi_rel_offset (7, 0); \ + stw r4, (sp, 4); \ + cfi_rel_offset (4, 4); \ + ldw r4, (sp, 8) +# undef DOARGS_6 +# define DOARGS_6 \ + subi sp, 16; \ + cfi_adjust_cfa_offset (16); \ + stw r7, (sp, 0); \ + cfi_rel_offset (7, 0); \ + stw r4, (sp, 4); \ + cfi_rel_offset (4, 4); \ + stw r5, (sp, 8); \ + cfi_rel_offset (5, 8); \ + ldw r4, (sp, 16); \ + ldw r5, (sp, 20) + +# undef UNDOARGS_0 +# define UNDOARGS_0 \ + ldw r7, (sp, 0); \ + cfi_restore (r7); \ + addi sp, 8; \ + cfi_adjust_cfa_offset (-8); + +# undef UNDOARGS_1 +# define UNDOARGS_1 UNDOARGS_0 +# undef UNDOARGS_2 +# define UNDOARGS_2 UNDOARGS_0 +# undef UNDOARGS_3 +# define UNDOARGS_3 UNDOARGS_0 +# undef UNDOARGS_4 +# define UNDOARGS_4 UNDOARGS_0 +# undef UNDOARGS_5 +# define UNDOARGS_5 \ + ldw r7, (sp, 0); \ + cfi_restore (r4); \ + ldw r4, (sp, 4); \ + cfi_restore (r4); \ + addi sp, 8; \ + cfi_adjust_cfa_offset (-8); + +# undef UNDOARGS_6 +# define UNDOARGS_6 \ + ldw r7, (sp, 0); \ + cfi_restore (r7); \ + ldw r4, (sp, 4); \ + cfi_restore (r4); \ + ldw r5, (sp, 8); \ + cfi_restore (r5); \ + addi sp, 16; \ + cfi_adjust_cfa_offset (-16); + +#else /* not __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system + call. */ +# undef INLINE_SYSCALL +# define INLINE_SYSCALL(name, nr, args...) \ + ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \ + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result,), 0)) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \ + _sys_result = (unsigned int) -1; \ + } \ + (int) _sys_result; }) + +# undef INTERNAL_SYSCALL_DECL +# define INTERNAL_SYSCALL_DECL(err) do { } while (0) + +# undef INTERNAL_SYSCALL_ERROR_P +# define INTERNAL_SYSCALL_ERROR_P(val, err) \ + ((unsigned int) (val) >= 0xffffff01u) + +# undef INTERNAL_SYSCALL_ERRNO +# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) + +# undef INTERNAL_SYSCALL_RAW +# define INTERNAL_SYSCALL_RAW0(name, err, dummy...) \ + ({unsigned int __sys_result; \ + { \ + register int _a1 __asm__ ("a0"), _nr __asm__ ("r7"); \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# define INTERNAL_SYSCALL_RAW1(name, err, arg1) \ + ({unsigned int __sys_result; \ + register int _tmp_arg1 = (int)(arg1); \ + { \ + register int _a1 __asm__ ("a0"), _nr __asm__ ("r7"); \ + _a1 = _tmp_arg1; \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr), "r" (_a1) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# define INTERNAL_SYSCALL_RAW2(name, err, arg1, arg2) \ + ({unsigned int __sys_result; \ + register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ + { \ + register int _nr __asm__ ("r7"); \ + register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ + _a1 = _tmp_arg1, _a2 = _tmp_arg2; \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr), "r" (_a1), "r" (_a2) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# define INTERNAL_SYSCALL_RAW3(name, err, arg1, arg2, arg3) \ + ({unsigned int __sys_result; \ + register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ + register int _tmp_arg3 = (int)(arg3); \ + { \ + register int _nr __asm__ ("r7"); \ + register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ + register int _a3 __asm__ ("a2"); \ + _a1 = _tmp_arg1; \ + _a2 = _tmp_arg2; \ + _a3 = _tmp_arg3; \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr), "r" (_a1), "r" (_a2), \ + "r" (_a3) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# define INTERNAL_SYSCALL_RAW4(name, err, arg1, arg2, arg3, arg4) \ + ({unsigned int __sys_result; \ + register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ + register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ + { \ + register int _nr __asm__ ("r7"); \ + register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ + register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ + _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ + _a4 = _tmp_arg4; \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr), "r" (_a1), "r" (_a2), \ + "r" (_a3), "r" (_a4) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# define INTERNAL_SYSCALL_RAW5(name, err, arg1, arg2, arg3, arg4, \ + arg5) \ + ({unsigned int __sys_result; \ + register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ + register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ + register int _tmp_arg5 = (int)(arg5); \ + { \ + register int _nr __asm__ ("r7"); \ + register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ + register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ + register int _a5 __asm__ ("r4"); \ + _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ + _a4 = _tmp_arg4, _a5 = _tmp_arg5; \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr), "r" (_a1), "r" (_a2), \ + "r" (_a3), "r" (_a4), "r" (_a5) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# define INTERNAL_SYSCALL_RAW6(name, err, arg1, arg2, arg3, arg4, \ + arg5, arg6) \ + ({unsigned int __sys_result; \ + register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ + register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ + register int _tmp_arg5 = (int)(arg5), _tmp_arg6 = (int)(arg6); \ + { \ + register int _nr __asm__ ("r7"); \ + register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ + register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ + register int _a5 __asm__ ("r4"), _a6 __asm__ ("r5"); \ + _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ + _a4 = _tmp_arg4, _a5 = _tmp_arg5, _a6 = _tmp_arg6; \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr), "r" (_a1), "r" (_a2), \ + "r" (_a3), "r" (_a4), "r" (_a5), \ + "r" (_a6) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# define INTERNAL_SYSCALL_RAW7(name, err, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7) \ + ({unsigned int __sys_result; \ + register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ + register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ + register int _tmp_arg5 = (int)(arg5), _tmp_arg6 = (int)(arg6); \ + register int _tmp_arg7 = (int)(arg7); \ + { \ + register int _nr __asm__ ("r7"); \ + register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ + register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ + register int _a5 __asm__ ("r4"), _a6 __asm__ ("r5"); \ + register int _a7 __asm__ ("r6"); \ + _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ + _a4 = _tmp_arg4, _a5 = _tmp_arg5, _a6 = _tmp_arg6; \ + _a7 = _tmp_arg7; \ + _nr = name; \ + __asm__ __volatile__ ("trap 0 \n\t" \ + : "=r" (_a1) \ + : "r" (_nr), "r" (_a1), "r" (_a2), \ + "r" (_a3), "r" (_a4), "r" (_a5), \ + "r" (_a6), "r" (_a7) \ + : "memory"); \ + __sys_result = _a1; \ + } \ + (int) __sys_result; }) + +# undef INTERNAL_SYSCALL +# define INTERNAL_SYSCALL(name, err, nr, args...) \ + INTERNAL_SYSCALL_RAW##nr(SYS_ify(name), err, args) + +# undef INTERNAL_SYSCALL_NCS +# define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + INTERNAL_SYSCALL_RAW##nr (number, err, args) + +#endif /* __ASSEMBLER__ */ + +/* Pointer mangling support. */ +#if (IS_IN (rtld) || \ + (!defined SHARED && (IS_IN (libc) || IS_IN (libpthread)))) +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(dst, src, guard) \ + grs t0, 1f; \ +1: \ + lrw guard, 1b@GOTPC; \ + addu t0, guard; \ + lrw guard, __pointer_chk_guard_local@GOT; \ + ldr.w guard, (t0, guard << 0); \ + ldw guard, (guard, 0); \ + xor dst, src, guard; +# define PTR_DEMANGLE(dst, src, guard) PTR_MANGLE (dst, src, guard) +# define PTR_MANGLE2(dst, src, guard) \ + xor dst, src, guard +# define PTR_DEMANGLE2(dst, src, guard) PTR_MANGLE2 (dst, src, guard) +# else +extern uintptr_t __pointer_chk_guard_local; +# define PTR_MANGLE(var) \ + (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local) +# define PTR_DEMANGLE(var) PTR_MANGLE (var) +# endif +#else +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(dst, src, guard) \ + grs t0, 1f; \ +1: \ + lrw guard, 1b@GOTPC; \ + addu t0, guard; \ + lrw guard, __pointer_chk_guard@GOT; \ + ldr.w guard, (t0, guard << 0); \ + ldw guard, (guard, 0); \ + xor dst, src, guard; +# define PTR_DEMANGLE(dst, src, guard) PTR_MANGLE (dst, src, guard) +# define PTR_MANGLE2(dst, src, guard) \ + xor dst, src, guard +# define PTR_DEMANGLE2(dst, src, guard) PTR_MANGLE2 (dst, src, guard) +# else +extern uintptr_t __pointer_chk_guard; +# define PTR_MANGLE(var) \ + (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard) +# define PTR_DEMANGLE(var) PTR_MANGLE (var) +# endif +#endif + +#endif /* linux/csky/sysdep.h */ |