(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
arm/
sysdep.h
       1  /* Copyright (C) 1992-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  #ifndef _LINUX_ARM_SYSDEP_H
      19  #define _LINUX_ARM_SYSDEP_H 1
      20  
      21  /* There is some commonality.  */
      22  #include <sysdeps/unix/sysv/linux/sysdep.h>
      23  #include <sysdeps/unix/arm/sysdep.h>
      24  
      25  /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO.  */
      26  #include <dl-sysdep.h>
      27  
      28  #include <tls.h>
      29  
      30  /* For Linux we can use the system call table in the header file
      31  	/usr/include/asm/unistd.h
      32     of the kernel.  But these symbols do not follow the SYS_* syntax
      33     so we have to redefine the `SYS_ify' macro here.  */
      34  #undef SYS_ify
      35  #define SYS_ify(syscall_name)	(__NR_##syscall_name)
      36  
      37  #include <bits/hwcap.h>
      38  
      39  #ifdef __ASSEMBLER__
      40  
      41  #ifndef ARCH_HAS_HARD_TP
      42  /* Internal macro calling the linux kernel kuser_get_tls helper.
      43     Note that in thumb mode, a constant pool break is often out of range, so
      44     we always expand the constant inline.  */
      45  # ifdef __thumb2__
      46  #  define GET_TLS_BODY			\
      47  	movw	r0, #0x0fe0;		\
      48  	movt	r0, #0xffff;		\
      49  	blx	r0
      50  # else
      51  #  define GET_TLS_BODY \
      52  	mov	r0, #0xffff0fff;	/* Point to the high page.  */	\
      53  	mov	lr, pc;			/* Save our return address.  */	\
      54  	sub	pc, r0, #31		/* Jump to the TLS entry.  */
      55  # endif
      56  
      57  /* Helper to get the TLS base pointer.  Save LR in TMP, return in R0,
      58     and no other registers clobbered.  TMP may be LR itself to indicate
      59     that no save is necessary.  */
      60  # undef GET_TLS
      61  # define GET_TLS(TMP)			\
      62    .ifnc TMP, lr;			\
      63  	mov	TMP, lr;		\
      64  	cfi_register (lr, TMP);		\
      65  	GET_TLS_BODY;			\
      66  	mov	lr, TMP;		\
      67  	cfi_restore (lr);		\
      68    .else;				\
      69  	GET_TLS_BODY;			\
      70    .endif
      71  #endif /* ARCH_HAS_HARD_TP */
      72  
      73  /* Linux uses a negative return value to indicate syscall errors,
      74     unlike most Unices, which use the condition codes' carry flag.
      75  
      76     Since version 2.1 the return value of a system call might be
      77     negative even if the call succeeded.  E.g., the `lseek' system call
      78     might return a large offset.  Therefore we must not anymore test
      79     for < 0, but test for a real error by making sure the value in R0
      80     is a real error number.  Linus said he will make sure the no syscall
      81     returns a value in -1 .. -4095 as a valid result so we can safely
      82     test with -4095.  */
      83  
      84  #undef	PSEUDO
      85  #define	PSEUDO(name, syscall_name, args)		\
      86  	.text;						\
      87    ENTRY (name);						\
      88  	DO_CALL (syscall_name, args);			\
      89  	cmn	r0, $4096;
      90  
      91  #define PSEUDO_RET					\
      92  	it	cc;					\
      93  	RETINSTR(cc, lr);				\
      94  	b	PLTJMP(SYSCALL_ERROR)
      95  #undef ret
      96  #define ret PSEUDO_RET
      97  
      98  #undef	PSEUDO_END
      99  #define	PSEUDO_END(name)				\
     100  	SYSCALL_ERROR_HANDLER;				\
     101    END (name)
     102  
     103  #undef	PSEUDO_NOERRNO
     104  #define	PSEUDO_NOERRNO(name, syscall_name, args)	\
     105  	.text;						\
     106    ENTRY (name);						\
     107  	DO_CALL (syscall_name, args);
     108  
     109  #define PSEUDO_RET_NOERRNO				\
     110  	DO_RET (lr);
     111  
     112  #undef ret_NOERRNO
     113  #define ret_NOERRNO PSEUDO_RET_NOERRNO
     114  
     115  #undef	PSEUDO_END_NOERRNO
     116  #define	PSEUDO_END_NOERRNO(name)			\
     117    END (name)
     118  
     119  /* The function has to return the error code.  */
     120  #undef	PSEUDO_ERRVAL
     121  #define	PSEUDO_ERRVAL(name, syscall_name, args)		\
     122  	.text;						\
     123    ENTRY (name)						\
     124  	DO_CALL (syscall_name, args);			\
     125  	rsb	r0, r0, #0
     126  
     127  #undef	PSEUDO_END_ERRVAL
     128  #define	PSEUDO_END_ERRVAL(name)				\
     129    END (name)
     130  
     131  #define ret_ERRVAL PSEUDO_RET_NOERRNO
     132  
     133  #if !IS_IN (libc)
     134  # define SYSCALL_ERROR __local_syscall_error
     135  # if RTLD_PRIVATE_ERRNO
     136  #  define SYSCALL_ERROR_HANDLER					\
     137  __local_syscall_error:						\
     138  	rsb	r0, r0, #0;					\
     139  	LDST_PCREL(str, r0, r1, C_SYMBOL_NAME(rtld_errno));	\
     140  	mvn	r0, #0;						\
     141  	DO_RET(lr)
     142  # else
     143  #  if defined(__ARM_ARCH_4T__) && defined(__THUMB_INTERWORK__)
     144  #   define POP_PC \
     145    pop { lr }; \
     146    cfi_adjust_cfa_offset (-4); \
     147    cfi_restore (lr); \
     148    bx lr
     149  #  else
     150  #   define POP_PC  pop { pc }
     151  #  endif
     152  #  define SYSCALL_ERROR_HANDLER					\
     153  __local_syscall_error:						\
     154  	push	{ lr };						\
     155  	cfi_adjust_cfa_offset (4);				\
     156  	cfi_rel_offset (lr, 0);					\
     157  	push	{ r0 };	    					\
     158  	cfi_adjust_cfa_offset (4);				\
     159  	bl	PLTJMP(C_SYMBOL_NAME(__errno_location)); 	\
     160  	pop	{ r1 };						\
     161  	cfi_adjust_cfa_offset (-4);				\
     162  	rsb	r1, r1, #0;					\
     163  	str	r1, [r0];					\
     164  	mvn	r0, #0;						\
     165  	POP_PC;
     166  # endif
     167  #else
     168  # define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */
     169  # define SYSCALL_ERROR __syscall_error
     170  #endif
     171  
     172  /* The ARM EABI user interface passes the syscall number in r7, instead
     173     of in the swi.  This is more efficient, because the kernel does not need
     174     to fetch the swi from memory to find out the number; which can be painful
     175     with separate I-cache and D-cache.  Make sure to use 0 for the SWI
     176     argument; otherwise the (optional) compatibility code for APCS binaries
     177     may be invoked.  */
     178  
     179  /* Linux takes system call args in registers:
     180  	arg 1		r0
     181  	arg 2		r1
     182  	arg 3		r2
     183  	arg 4		r3
     184  	arg 5		r4	(this is different from the APCS convention)
     185  	arg 6		r5
     186  	arg 7		r6
     187  
     188     The compiler is going to form a call by coming here, through PSEUDO, with
     189     arguments
     190  	syscall number	in the DO_CALL macro
     191  	arg 1		r0
     192  	arg 2		r1
     193  	arg 3		r2
     194  	arg 4		r3
     195  	arg 5		[sp]
     196  	arg 6		[sp+4]
     197  	arg 7		[sp+8]
     198  
     199     We need to shuffle values between R4..R6 and the stack so that the
     200     caller's v1..v3 and stack frame are not corrupted, and the kernel
     201     sees the right arguments.
     202  
     203  */
     204  
     205  /* We must save and restore r7 (call-saved) for the syscall number.
     206     We never make function calls from inside here (only potentially
     207     signal handlers), so we do not bother with doubleword alignment.
     208  
     209     Just like the APCS syscall convention, the EABI syscall convention uses
     210     r0 through r6 for up to seven syscall arguments.  None are ever passed to
     211     the kernel on the stack, although incoming arguments are on the stack for
     212     syscalls with five or more arguments.
     213  
     214     The assembler will convert the literal pool load to a move for most
     215     syscalls.  */
     216  
     217  #undef	DO_CALL
     218  #define DO_CALL(syscall_name, args)			\
     219  	DOARGS_##args;					\
     220  	ldr	r7, =SYS_ify (syscall_name);		\
     221  	swi	0x0;					\
     222  	UNDOARGS_##args
     223  
     224  #undef  DOARGS_0
     225  #define DOARGS_0					\
     226  	.fnstart;					\
     227  	push	{ r7 };					\
     228  	cfi_adjust_cfa_offset (4);			\
     229  	cfi_rel_offset (r7, 0);				\
     230  	.save	{ r7 }
     231  #undef  DOARGS_1
     232  #define DOARGS_1 DOARGS_0
     233  #undef  DOARGS_2
     234  #define DOARGS_2 DOARGS_0
     235  #undef  DOARGS_3
     236  #define DOARGS_3 DOARGS_0
     237  #undef  DOARGS_4
     238  #define DOARGS_4 DOARGS_0
     239  #undef  DOARGS_5
     240  #define DOARGS_5					\
     241  	.fnstart;					\
     242  	push	{r4, r7};				\
     243  	cfi_adjust_cfa_offset (8);			\
     244  	cfi_rel_offset (r4, 0);				\
     245  	cfi_rel_offset (r7, 4);				\
     246  	.save	{ r4, r7 };				\
     247  	ldr	r4, [sp, #8]
     248  #undef  DOARGS_6
     249  #define DOARGS_6					\
     250  	.fnstart;					\
     251  	mov	ip, sp;					\
     252  	push	{r4, r5, r7};				\
     253  	cfi_adjust_cfa_offset (12);			\
     254  	cfi_rel_offset (r4, 0);				\
     255  	cfi_rel_offset (r5, 4);				\
     256  	cfi_rel_offset (r7, 8);				\
     257  	.save	{ r4, r5, r7 };				\
     258  	ldmia	ip, {r4, r5}
     259  #undef  DOARGS_7
     260  #define DOARGS_7					\
     261  	.fnstart;					\
     262  	mov	ip, sp;					\
     263  	push	{r4, r5, r6, r7};			\
     264  	cfi_adjust_cfa_offset (16);			\
     265  	cfi_rel_offset (r4, 0);				\
     266  	cfi_rel_offset (r5, 4);				\
     267  	cfi_rel_offset (r6, 8);				\
     268  	cfi_rel_offset (r7, 12);			\
     269  	.save	{ r4, r5, r6, r7 };			\
     270  	ldmia	ip, {r4, r5, r6}
     271  
     272  #undef  UNDOARGS_0
     273  #define UNDOARGS_0					\
     274  	pop	{r7};					\
     275  	cfi_adjust_cfa_offset (-4);			\
     276  	cfi_restore (r7);				\
     277  	.fnend
     278  #undef  UNDOARGS_1
     279  #define UNDOARGS_1 UNDOARGS_0
     280  #undef  UNDOARGS_2
     281  #define UNDOARGS_2 UNDOARGS_0
     282  #undef  UNDOARGS_3
     283  #define UNDOARGS_3 UNDOARGS_0
     284  #undef  UNDOARGS_4
     285  #define UNDOARGS_4 UNDOARGS_0
     286  #undef  UNDOARGS_5
     287  #define UNDOARGS_5					\
     288  	pop	{r4, r7};				\
     289  	cfi_adjust_cfa_offset (-8);			\
     290  	cfi_restore (r4);				\
     291  	cfi_restore (r7);				\
     292  	.fnend
     293  #undef  UNDOARGS_6
     294  #define UNDOARGS_6					\
     295  	pop	{r4, r5, r7};				\
     296  	cfi_adjust_cfa_offset (-12);			\
     297  	cfi_restore (r4);				\
     298  	cfi_restore (r5);				\
     299  	cfi_restore (r7);				\
     300  	.fnend
     301  #undef  UNDOARGS_7
     302  #define UNDOARGS_7					\
     303  	pop	{r4, r5, r6, r7};			\
     304  	cfi_adjust_cfa_offset (-16);			\
     305  	cfi_restore (r4);				\
     306  	cfi_restore (r5);				\
     307  	cfi_restore (r6);				\
     308  	cfi_restore (r7);				\
     309  	.fnend
     310  
     311  #else /* not __ASSEMBLER__ */
     312  
     313  #if defined(__thumb__)
     314  /* We can not expose the use of r7 to the compiler.  GCC (as
     315     of 4.5) uses r7 as the hard frame pointer for Thumb - although
     316     for Thumb-2 it isn't obviously a better choice than r11.
     317     And GCC does not support asms that conflict with the frame
     318     pointer.
     319  
     320     This would be easier if syscall numbers never exceeded 255,
     321     but they do.  For the moment the LOAD_ARGS_7 is sacrificed.
     322     We can't use push/pop inside the asm because that breaks
     323     unwinding (i.e. thread cancellation) for this frame.  We can't
     324     locally save and restore r7, because we do not know if this
     325     function uses r7 or if it is our caller's r7; if it is our caller's,
     326     then unwinding will fail higher up the stack.  So we move the
     327     syscall out of line and provide its own unwind information.  */
     328  # undef INTERNAL_SYSCALL_RAW
     329  # define INTERNAL_SYSCALL_RAW(name, nr, args...)		\
     330    ({								\
     331        register int _a1 asm ("a1");				\
     332        int _nametmp = name;					\
     333        LOAD_ARGS_##nr (args)					\
     334        register int _name asm ("ip") = _nametmp;			\
     335        asm volatile ("bl      __libc_do_syscall"			\
     336                      : "=r" (_a1)				\
     337                      : "r" (_name) ASM_ARGS_##nr			\
     338                      : "memory", "lr");				\
     339        _a1; })
     340  #else /* ARM */
     341  # undef INTERNAL_SYSCALL_RAW
     342  # define INTERNAL_SYSCALL_RAW(name, nr, args...)		\
     343    ({								\
     344         register int _a1 asm ("r0"), _nr asm ("r7");		\
     345         LOAD_ARGS_##nr (args)					\
     346         _nr = name;						\
     347         asm volatile ("swi	0x0	@ syscall " #name	\
     348  		     : "=r" (_a1)				\
     349  		     : "r" (_nr) ASM_ARGS_##nr			\
     350  		     : "memory");				\
     351         _a1; })
     352  #endif
     353  
     354  #undef INTERNAL_SYSCALL
     355  #define INTERNAL_SYSCALL(name, nr, args...)			\
     356  	INTERNAL_SYSCALL_RAW(SYS_ify(name), nr, args)
     357  
     358  #define VDSO_NAME  "LINUX_2.6"
     359  #define VDSO_HASH  61765110
     360  
     361  /* List of system calls which are supported as vsyscalls.  */
     362  #define HAVE_CLOCK_GETTIME_VSYSCALL	"__vdso_clock_gettime"
     363  #define HAVE_CLOCK_GETTIME64_VSYSCALL	"__vdso_clock_gettime64"
     364  #define HAVE_GETTIMEOFDAY_VSYSCALL	"__vdso_gettimeofday"
     365  
     366  #define LOAD_ARGS_0()
     367  #define ASM_ARGS_0
     368  #define LOAD_ARGS_1(a1)				\
     369    int _a1tmp = (int) (a1);			\
     370    LOAD_ARGS_0 ()				\
     371    _a1 = _a1tmp;
     372  #define ASM_ARGS_1	ASM_ARGS_0, "r" (_a1)
     373  #define LOAD_ARGS_2(a1, a2)			\
     374    int _a2tmp = (int) (a2);			\
     375    LOAD_ARGS_1 (a1)				\
     376    register int _a2 asm ("a2") = _a2tmp;
     377  #define ASM_ARGS_2	ASM_ARGS_1, "r" (_a2)
     378  #define LOAD_ARGS_3(a1, a2, a3)			\
     379    int _a3tmp = (int) (a3);			\
     380    LOAD_ARGS_2 (a1, a2)				\
     381    register int _a3 asm ("a3") = _a3tmp;
     382  #define ASM_ARGS_3	ASM_ARGS_2, "r" (_a3)
     383  #define LOAD_ARGS_4(a1, a2, a3, a4)		\
     384    int _a4tmp = (int) (a4);			\
     385    LOAD_ARGS_3 (a1, a2, a3)			\
     386    register int _a4 asm ("a4") = _a4tmp;
     387  #define ASM_ARGS_4	ASM_ARGS_3, "r" (_a4)
     388  #define LOAD_ARGS_5(a1, a2, a3, a4, a5)		\
     389    int _v1tmp = (int) (a5);			\
     390    LOAD_ARGS_4 (a1, a2, a3, a4)			\
     391    register int _v1 asm ("v1") = _v1tmp;
     392  #define ASM_ARGS_5	ASM_ARGS_4, "r" (_v1)
     393  #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)	\
     394    int _v2tmp = (int) (a6);			\
     395    LOAD_ARGS_5 (a1, a2, a3, a4, a5)		\
     396    register int _v2 asm ("v2") = _v2tmp;
     397  #define ASM_ARGS_6	ASM_ARGS_5, "r" (_v2)
     398  #ifndef __thumb__
     399  # define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7)	\
     400    int _v3tmp = (int) (a7);				\
     401    LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6)			\
     402    register int _v3 asm ("v3") = _v3tmp;
     403  # define ASM_ARGS_7	ASM_ARGS_6, "r" (_v3)
     404  #endif
     405  
     406  /* For EABI, non-constant syscalls are actually pretty easy...  */
     407  #undef INTERNAL_SYSCALL_NCS
     408  #define INTERNAL_SYSCALL_NCS(number, nr, args...)              \
     409    INTERNAL_SYSCALL_RAW (number, nr, args)
     410  
     411  #endif	/* __ASSEMBLER__ */
     412  
     413  #endif /* linux/arm/sysdep.h */