1  /* Copyright (C) 1996-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library.  If not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <sysdeps/unix/sysv/linux/sysdep.h>
      19  #include <tls.h>
      20  
      21  /* Defines RTLD_PRIVATE_ERRNO.  */
      22  #include <dl-sysdep.h>
      23  
      24  /* For Linux we can use the system call table in the header file
      25  	/usr/include/asm/unistd.h
      26     of the kernel.  But these symbols do not follow the SYS_* syntax
      27     so we have to redefine the `SYS_ify' macro here.  */
      28  #undef SYS_ify
      29  #define SYS_ify(syscall_name)	__NR_##syscall_name
      30  
      31  #ifdef __ASSEMBLER__
      32  
      33  /* Linux uses a negative return value to indicate syscall errors, unlike
      34     most Unices, which use the condition codes' carry flag.
      35  
      36     Since version 2.1 the return value of a system call might be negative
      37     even if the call succeeded.  E.g., the `lseek' system call might return
      38     a large offset.  Therefore we must not anymore test for < 0, but test
      39     for a real error by making sure the value in %d0 is a real error
      40     number.  Linus said he will make sure the no syscall returns a value
      41     in -1 .. -4095 as a valid result so we can safely test with -4095.  */
      42  
      43  /* We don't want the label for the error handler to be visible in the symbol
      44     table when we define it here.  */
      45  #undef SYSCALL_ERROR_LABEL
      46  #ifdef PIC
      47  #define SYSCALL_ERROR_LABEL .Lsyscall_error
      48  #else
      49  #define SYSCALL_ERROR_LABEL __syscall_error
      50  #endif
      51  
      52  #undef PSEUDO
      53  #define	PSEUDO(name, syscall_name, args)				      \
      54    .text;								      \
      55    ENTRY (name)								      \
      56      DO_CALL (syscall_name, args);					      \
      57      cmp.l &-4095, %d0;							      \
      58      jcc SYSCALL_ERROR_LABEL
      59  
      60  #undef PSEUDO_END
      61  #define PSEUDO_END(name)						      \
      62    SYSCALL_ERROR_HANDLER;						      \
      63    END (name)
      64  
      65  #undef PSEUDO_NOERRNO
      66  #define	PSEUDO_NOERRNO(name, syscall_name, args)			      \
      67    .text;								      \
      68    ENTRY (name)								      \
      69      DO_CALL (syscall_name, args)
      70  
      71  #undef PSEUDO_END_NOERRNO
      72  #define PSEUDO_END_NOERRNO(name)					      \
      73    END (name)
      74  
      75  #define ret_NOERRNO rts
      76  
      77  /* The function has to return the error code.  */
      78  #undef	PSEUDO_ERRVAL
      79  #define	PSEUDO_ERRVAL(name, syscall_name, args) \
      80    .text;								      \
      81    ENTRY (name)								      \
      82      DO_CALL (syscall_name, args);					      \
      83      negl %d0
      84  
      85  #undef	PSEUDO_END_ERRVAL
      86  #define	PSEUDO_END_ERRVAL(name) \
      87    END (name)
      88  
      89  #define ret_ERRVAL rts
      90  
      91  #ifdef PIC
      92  # if RTLD_PRIVATE_ERRNO
      93  #  define SYSCALL_ERROR_HANDLER						      \
      94  SYSCALL_ERROR_LABEL:							      \
      95      PCREL_OP (lea, rtld_errno, %a0, %a0);				      \
      96      neg.l %d0;								      \
      97      move.l %d0, (%a0);							      \
      98      move.l &-1, %d0;							      \
      99      /* Copy return value to %a0 for syscalls that are declared to return      \
     100         a pointer (e.g., mmap).  */					      \
     101      move.l %d0, %a0;							      \
     102      rts;
     103  # elif defined _LIBC_REENTRANT
     104  #  if IS_IN (libc)
     105  #   define SYSCALL_ERROR_ERRNO __libc_errno
     106  #  else
     107  #   define SYSCALL_ERROR_ERRNO errno
     108  #  endif
     109  #  define SYSCALL_ERROR_HANDLER						      \
     110  SYSCALL_ERROR_LABEL:							      \
     111      neg.l %d0;								      \
     112      move.l %d0, -(%sp);							      \
     113      cfi_adjust_cfa_offset (4);						      \
     114      jbsr __m68k_read_tp@PLTPC;						      \
     115      SYSCALL_ERROR_LOAD_GOT (%a1);					      \
     116      add.l (SYSCALL_ERROR_ERRNO@TLSIE, %a1), %a0;			      \
     117      move.l (%sp)+, (%a0);						      \
     118      cfi_adjust_cfa_offset (-4);						      \
     119      move.l &-1, %d0;							      \
     120      /* Copy return value to %a0 for syscalls that are declared to return      \
     121         a pointer (e.g., mmap).  */					      \
     122      move.l %d0, %a0;							      \
     123      rts;
     124  # else /* !_LIBC_REENTRANT */
     125  /* Store (- %d0) into errno through the GOT.  */
     126  #  define SYSCALL_ERROR_HANDLER						      \
     127  SYSCALL_ERROR_LABEL:							      \
     128      move.l (errno@GOTPC, %pc), %a0;					      \
     129      neg.l %d0;								      \
     130      move.l %d0, (%a0);							      \
     131      move.l &-1, %d0;							      \
     132      /* Copy return value to %a0 for syscalls that are declared to return      \
     133         a pointer (e.g., mmap).  */					      \
     134      move.l %d0, %a0;							      \
     135      rts;
     136  # endif /* _LIBC_REENTRANT */
     137  #else
     138  # define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */
     139  #endif /* PIC */
     140  
     141  /* Linux takes system call arguments in registers:
     142  
     143  	syscall number	%d0	     call-clobbered
     144  	arg 1		%d1	     call-clobbered
     145  	arg 2		%d2	     call-saved
     146  	arg 3		%d3	     call-saved
     147  	arg 4		%d4	     call-saved
     148  	arg 5		%d5	     call-saved
     149  	arg 6		%a0	     call-clobbered
     150  
     151     The stack layout upon entering the function is:
     152  
     153  	24(%sp)		Arg# 6
     154  	20(%sp)		Arg# 5
     155  	16(%sp)		Arg# 4
     156  	12(%sp)		Arg# 3
     157  	 8(%sp)		Arg# 2
     158  	 4(%sp)		Arg# 1
     159  	  (%sp)		Return address
     160  
     161     (Of course a function with say 3 arguments does not have entries for
     162     arguments 4 and 5.)
     163  
     164     Separate move's are faster than movem, but need more space.  Since
     165     speed is more important, we don't use movem.  Since %a0 and %a1 are
     166     scratch registers, we can use them for saving as well.  */
     167  
     168  #define DO_CALL(syscall_name, args)			      		      \
     169      move.l &SYS_ify(syscall_name), %d0;					      \
     170      DOARGS_##args							      \
     171      trap &0;								      \
     172      UNDOARGS_##args
     173  
     174  #define	DOARGS_0	/* No arguments to frob.  */
     175  #define	UNDOARGS_0	/* No arguments to unfrob.  */
     176  #define	_DOARGS_0(n)	/* No arguments to frob.  */
     177  
     178  #define	DOARGS_1	_DOARGS_1 (4)
     179  #define	_DOARGS_1(n)	move.l n(%sp), %d1; _DOARGS_0 (n)
     180  #define	UNDOARGS_1	UNDOARGS_0
     181  
     182  #define	DOARGS_2	_DOARGS_2 (8)
     183  #define	_DOARGS_2(n)	move.l %d2, %a0; cfi_register (%d2, %a0);	      \
     184  			move.l n(%sp), %d2; _DOARGS_1 (n-4)
     185  #define	UNDOARGS_2	UNDOARGS_1; move.l %a0, %d2; cfi_restore (%d2)
     186  
     187  #define DOARGS_3	_DOARGS_3 (12)
     188  #define _DOARGS_3(n)	move.l %d3, %a1; cfi_register (%d3, %a1);	      \
     189  			move.l n(%sp), %d3; _DOARGS_2 (n-4)
     190  #define UNDOARGS_3	UNDOARGS_2; move.l %a1, %d3; cfi_restore (%d3)
     191  
     192  #define DOARGS_4	_DOARGS_4 (16)
     193  #define _DOARGS_4(n)	move.l %d4, -(%sp);				      \
     194  			cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);   \
     195  			move.l n+4(%sp), %d4; _DOARGS_3 (n)
     196  #define UNDOARGS_4	UNDOARGS_3; move.l (%sp)+, %d4;			      \
     197  			cfi_adjust_cfa_offset (-4); cfi_restore (%d4)
     198  
     199  #define DOARGS_5	_DOARGS_5 (20)
     200  #define _DOARGS_5(n)	move.l %d5, -(%sp); 				      \
     201  			cfi_adjust_cfa_offset (4); cfi_rel_offset (%d5, 0);   \
     202  			move.l n+4(%sp), %d5; _DOARGS_4 (n)
     203  #define UNDOARGS_5	UNDOARGS_4; move.l (%sp)+, %d5;			      \
     204  			cfi_adjust_cfa_offset (-4); cfi_restore (%d5)
     205  
     206  #define DOARGS_6	_DOARGS_6 (24)
     207  #define _DOARGS_6(n)	_DOARGS_5 (n-4); move.l %a0, -(%sp);		      \
     208  			cfi_adjust_cfa_offset (4);			      \
     209  			move.l n+12(%sp), %a0;
     210  #define UNDOARGS_6	move.l (%sp)+, %a0; cfi_adjust_cfa_offset (-4);	      \
     211  			UNDOARGS_5
     212  
     213  
     214  #define	ret	rts
     215  #if 0 /* Not used by Linux */
     216  #define	r0	%d0
     217  #define	r1	%d1
     218  #define	MOVE(x,y)	movel x , y
     219  #endif
     220  
     221  #else /* not __ASSEMBLER__ */
     222  
     223  /* Define a macro which expands inline into the wrapper code for a system
     224     call.  This use is for internal calls that do not need to handle errors
     225     normally.  It will never touch errno.  This returns just what the kernel
     226     gave back.  */
     227  #undef INTERNAL_SYSCALL
     228  #define INTERNAL_SYSCALL_NCS(name, nr, args...)	\
     229    ({ unsigned int _sys_result;				\
     230       {							\
     231         /* Load argument values in temporary variables
     232  	  to perform side effects like function calls
     233  	  before the call used registers are set.  */	\
     234         LOAD_ARGS_##nr (args)				\
     235         LOAD_REGS_##nr					\
     236         register int _d0 asm ("%d0") = name;		\
     237         asm volatile ("trap #0"				\
     238  		     : "=d" (_d0)			\
     239  		     : "0" (_d0) ASM_ARGS_##nr		\
     240  		     : "memory");			\
     241         _sys_result = _d0;				\
     242       }							\
     243       (int) _sys_result; })
     244  #define INTERNAL_SYSCALL(name, nr, args...)	\
     245    INTERNAL_SYSCALL_NCS (__NR_##name, nr, ##args)
     246  
     247  #define LOAD_ARGS_0()
     248  #define LOAD_REGS_0
     249  #define ASM_ARGS_0
     250  #define LOAD_ARGS_1(a1)				\
     251    LOAD_ARGS_0 ()				\
     252    int __arg1 = (int) (a1);
     253  #define LOAD_REGS_1				\
     254    register int _d1 asm ("d1") = __arg1;		\
     255    LOAD_REGS_0
     256  #define ASM_ARGS_1	ASM_ARGS_0, "d" (_d1)
     257  #define LOAD_ARGS_2(a1, a2)			\
     258    LOAD_ARGS_1 (a1)				\
     259    int __arg2 = (int) (a2);
     260  #define LOAD_REGS_2				\
     261    register int _d2 asm ("d2") = __arg2;		\
     262    LOAD_REGS_1
     263  #define ASM_ARGS_2	ASM_ARGS_1, "d" (_d2)
     264  #define LOAD_ARGS_3(a1, a2, a3)			\
     265    LOAD_ARGS_2 (a1, a2)				\
     266    int __arg3 = (int) (a3);
     267  #define LOAD_REGS_3				\
     268    register int _d3 asm ("d3") = __arg3;		\
     269    LOAD_REGS_2
     270  #define ASM_ARGS_3	ASM_ARGS_2, "d" (_d3)
     271  #define LOAD_ARGS_4(a1, a2, a3, a4)		\
     272    LOAD_ARGS_3 (a1, a2, a3)			\
     273    int __arg4 = (int) (a4);
     274  #define LOAD_REGS_4				\
     275    register int _d4 asm ("d4") = __arg4;		\
     276    LOAD_REGS_3
     277  #define ASM_ARGS_4	ASM_ARGS_3, "d" (_d4)
     278  #define LOAD_ARGS_5(a1, a2, a3, a4, a5)		\
     279    LOAD_ARGS_4 (a1, a2, a3, a4)			\
     280    int __arg5 = (int) (a5);
     281  #define LOAD_REGS_5				\
     282    register int _d5 asm ("d5") = __arg5;		\
     283    LOAD_REGS_4
     284  #define ASM_ARGS_5	ASM_ARGS_4, "d" (_d5)
     285  #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)	\
     286    LOAD_ARGS_5 (a1, a2, a3, a4, a5)		\
     287    int __arg6 = (int) (a6);
     288  #define LOAD_REGS_6				\
     289    register int _a0 asm ("a0") = __arg6;		\
     290    LOAD_REGS_5
     291  #define ASM_ARGS_6	ASM_ARGS_5, "a" (_a0)
     292  
     293  #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
     294  #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
     295  
     296  #endif /* not __ASSEMBLER__ */
     297  
     298  /* M68K needs system-supplied DSO to access TLS helpers
     299     even when statically linked.  */
     300  #define NEED_STATIC_SYSINFO_DSO 1