1 /* Copyright (C) 1996-2021 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 savely 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 /* Pointer mangling is not yet supported for M68K.  */
299 #define PTR_MANGLE(var) (void) (var)
300 #define PTR_DEMANGLE(var) (void) (var)
301 
302 #if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
303 /* M68K needs system-supplied DSO to access TLS helpers
304    even when statically linked.  */
305 # define NEED_STATIC_SYSINFO_DSO 1
306 #endif
307