(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
hppa/
sysdep.h
       1  /* Assembler macros for PA-RISC.
       2     Copyright (C) 1999-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       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.
       9  
      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.
      14  
      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     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifndef _LINUX_HPPA_SYSDEP_H
      20  #define _LINUX_HPPA_SYSDEP_H 1
      21  
      22  #include <sysdeps/unix/sysdep.h>
      23  #include <sysdeps/unix/sysv/linux/sysdep.h>
      24  #include <sysdeps/hppa/sysdep.h>
      25  
      26  /* Defines RTLD_PRIVATE_ERRNO.  */
      27  #include <dl-sysdep.h>
      28  
      29  #include <tls.h>
      30  
      31  /* In order to get __set_errno() definition in INLINE_SYSCALL.  */
      32  #ifndef __ASSEMBLER__
      33  #include <errno.h>
      34  #endif
      35  
      36  #undef ASM_LINE_SEP
      37  #define ASM_LINE_SEP !
      38  
      39  #undef SYS_ify
      40  #define SYS_ify(syscall_name)	(__NR_##syscall_name)
      41  
      42  /* The vfork, fork, and clone syscalls clobber r19
      43   * and r21. We list r21 as either clobbered or as an
      44   * input to a 6-argument syscall. We must save and
      45   * restore r19 in both PIC and non-PIC cases.
      46   */
      47  /* WARNING: TREG must be a callee saves register so
      48     that it doesn't have to be restored after a call
      49     to another function */
      50  #define TREG 4
      51  #define SAVE_PIC(SREG) \
      52  	copy %r19, SREG
      53  #define LOAD_PIC(LREG) \
      54  	copy LREG , %r19
      55  /* Inline assembly defines */
      56  #define TREG_ASM "%r4" /* Can't clobber r3, it holds framemarker */
      57  #define SAVE_ASM_PIC	"       copy %%r19, %" TREG_ASM "\n"
      58  #define LOAD_ASM_PIC	"       copy %" TREG_ASM ", %%r19\n"
      59  #define CLOB_TREG	TREG_ASM ,
      60  #define PIC_REG_DEF	register unsigned long __r19 asm("r19");
      61  #define PIC_REG_USE	, "r" (__r19)
      62  
      63  #ifdef __ASSEMBLER__
      64  
      65  /* Syntactic details of assembler.  */
      66  
      67  #define ALIGNARG(log2) log2
      68  
      69  /* For Linux we can use the system call table in the header file
      70  	/usr/include/asm/unistd.h
      71     of the kernel.  But these symbols do not follow the SYS_* syntax
      72     so we have to redefine the `SYS_ify' macro here.  */
      73  #undef SYS_ify
      74  #define SYS_ify(syscall_name)	__NR_##syscall_name
      75  
      76  /* ELF-like local names start with `.L'.  */
      77  #undef L
      78  #define L(name)	.L##name
      79  
      80  /* Linux uses a negative return value to indicate syscall errors,
      81     unlike most Unices, which use the condition codes' carry flag.
      82  
      83     Since version 2.1 the return value of a system call might be
      84     negative even if the call succeeded.  E.g., the `lseek' system call
      85     might return a large offset.  Therefore we must not anymore test
      86     for < 0, but test for a real error by making sure the value in %eax
      87     is a real error number.  Linus said he will make sure the no syscall
      88     returns a value in -1 .. -4095 as a valid result so we can safely
      89     test with -4095.  */
      90  
      91  /* We don't want the label for the error handle to be global when we define
      92     it here.  */
      93  /*#ifdef PIC
      94  # define SYSCALL_ERROR_LABEL 0f
      95  #else
      96  # define SYSCALL_ERROR_LABEL syscall_error
      97  #endif*/
      98  
      99  /* Argument manipulation from the stack for preparing to
     100     make a syscall */
     101  
     102  #define DOARGS_0 /* nothing */
     103  #define DOARGS_1 /* nothing */
     104  #define DOARGS_2 /* nothing */
     105  #define DOARGS_3 /* nothing */
     106  #define DOARGS_4 /* nothing */
     107  #define DOARGS_5 ldw -52(%sp), %r22		ASM_LINE_SEP
     108  #define DOARGS_6 DOARGS_5 ldw -56(%sp), %r21	ASM_LINE_SEP
     109  
     110  #define UNDOARGS_0 /* nothing */
     111  #define UNDOARGS_1 /* nothing */
     112  #define UNDOARGS_2 /* nothing */
     113  #define UNDOARGS_3 /* nothing */
     114  #define UNDOARGS_4 /* nothing */
     115  #define UNDOARGS_5 /* nothing */
     116  #define UNDOARGS_6 /* nothing */
     117  
     118  /* Define an entry point visible from C.
     119  
     120     There is currently a bug in gdb which prevents us from specifying
     121     incomplete stabs information.  Fake some entries here which specify
     122     the current source file.  */
     123  #undef ENTRY
     124  #define	ENTRY(name)							\
     125  	.text						ASM_LINE_SEP	\
     126  	.align ALIGNARG(4)				ASM_LINE_SEP	\
     127  	.export C_SYMBOL_NAME(name)			ASM_LINE_SEP	\
     128  	.type	C_SYMBOL_NAME(name),@function		ASM_LINE_SEP	\
     129  	cfi_startproc					ASM_LINE_SEP	\
     130  	C_LABEL(name)					ASM_LINE_SEP	\
     131  	.PROC						ASM_LINE_SEP	\
     132  	.CALLINFO FRAME=64,CALLS,SAVE_RP,ENTRY_GR=3	ASM_LINE_SEP	\
     133  	.ENTRY						ASM_LINE_SEP	\
     134  	/* SAVE_RP says we do */			ASM_LINE_SEP	\
     135  	stw %rp, -20(%sr0,%sp)				ASM_LINE_SEP	\
     136  	.cfi_offset 2, -20				ASM_LINE_SEP	\
     137  	/*FIXME: Call mcount? (careful with stack!) */
     138  
     139  /* Some syscall wrappers do not call other functions, and
     140     hence are classified as leaf, so add NO_CALLS for gdb */
     141  #define	ENTRY_LEAF(name)						\
     142  	.text						ASM_LINE_SEP	\
     143  	.align ALIGNARG(4)				ASM_LINE_SEP	\
     144  	.export C_SYMBOL_NAME(name)			ASM_LINE_SEP	\
     145  	.type	C_SYMBOL_NAME(name),@function		ASM_LINE_SEP	\
     146  	cfi_startproc					ASM_LINE_SEP	\
     147  	C_LABEL(name)					ASM_LINE_SEP	\
     148  	.PROC						ASM_LINE_SEP	\
     149  	.CALLINFO FRAME=64,NO_CALLS,SAVE_RP,ENTRY_GR=3	ASM_LINE_SEP	\
     150  	.ENTRY						ASM_LINE_SEP	\
     151  	/* SAVE_RP says we do */			ASM_LINE_SEP	\
     152  	stw %rp, -20(%sr0,%sp)				ASM_LINE_SEP	\
     153  	.cfi_offset 2, -20				ASM_LINE_SEP	\
     154  	/*FIXME: Call mcount? (careful with stack!) */
     155  
     156  #undef	END
     157  #define END(name)							\
     158  	.EXIT						ASM_LINE_SEP	\
     159  	.PROCEND					ASM_LINE_SEP	\
     160  	cfi_endproc					ASM_LINE_SEP	\
     161  .size	C_SYMBOL_NAME(name), .-C_SYMBOL_NAME(name)	ASM_LINE_SEP
     162  
     163  /* If compiled for profiling, call `mcount' at the start
     164     of each function. No, don't bother.  gcc will put the
     165     call in for us.  */
     166  #define CALL_MCOUNT		/* Do nothing.  */
     167  
     168  /* syscall wrappers consist of
     169  	#include <sysdep.h>
     170  	PSEUDO(...)
     171  	ret
     172  	PSEUDO_END(...)
     173  
     174     which means
     175  	ENTRY(name)
     176  	DO_CALL(...)
     177  	bv,n 0(2)
     178  */
     179  
     180  #undef PSEUDO
     181  #define	PSEUDO(name, syscall_name, args)			\
     182    ENTRY (name)					ASM_LINE_SEP	\
     183    /* If necc. load args from stack */		ASM_LINE_SEP	\
     184    DOARGS_##args					ASM_LINE_SEP	\
     185    DO_CALL (syscall_name, args)			ASM_LINE_SEP	\
     186    UNDOARGS_##args				ASM_LINE_SEP
     187  
     188  #define ret \
     189    /* Return value set by ERRNO code */		ASM_LINE_SEP	\
     190    bv,n 0(2)					ASM_LINE_SEP
     191  
     192  #undef	PSEUDO_END
     193  #define	PSEUDO_END(name)					\
     194    END (name)
     195  
     196  /* We don't set the errno on the return from the syscall */
     197  #define	PSEUDO_NOERRNO(name, syscall_name, args)		\
     198    ENTRY_LEAF (name)				ASM_LINE_SEP	\
     199    DOARGS_##args					ASM_LINE_SEP	\
     200    DO_CALL_NOERRNO (syscall_name, args)		ASM_LINE_SEP	\
     201    UNDOARGS_##args				ASM_LINE_SEP
     202  
     203  #define ret_NOERRNO ret
     204  
     205  #undef	PSEUDO_END_NOERRNO
     206  #define	PSEUDO_END_NOERRNO(name)				\
     207    END (name)
     208  
     209  /* This has to return the error value */
     210  #undef  PSEUDO_ERRVAL
     211  #define PSEUDO_ERRVAL(name, syscall_name, args)			\
     212    ENTRY_LEAF (name)				ASM_LINE_SEP	\
     213    DOARGS_##args					ASM_LINE_SEP	\
     214    DO_CALL_ERRVAL (syscall_name, args)		ASM_LINE_SEP	\
     215    UNDOARGS_##args				ASM_LINE_SEP
     216  
     217  #define ret_ERRVAL ret
     218  
     219  #undef	PSEUDO_END_ERRVAL
     220  #define PSEUDO_END_ERRVAL(name)					\
     221  	END(name)
     222  
     223  #undef JUMPTARGET
     224  #define JUMPTARGET(name)	name
     225  #define SYSCALL_PIC_SETUP	/* Nothing.  */
     226  
     227  
     228  /* FIXME: This comment is not true.
     229   * All the syscall assembly macros rely on finding the appropriate
     230     SYSCALL_ERROR_LABEL or rather HANDLER. */
     231  
     232  /* int * __errno_location(void) so you have to store your value
     233     into the return address! */
     234  #define DEFAULT_SYSCALL_ERROR_HANDLER			\
     235  	.import __errno_location,code	ASM_LINE_SEP	\
     236  	/* branch to errno handler */	ASM_LINE_SEP	\
     237  	bl __errno_location,%rp		ASM_LINE_SEP
     238  
     239  /* Here are the myriad of configuration options that the above can
     240     work for... what we've done is provide the framework for future
     241     changes if required to each section */
     242  
     243  #ifdef PIC
     244  # if RTLD_PRIVATE_ERRNO
     245  #  define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER
     246  # else /* !RTLD_PRIVATE_ERRNO */
     247  #  if defined _LIBC_REENTRANT
     248  #   define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER
     249  #  else /* !_LIBC_REENTRANT */
     250  #   define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER
     251  #  endif /* _LIBC_REENTRANT */
     252  # endif /* RTLD_PRIVATE_ERRNO */
     253  #else
     254  # ifndef _LIBC_REENTRANT
     255  #  define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER
     256  # else
     257  #  define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER
     258  # endif
     259  #endif
     260  
     261  
     262  /* Linux takes system call arguments in registers:
     263  	syscall number	gr20
     264  	arg 1		gr26
     265  	arg 2		gr25
     266  	arg 3		gr24
     267  	arg 4		gr23
     268  	arg 5		gr22
     269  	arg 6		gr21
     270  
     271     The compiler calls us by the C convention:
     272  	syscall number	in the DO_CALL macro
     273  	arg 1		gr26
     274  	arg 2		gr25
     275  	arg 3		gr24
     276  	arg 4		gr23
     277  	arg 5		-52(sp)
     278  	arg 6		-56(sp)
     279  
     280     gr22 and gr21 are caller-saves, so we can just load the arguments
     281     there and generally be happy. */
     282  
     283  /* the cmpb...no_error code below inside DO_CALL
     284   * is intended to mimic the if (__sys_res...)
     285   * code inside INLINE_SYSCALL
     286   */
     287  #define NO_ERROR -0x1000
     288  
     289  #undef	DO_CALL
     290  #define DO_CALL(syscall_name, args)				\
     291  	/* Create a frame */			ASM_LINE_SEP	\
     292  	stwm TREG, 64(%sp)			ASM_LINE_SEP	\
     293  	.cfi_def_cfa_offset -64			ASM_LINE_SEP	\
     294  	.cfi_offset TREG, 0			ASM_LINE_SEP	\
     295  	stw %sp, -4(%sp)			ASM_LINE_SEP	\
     296  	stw %r19, -32(%sp)			ASM_LINE_SEP	\
     297  	.cfi_offset 19, 32			ASM_LINE_SEP	\
     298  	/* Save r19 */				ASM_LINE_SEP	\
     299  	SAVE_PIC(TREG)				ASM_LINE_SEP	\
     300  	/* Do syscall, delay loads # */		ASM_LINE_SEP	\
     301  	ble  0x100(%sr2,%r0)			ASM_LINE_SEP	\
     302  	ldi SYS_ify (syscall_name), %r20	ASM_LINE_SEP	\
     303  	ldi NO_ERROR,%r1			ASM_LINE_SEP	\
     304  	cmpb,>>=,n %r1,%ret0,L(pre_end)		ASM_LINE_SEP	\
     305  	/* Restore r19 from TREG */		ASM_LINE_SEP	\
     306  	LOAD_PIC(TREG) /* delay */		ASM_LINE_SEP	\
     307  	SYSCALL_ERROR_HANDLER			ASM_LINE_SEP	\
     308  	/* Use TREG for temp storage */		ASM_LINE_SEP	\
     309  	copy %ret0, TREG /* delay */		ASM_LINE_SEP	\
     310  	/* OPTIMIZE: Don't reload r19 */	ASM_LINE_SEP	\
     311  	/* do a -1*syscall_ret0 */		ASM_LINE_SEP	\
     312  	sub %r0, TREG, TREG			ASM_LINE_SEP	\
     313  	/* Store into errno location */		ASM_LINE_SEP	\
     314  	stw TREG, 0(%sr0,%ret0)			ASM_LINE_SEP	\
     315  	/* return -1 as error */		ASM_LINE_SEP	\
     316  	ldo -1(%r0), %ret0			ASM_LINE_SEP	\
     317  L(pre_end):					ASM_LINE_SEP	\
     318  	/* Restore our frame, restoring TREG */	ASM_LINE_SEP	\
     319  	ldwm -64(%sp), TREG			ASM_LINE_SEP	\
     320  	/* Restore return pointer */		ASM_LINE_SEP	\
     321  	ldw -20(%sp),%rp			ASM_LINE_SEP
     322  
     323  /* We do nothing with the return, except hand it back to someone else */
     324  #undef  DO_CALL_NOERRNO
     325  #define DO_CALL_NOERRNO(syscall_name, args)			\
     326  	/* No need to store r19 */		ASM_LINE_SEP	\
     327  	ble  0x100(%sr2,%r0)                    ASM_LINE_SEP    \
     328  	ldi SYS_ify (syscall_name), %r20        ASM_LINE_SEP    \
     329  	/* Caller will restore r19 */		ASM_LINE_SEP
     330  
     331  /* Here, we return the ERRVAL in assembly, note we don't call the
     332     error handler function, but we do 'negate' the return _IF_
     333     it's an error. Not sure if this is the right semantic. */
     334  
     335  #undef	DO_CALL_ERRVAL
     336  #define DO_CALL_ERRVAL(syscall_name, args)			\
     337  	/* No need to store r19 */		ASM_LINE_SEP	\
     338  	ble  0x100(%sr2,%r0)			ASM_LINE_SEP	\
     339  	ldi SYS_ify (syscall_name), %r20	ASM_LINE_SEP	\
     340  	/* Caller will restore r19 */		ASM_LINE_SEP	\
     341  	ldi NO_ERROR,%r1			ASM_LINE_SEP	\
     342  	cmpb,>>=,n %r1,%ret0,0f			ASM_LINE_SEP	\
     343  	sub %r0, %ret0, %ret0			ASM_LINE_SEP	\
     344  0:						ASM_LINE_SEP
     345  
     346  
     347  #else
     348  
     349  /* GCC has to be warned that a syscall may clobber all the ABI
     350     registers listed as "caller-saves", see page 8, Table 2
     351     in section 2.2.6 of the PA-RISC RUN-TIME architecture
     352     document. However! r28 is the result and will conflict with
     353     the clobber list so it is left out. Also the input arguments
     354     registers r20 -> r26 will conflict with the list so they
     355     are treated specially. Although r19 is clobbered by the syscall
     356     we cannot say this because it would violate ABI, thus we say
     357     TREG is clobbered and use that register to save/restore r19
     358     across the syscall. */
     359  
     360  #define CALL_CLOB_REGS	"%r1", "%r2", CLOB_TREG \
     361  			"%r20", "%r29", "%r31"
     362  
     363  /* Similar to INLINE_SYSCALL but we don't set errno */
     364  #undef INTERNAL_SYSCALL
     365  #define INTERNAL_SYSCALL(name, nr, args...)				\
     366  ({									\
     367  	long __sys_res;							\
     368  	{								\
     369  		LOAD_ARGS_##nr(args)					\
     370  		register unsigned long __res asm("r28");		\
     371  		PIC_REG_DEF						\
     372  		LOAD_REGS_##nr						\
     373  		/* FIXME: HACK save/load r19 around syscall */		\
     374  		asm volatile(						\
     375  			SAVE_ASM_PIC					\
     376  			"	ble  0x100(%%sr2, %%r0)\n"		\
     377  			"	ldi %1, %%r20\n"			\
     378  			LOAD_ASM_PIC					\
     379  			: "=r" (__res)					\
     380  			: "i" (SYS_ify(name)) PIC_REG_USE ASM_ARGS_##nr	\
     381  			: "memory", CALL_CLOB_REGS CLOB_ARGS_##nr	\
     382  		);							\
     383  		__sys_res = (long)__res;				\
     384  	}								\
     385  	__sys_res;							\
     386   })
     387  
     388  
     389  /* The _NCS variant allows non-constant syscall numbers.  */
     390  #undef INTERNAL_SYSCALL_NCS
     391  #define INTERNAL_SYSCALL_NCS(name, nr, args...)				\
     392  ({									\
     393  	long __sys_res;							\
     394  	{								\
     395  		LOAD_ARGS_##nr(args)					\
     396  		register unsigned long __res asm("r28");		\
     397  		PIC_REG_DEF						\
     398  		LOAD_REGS_##nr						\
     399  		/* FIXME: HACK save/load r19 around syscall */		\
     400  		asm volatile(						\
     401  			SAVE_ASM_PIC					\
     402  			"	ble  0x100(%%sr2, %%r0)\n"		\
     403  			"	copy %1, %%r20\n"			\
     404  			LOAD_ASM_PIC					\
     405  			: "=r" (__res)					\
     406  			: "r" (name) PIC_REG_USE ASM_ARGS_##nr		\
     407  			: "memory", CALL_CLOB_REGS CLOB_ARGS_##nr	\
     408  		);							\
     409  		__sys_res = (long)__res;				\
     410  	}								\
     411  	__sys_res;							\
     412   })
     413  
     414  #define LOAD_ARGS_0()
     415  #define LOAD_REGS_0
     416  #define LOAD_ARGS_1(a1)							\
     417    register unsigned long __x26 = (unsigned long)(a1);			\
     418    LOAD_ARGS_0()
     419  #define LOAD_REGS_1							\
     420    register unsigned long __r26 __asm__("r26") = __x26;			\
     421    LOAD_REGS_0
     422  #define LOAD_ARGS_2(a1,a2)						\
     423    register unsigned long __x25 = (unsigned long)(a2);			\
     424    LOAD_ARGS_1(a1)
     425  #define LOAD_REGS_2							\
     426    register unsigned long __r25 __asm__("r25") = __x25;			\
     427    LOAD_REGS_1
     428  #define LOAD_ARGS_3(a1,a2,a3)						\
     429    register unsigned long __x24 = (unsigned long)(a3);			\
     430    LOAD_ARGS_2(a1,a2)
     431  #define LOAD_REGS_3							\
     432    register unsigned long __r24 __asm__("r24") = __x24;			\
     433    LOAD_REGS_2
     434  #define LOAD_ARGS_4(a1,a2,a3,a4)					\
     435    register unsigned long __x23 = (unsigned long)(a4);			\
     436    LOAD_ARGS_3(a1,a2,a3)
     437  #define LOAD_REGS_4							\
     438    register unsigned long __r23 __asm__("r23") = __x23;			\
     439    LOAD_REGS_3
     440  #define LOAD_ARGS_5(a1,a2,a3,a4,a5)					\
     441    register unsigned long __x22 = (unsigned long)(a5);			\
     442    LOAD_ARGS_4(a1,a2,a3,a4)
     443  #define LOAD_REGS_5							\
     444    register unsigned long __r22 __asm__("r22") = __x22;			\
     445    LOAD_REGS_4
     446  #define LOAD_ARGS_6(a1,a2,a3,a4,a5,a6)					\
     447    register unsigned long __x21 = (unsigned long)(a6);			\
     448    LOAD_ARGS_5(a1,a2,a3,a4,a5)
     449  #define LOAD_REGS_6							\
     450    register unsigned long __r21 __asm__("r21") = __x21;			\
     451    LOAD_REGS_5
     452  
     453  /* Even with zero args we use r20 for the syscall number */
     454  #define ASM_ARGS_0
     455  #define ASM_ARGS_1 ASM_ARGS_0, "r" (__r26)
     456  #define ASM_ARGS_2 ASM_ARGS_1, "r" (__r25)
     457  #define ASM_ARGS_3 ASM_ARGS_2, "r" (__r24)
     458  #define ASM_ARGS_4 ASM_ARGS_3, "r" (__r23)
     459  #define ASM_ARGS_5 ASM_ARGS_4, "r" (__r22)
     460  #define ASM_ARGS_6 ASM_ARGS_5, "r" (__r21)
     461  
     462  /* The registers not listed as inputs but clobbered */
     463  #define CLOB_ARGS_6
     464  #define CLOB_ARGS_5 CLOB_ARGS_6, "%r21"
     465  #define CLOB_ARGS_4 CLOB_ARGS_5, "%r22"
     466  #define CLOB_ARGS_3 CLOB_ARGS_4, "%r23"
     467  #define CLOB_ARGS_2 CLOB_ARGS_3, "%r24"
     468  #define CLOB_ARGS_1 CLOB_ARGS_2, "%r25"
     469  #define CLOB_ARGS_0 CLOB_ARGS_1, "%r26"
     470  
     471  #endif	/* __ASSEMBLER__ */
     472  
     473  #endif /* _LINUX_HPPA_SYSDEP_H */