Blame sysdeps/unix/sysv/linux/m68k/sysdep.h

Packit 6c4009
/* Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Written by Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>,
Packit 6c4009
   December 1995.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library.  If not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sysdeps/unix/sysv/linux/sysdep.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
Packit 6c4009
/* Defines RTLD_PRIVATE_ERRNO.  */
Packit 6c4009
#include <dl-sysdep.h>
Packit 6c4009
Packit 6c4009
/* For Linux we can use the system call table in the header file
Packit 6c4009
	/usr/include/asm/unistd.h
Packit 6c4009
   of the kernel.  But these symbols do not follow the SYS_* syntax
Packit 6c4009
   so we have to redefine the `SYS_ify' macro here.  */
Packit 6c4009
#undef SYS_ify
Packit 6c4009
#define SYS_ify(syscall_name)	__NR_##syscall_name
Packit 6c4009
Packit 6c4009
#ifdef __ASSEMBLER__
Packit 6c4009
Packit 6c4009
/* Linux uses a negative return value to indicate syscall errors, unlike
Packit 6c4009
   most Unices, which use the condition codes' carry flag.
Packit 6c4009
Packit 6c4009
   Since version 2.1 the return value of a system call might be negative
Packit 6c4009
   even if the call succeeded.  E.g., the `lseek' system call might return
Packit 6c4009
   a large offset.  Therefore we must not anymore test for < 0, but test
Packit 6c4009
   for a real error by making sure the value in %d0 is a real error
Packit 6c4009
   number.  Linus said he will make sure the no syscall returns a value
Packit 6c4009
   in -1 .. -4095 as a valid result so we can savely test with -4095.  */
Packit 6c4009
Packit 6c4009
/* We don't want the label for the error handler to be visible in the symbol
Packit 6c4009
   table when we define it here.  */
Packit 6c4009
#ifdef PIC
Packit 6c4009
#define SYSCALL_ERROR_LABEL .Lsyscall_error
Packit 6c4009
#else
Packit 6c4009
#define SYSCALL_ERROR_LABEL __syscall_error
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#undef PSEUDO
Packit 6c4009
#define	PSEUDO(name, syscall_name, args)				      \
Packit 6c4009
  .text;								      \
Packit 6c4009
  ENTRY (name)								      \
Packit 6c4009
    DO_CALL (syscall_name, args);					      \
Packit 6c4009
    cmp.l &-4095, %d0;							      \
Packit 6c4009
    jcc SYSCALL_ERROR_LABEL
Packit 6c4009
Packit 6c4009
#undef PSEUDO_END
Packit 6c4009
#define PSEUDO_END(name)						      \
Packit 6c4009
  SYSCALL_ERROR_HANDLER;						      \
Packit 6c4009
  END (name)
Packit 6c4009
Packit 6c4009
#undef PSEUDO_NOERRNO
Packit 6c4009
#define	PSEUDO_NOERRNO(name, syscall_name, args)			      \
Packit 6c4009
  .text;								      \
Packit 6c4009
  ENTRY (name)								      \
Packit 6c4009
    DO_CALL (syscall_name, args)
Packit 6c4009
Packit 6c4009
#undef PSEUDO_END_NOERRNO
Packit 6c4009
#define PSEUDO_END_NOERRNO(name)					      \
Packit 6c4009
  END (name)
Packit 6c4009
Packit 6c4009
#define ret_NOERRNO rts
Packit 6c4009
Packit 6c4009
/* The function has to return the error code.  */
Packit 6c4009
#undef	PSEUDO_ERRVAL
Packit 6c4009
#define	PSEUDO_ERRVAL(name, syscall_name, args) \
Packit 6c4009
  .text;								      \
Packit 6c4009
  ENTRY (name)								      \
Packit 6c4009
    DO_CALL (syscall_name, args);					      \
Packit 6c4009
    negl %d0
Packit 6c4009
Packit 6c4009
#undef	PSEUDO_END_ERRVAL
Packit 6c4009
#define	PSEUDO_END_ERRVAL(name) \
Packit 6c4009
  END (name)
Packit 6c4009
Packit 6c4009
#define ret_ERRVAL rts
Packit 6c4009
Packit 6c4009
#ifdef PIC
Packit 6c4009
# if RTLD_PRIVATE_ERRNO
Packit 6c4009
#  define SYSCALL_ERROR_HANDLER						      \
Packit 6c4009
SYSCALL_ERROR_LABEL:							      \
Packit 6c4009
    PCREL_OP (lea, rtld_errno, %a0, %a0);				      \
Packit 6c4009
    neg.l %d0;								      \
Packit 6c4009
    move.l %d0, (%a0);							      \
Packit 6c4009
    move.l &-1, %d0;							      \
Packit 6c4009
    /* Copy return value to %a0 for syscalls that are declared to return      \
Packit 6c4009
       a pointer (e.g., mmap).  */					      \
Packit 6c4009
    move.l %d0, %a0;							      \
Packit 6c4009
    rts;
Packit 6c4009
# elif defined _LIBC_REENTRANT
Packit 6c4009
#  if IS_IN (libc)
Packit 6c4009
#   define SYSCALL_ERROR_ERRNO __libc_errno
Packit 6c4009
#  else
Packit 6c4009
#   define SYSCALL_ERROR_ERRNO errno
Packit 6c4009
#  endif
Packit 6c4009
#  define SYSCALL_ERROR_HANDLER						      \
Packit 6c4009
SYSCALL_ERROR_LABEL:							      \
Packit 6c4009
    neg.l %d0;								      \
Packit 6c4009
    move.l %d0, -(%sp);							      \
Packit 6c4009
    cfi_adjust_cfa_offset (4);						      \
Packit 6c4009
    jbsr __m68k_read_tp@PLTPC;						      \
Packit 6c4009
    SYSCALL_ERROR_LOAD_GOT (%a1);					      \
Packit 6c4009
    add.l (SYSCALL_ERROR_ERRNO@TLSIE, %a1), %a0;			      \
Packit 6c4009
    move.l (%sp)+, (%a0);						      \
Packit 6c4009
    cfi_adjust_cfa_offset (-4);						      \
Packit 6c4009
    move.l &-1, %d0;							      \
Packit 6c4009
    /* Copy return value to %a0 for syscalls that are declared to return      \
Packit 6c4009
       a pointer (e.g., mmap).  */					      \
Packit 6c4009
    move.l %d0, %a0;							      \
Packit 6c4009
    rts;
Packit 6c4009
# else /* !_LIBC_REENTRANT */
Packit 6c4009
/* Store (- %d0) into errno through the GOT.  */
Packit 6c4009
#  define SYSCALL_ERROR_HANDLER						      \
Packit 6c4009
SYSCALL_ERROR_LABEL:							      \
Packit 6c4009
    move.l (errno@GOTPC, %pc), %a0;					      \
Packit 6c4009
    neg.l %d0;								      \
Packit 6c4009
    move.l %d0, (%a0);							      \
Packit 6c4009
    move.l &-1, %d0;							      \
Packit 6c4009
    /* Copy return value to %a0 for syscalls that are declared to return      \
Packit 6c4009
       a pointer (e.g., mmap).  */					      \
Packit 6c4009
    move.l %d0, %a0;							      \
Packit 6c4009
    rts;
Packit 6c4009
# endif /* _LIBC_REENTRANT */
Packit 6c4009
#else
Packit 6c4009
# define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */
Packit 6c4009
#endif /* PIC */
Packit 6c4009
Packit 6c4009
/* Linux takes system call arguments in registers:
Packit 6c4009
Packit 6c4009
	syscall number	%d0	     call-clobbered
Packit 6c4009
	arg 1		%d1	     call-clobbered
Packit 6c4009
	arg 2		%d2	     call-saved
Packit 6c4009
	arg 3		%d3	     call-saved
Packit 6c4009
	arg 4		%d4	     call-saved
Packit 6c4009
	arg 5		%d5	     call-saved
Packit 6c4009
	arg 6		%a0	     call-clobbered
Packit 6c4009
Packit 6c4009
   The stack layout upon entering the function is:
Packit 6c4009
Packit 6c4009
	24(%sp)		Arg# 6
Packit 6c4009
	20(%sp)		Arg# 5
Packit 6c4009
	16(%sp)		Arg# 4
Packit 6c4009
	12(%sp)		Arg# 3
Packit 6c4009
	 8(%sp)		Arg# 2
Packit 6c4009
	 4(%sp)		Arg# 1
Packit 6c4009
	  (%sp)		Return address
Packit 6c4009
Packit 6c4009
   (Of course a function with say 3 arguments does not have entries for
Packit 6c4009
   arguments 4 and 5.)
Packit 6c4009
Packit 6c4009
   Separate move's are faster than movem, but need more space.  Since
Packit 6c4009
   speed is more important, we don't use movem.  Since %a0 and %a1 are
Packit 6c4009
   scratch registers, we can use them for saving as well.  */
Packit 6c4009
Packit 6c4009
#define DO_CALL(syscall_name, args)			      		      \
Packit 6c4009
    move.l &SYS_ify(syscall_name), %d0;					      \
Packit 6c4009
    DOARGS_##args							      \
Packit 6c4009
    trap &0;								      \
Packit 6c4009
    UNDOARGS_##args
Packit 6c4009
Packit 6c4009
#define	DOARGS_0	/* No arguments to frob.  */
Packit 6c4009
#define	UNDOARGS_0	/* No arguments to unfrob.  */
Packit 6c4009
#define	_DOARGS_0(n)	/* No arguments to frob.  */
Packit 6c4009
Packit 6c4009
#define	DOARGS_1	_DOARGS_1 (4)
Packit 6c4009
#define	_DOARGS_1(n)	move.l n(%sp), %d1; _DOARGS_0 (n)
Packit 6c4009
#define	UNDOARGS_1	UNDOARGS_0
Packit 6c4009
Packit 6c4009
#define	DOARGS_2	_DOARGS_2 (8)
Packit 6c4009
#define	_DOARGS_2(n)	move.l %d2, %a0; cfi_register (%d2, %a0);	      \
Packit 6c4009
			move.l n(%sp), %d2; _DOARGS_1 (n-4)
Packit 6c4009
#define	UNDOARGS_2	UNDOARGS_1; move.l %a0, %d2; cfi_restore (%d2)
Packit 6c4009
Packit 6c4009
#define DOARGS_3	_DOARGS_3 (12)
Packit 6c4009
#define _DOARGS_3(n)	move.l %d3, %a1; cfi_register (%d3, %a1);	      \
Packit 6c4009
			move.l n(%sp), %d3; _DOARGS_2 (n-4)
Packit 6c4009
#define UNDOARGS_3	UNDOARGS_2; move.l %a1, %d3; cfi_restore (%d3)
Packit 6c4009
Packit 6c4009
#define DOARGS_4	_DOARGS_4 (16)
Packit 6c4009
#define _DOARGS_4(n)	move.l %d4, -(%sp);				      \
Packit 6c4009
			cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);   \
Packit 6c4009
			move.l n+4(%sp), %d4; _DOARGS_3 (n)
Packit 6c4009
#define UNDOARGS_4	UNDOARGS_3; move.l (%sp)+, %d4;			      \
Packit 6c4009
			cfi_adjust_cfa_offset (-4); cfi_restore (%d4)
Packit 6c4009
Packit 6c4009
#define DOARGS_5	_DOARGS_5 (20)
Packit 6c4009
#define _DOARGS_5(n)	move.l %d5, -(%sp); 				      \
Packit 6c4009
			cfi_adjust_cfa_offset (4); cfi_rel_offset (%d5, 0);   \
Packit 6c4009
			move.l n+4(%sp), %d5; _DOARGS_4 (n)
Packit 6c4009
#define UNDOARGS_5	UNDOARGS_4; move.l (%sp)+, %d5;			      \
Packit 6c4009
			cfi_adjust_cfa_offset (-4); cfi_restore (%d5)
Packit 6c4009
Packit 6c4009
#define DOARGS_6	_DOARGS_6 (24)
Packit 6c4009
#define _DOARGS_6(n)	_DOARGS_5 (n-4); move.l %a0, -(%sp);		      \
Packit 6c4009
			cfi_adjust_cfa_offset (4);			      \
Packit 6c4009
			move.l n+12(%sp), %a0;
Packit 6c4009
#define UNDOARGS_6	move.l (%sp)+, %a0; cfi_adjust_cfa_offset (-4);	      \
Packit 6c4009
			UNDOARGS_5
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define	ret	rts
Packit 6c4009
#if 0 /* Not used by Linux */
Packit 6c4009
#define	r0	%d0
Packit 6c4009
#define	r1	%d1
Packit 6c4009
#define	MOVE(x,y)	movel x , y
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#else /* not __ASSEMBLER__ */
Packit 6c4009
Packit 6c4009
/* Define a macro which expands into the inline wrapper code for a system
Packit 6c4009
   call.  */
Packit 6c4009
#undef INLINE_SYSCALL
Packit 6c4009
#define INLINE_SYSCALL(name, nr, args...)				\
Packit 6c4009
  ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);	\
Packit 6c4009
     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))\
Packit 6c4009
       {								\
Packit 6c4009
	 __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, ));		\
Packit 6c4009
	 _sys_result = (unsigned int) -1;				\
Packit 6c4009
       }								\
Packit 6c4009
     (int) _sys_result; })
Packit 6c4009
Packit 6c4009
#undef INTERNAL_SYSCALL_DECL
Packit 6c4009
#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
Packit 6c4009
Packit 6c4009
/* Define a macro which expands inline into the wrapper code for a system
Packit 6c4009
   call.  This use is for internal calls that do not need to handle errors
Packit 6c4009
   normally.  It will never touch errno.  This returns just what the kernel
Packit 6c4009
   gave back.  */
Packit 6c4009
#undef INTERNAL_SYSCALL
Packit 6c4009
#define INTERNAL_SYSCALL_NCS(name, err, nr, args...)	\
Packit 6c4009
  ({ unsigned int _sys_result;				\
Packit 6c4009
     {							\
Packit 6c4009
       /* Load argument values in temporary variables
Packit 6c4009
	  to perform side effects like function calls
Packit 6c4009
	  before the call used registers are set.  */	\
Packit 6c4009
       LOAD_ARGS_##nr (args)				\
Packit 6c4009
       LOAD_REGS_##nr					\
Packit 6c4009
       register int _d0 asm ("%d0") = name;		\
Packit 6c4009
       asm volatile ("trap #0"				\
Packit 6c4009
		     : "=d" (_d0)			\
Packit 6c4009
		     : "0" (_d0) ASM_ARGS_##nr		\
Packit 6c4009
		     : "memory");			\
Packit 6c4009
       _sys_result = _d0;				\
Packit 6c4009
     }							\
Packit 6c4009
     (int) _sys_result; })
Packit 6c4009
#define INTERNAL_SYSCALL(name, err, nr, args...)	\
Packit 6c4009
  INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
Packit 6c4009
Packit 6c4009
#undef INTERNAL_SYSCALL_ERROR_P
Packit 6c4009
#define INTERNAL_SYSCALL_ERROR_P(val, err)		\
Packit 6c4009
  ((unsigned int) (val) >= -4095U)
Packit 6c4009
Packit 6c4009
#undef INTERNAL_SYSCALL_ERRNO
Packit 6c4009
#define INTERNAL_SYSCALL_ERRNO(val, err)	(-(val))
Packit 6c4009
Packit 6c4009
#define LOAD_ARGS_0()
Packit 6c4009
#define LOAD_REGS_0
Packit 6c4009
#define ASM_ARGS_0
Packit 6c4009
#define LOAD_ARGS_1(a1)				\
Packit 6c4009
  LOAD_ARGS_0 ()				\
Packit 6c4009
  int __arg1 = (int) (a1);
Packit 6c4009
#define LOAD_REGS_1				\
Packit 6c4009
  register int _d1 asm ("d1") = __arg1;		\
Packit 6c4009
  LOAD_REGS_0
Packit 6c4009
#define ASM_ARGS_1	ASM_ARGS_0, "d" (_d1)
Packit 6c4009
#define LOAD_ARGS_2(a1, a2)			\
Packit 6c4009
  LOAD_ARGS_1 (a1)				\
Packit 6c4009
  int __arg2 = (int) (a2);
Packit 6c4009
#define LOAD_REGS_2				\
Packit 6c4009
  register int _d2 asm ("d2") = __arg2;		\
Packit 6c4009
  LOAD_REGS_1
Packit 6c4009
#define ASM_ARGS_2	ASM_ARGS_1, "d" (_d2)
Packit 6c4009
#define LOAD_ARGS_3(a1, a2, a3)			\
Packit 6c4009
  LOAD_ARGS_2 (a1, a2)				\
Packit 6c4009
  int __arg3 = (int) (a3);
Packit 6c4009
#define LOAD_REGS_3				\
Packit 6c4009
  register int _d3 asm ("d3") = __arg3;		\
Packit 6c4009
  LOAD_REGS_2
Packit 6c4009
#define ASM_ARGS_3	ASM_ARGS_2, "d" (_d3)
Packit 6c4009
#define LOAD_ARGS_4(a1, a2, a3, a4)		\
Packit 6c4009
  LOAD_ARGS_3 (a1, a2, a3)			\
Packit 6c4009
  int __arg4 = (int) (a4);
Packit 6c4009
#define LOAD_REGS_4				\
Packit 6c4009
  register int _d4 asm ("d4") = __arg4;		\
Packit 6c4009
  LOAD_REGS_3
Packit 6c4009
#define ASM_ARGS_4	ASM_ARGS_3, "d" (_d4)
Packit 6c4009
#define LOAD_ARGS_5(a1, a2, a3, a4, a5)		\
Packit 6c4009
  LOAD_ARGS_4 (a1, a2, a3, a4)			\
Packit 6c4009
  int __arg5 = (int) (a5);
Packit 6c4009
#define LOAD_REGS_5				\
Packit 6c4009
  register int _d5 asm ("d5") = __arg5;		\
Packit 6c4009
  LOAD_REGS_4
Packit 6c4009
#define ASM_ARGS_5	ASM_ARGS_4, "d" (_d5)
Packit 6c4009
#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)	\
Packit 6c4009
  LOAD_ARGS_5 (a1, a2, a3, a4, a5)		\
Packit 6c4009
  int __arg6 = (int) (a6);
Packit 6c4009
#define LOAD_REGS_6				\
Packit 6c4009
  register int _a0 asm ("a0") = __arg6;		\
Packit 6c4009
  LOAD_REGS_5
Packit 6c4009
#define ASM_ARGS_6	ASM_ARGS_5, "a" (_a0)
Packit 6c4009
Packit 6c4009
#endif /* not __ASSEMBLER__ */
Packit 6c4009
Packit 6c4009
/* Pointer mangling is not yet supported for M68K.  */
Packit 6c4009
#define PTR_MANGLE(var) (void) (var)
Packit 6c4009
#define PTR_DEMANGLE(var) (void) (var)
Packit 6c4009
Packit 6c4009
#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
Packit 6c4009
/* M68K needs system-supplied DSO to access TLS helpers
Packit 6c4009
   even when statically linked.  */
Packit 6c4009
# define NEED_STATIC_SYSINFO_DSO 1
Packit 6c4009
#endif