1 /* Copyright (C) 1992-2022 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_SH_SYSDEP_H 19 #define _LINUX_SH_SYSDEP_H 1 20 21 /* There is some commonality. */ 22 #include <sysdeps/unix/sysv/linux/sysdep.h> 23 #include <sysdeps/unix/sh/sysdep.h> 24 #include <tls.h> 25 26 /* For Linux we can use the system call table in the header file 27 /usr/include/asm/unistd.h 28 of the kernel. But these symbols do not follow the SYS_* syntax 29 so we have to redefine the `SYS_ify' macro here. */ 30 #undef SYS_ify 31 #define SYS_ify(syscall_name) (__NR_##syscall_name) 32 33 34 #ifdef __ASSEMBLER__ 35 36 /* Linux uses a negative return value to indicate syscall errors, 37 unlike most Unices, which use the condition codes' carry flag. 38 39 Since version 2.1 the return value of a system call might be 40 negative even if the call succeeded. E.g., the `lseek' system call 41 might return a large offset. Therefore we must not anymore test 42 for < 0, but test for a real error by making sure the value in R0 43 is a real error number. Linus said he will make sure the no syscall 44 returns a value in -1 .. -4095 as a valid result so we can savely 45 test with -4095. */ 46 47 #define _IMM1 #-1 48 #define _IMM12 #-12 49 #undef PSEUDO 50 #define PSEUDO(name, syscall_name, args) \ 51 .text; \ 52 ENTRY (name); \ 53 DO_CALL (syscall_name, args); \ 54 mov r0,r1; \ 55 mov _IMM12,r2; \ 56 shad r2,r1; \ 57 not r1,r1; \ 58 tst r1,r1; \ 59 bf .Lpseudo_end; \ 60 SYSCALL_ERROR_HANDLER; \ 61 .Lpseudo_end: 62 63 #undef PSEUDO_END 64 #define PSEUDO_END(name) \ 65 END (name) 66 67 #undef PSEUDO_NOERRNO 68 #define PSEUDO_NOERRNO(name, syscall_name, args) \ 69 .text; \ 70 ENTRY (name); \ 71 DO_CALL (syscall_name, args) 72 73 #undef PSEUDO_END_NOERRNO 74 #define PSEUDO_END_NOERRNO(name) \ 75 END (name) 76 77 #define ret_NOERRNO ret 78 79 #define PSEUDO_ERRVAL(name, syscall_name, args) \ 80 .text; \ 81 ENTRY (name); \ 82 DO_CALL (syscall_name, args); 83 84 #undef PSEUDO_END_ERRVAL 85 #define PSEUDO_END_ERRVAL(name) \ 86 END (name) 87 88 #define ret_ERRVAL ret 89 90 #ifndef PIC 91 # define SYSCALL_ERROR_HANDLER \ 92 mov.l 0f,r1; \ 93 jmp @r1; \ 94 mov r0,r4; \ 95 .align 2; \ 96 0: .long __syscall_error 97 #else 98 # if RTLD_PRIVATE_ERRNO 99 # define SYSCALL_ERROR_HANDLER \ 100 neg r0,r1; \ 101 mov r12,r2; \ 102 cfi_register (r12, r2); \ 103 mov.l 0f,r12; \ 104 mova 0f,r0; \ 105 add r0,r12; \ 106 mov.l 1f,r0; \ 107 mov.l r1,@(r0,r12); \ 108 mov r2,r12; \ 109 cfi_restore (r12); \ 110 bra .Lpseudo_end; \ 111 mov _IMM1,r0; \ 112 .align 2; \ 113 0: .long _GLOBAL_OFFSET_TABLE_; \ 114 1: .long rtld_errno@GOTOFF 115 116 # elif defined _LIBC_REENTRANT 117 118 # if IS_IN (libc) 119 # define SYSCALL_ERROR_ERRNO __libc_errno 120 # else 121 # define SYSCALL_ERROR_ERRNO errno 122 # endif 123 # define SYSCALL_ERROR_HANDLER \ 124 neg r0,r1; \ 125 mov r12,r2; \ 126 cfi_register (r12, r2); \ 127 mov.l 0f,r12; \ 128 mova 0f,r0; \ 129 add r0,r12; \ 130 mov.l 1f,r0; \ 131 stc gbr, r4; \ 132 mov.l @(r0,r12),r0; \ 133 mov r2,r12; \ 134 cfi_restore (r12); \ 135 add r4,r0; \ 136 mov.l r1,@r0; \ 137 bra .Lpseudo_end; \ 138 mov _IMM1,r0; \ 139 .align 2; \ 140 0: .long _GLOBAL_OFFSET_TABLE_; \ 141 1: .long SYSCALL_ERROR_ERRNO@GOTTPOFF 142 # else 143 /* Store (-r0) into errno through the GOT. */ 144 # define SYSCALL_ERROR_HANDLER \ 145 neg r0,r1; \ 146 mov r12,r2; \ 147 cfi_register (r12, r2); \ 148 mov.l 0f,r12; \ 149 mova 0f,r0; \ 150 add r0,r12; \ 151 mov.l 1f,r0; \ 152 mov.l @(r0,r12),r0; \ 153 mov r2,r12; \ 154 cfi_restore (r12); \ 155 mov.l r1,@r0; \ 156 bra .Lpseudo_end; \ 157 mov _IMM1,r0; \ 158 .align 2; \ 159 0: .long _GLOBAL_OFFSET_TABLE_; \ 160 1: .long errno@GOT 161 # endif /* _LIBC_REENTRANT */ 162 #endif /* PIC */ 163 164 # ifdef NEED_SYSCALL_INST_PAD 165 # define SYSCALL_INST_PAD \ 166 or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0 167 # else 168 # define SYSCALL_INST_PAD 169 # endif 170 171 #define SYSCALL_INST0 trapa #0x10 172 #define SYSCALL_INST1 trapa #0x11 173 #define SYSCALL_INST2 trapa #0x12 174 #define SYSCALL_INST3 trapa #0x13 175 #define SYSCALL_INST4 trapa #0x14 176 #define SYSCALL_INST5 mov.l @(0,r15),r0; trapa #0x15 177 #define SYSCALL_INST6 mov.l @(0,r15),r0; mov.l @(4,r15),r1; trapa #0x16 178 179 #undef DO_CALL 180 #define DO_CALL(syscall_name, args) \ 181 mov.l 1f,r3; \ 182 SYSCALL_INST##args; \ 183 SYSCALL_INST_PAD; \ 184 bra 2f; \ 185 nop; \ 186 .align 2; \ 187 1: .long SYS_ify (syscall_name); \ 188 2: 189 190 #else /* not __ASSEMBLER__ */ 191 192 #define SYSCALL_INST_STR0 "trapa #0x10\n\t" 193 #define SYSCALL_INST_STR1 "trapa #0x11\n\t" 194 #define SYSCALL_INST_STR2 "trapa #0x12\n\t" 195 #define SYSCALL_INST_STR3 "trapa #0x13\n\t" 196 #define SYSCALL_INST_STR4 "trapa #0x14\n\t" 197 #define SYSCALL_INST_STR5 "trapa #0x15\n\t" 198 #define SYSCALL_INST_STR6 "trapa #0x16\n\t" 199 200 # ifdef NEED_SYSCALL_INST_PAD 201 # define SYSCALL_INST_PAD "\ 202 or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0" 203 # else 204 # define SYSCALL_INST_PAD 205 # endif 206 207 #define ASMFMT_0 208 #define ASMFMT_1 \ 209 , "r" (r4) 210 #define ASMFMT_2 \ 211 , "r" (r4), "r" (r5) 212 #define ASMFMT_3 \ 213 , "r" (r4), "r" (r5), "r" (r6) 214 #define ASMFMT_4 \ 215 , "r" (r4), "r" (r5), "r" (r6), "r" (r7) 216 #define ASMFMT_5 \ 217 , "r" (r4), "r" (r5), "r" (r6), "r" (r7), "0" (r0) 218 #define ASMFMT_6 \ 219 , "r" (r4), "r" (r5), "r" (r6), "r" (r7), "0" (r0), "r" (r1) 220 #define ASMFMT_7 \ 221 , "r" (r4), "r" (r5), "r" (r6), "r" (r7), "0" (r0), "r" (r1), "r" (r2) 222 223 #define SUBSTITUTE_ARGS_0() 224 #define SUBSTITUTE_ARGS_1(arg1) \ 225 long int _arg1 = (long int) (arg1); \ 226 register long int r4 asm ("%r4") = (long int) (_arg1) 227 #define SUBSTITUTE_ARGS_2(arg1, arg2) \ 228 long int _arg1 = (long int) (arg1); \ 229 long int _arg2 = (long int) (arg2); \ 230 register long int r4 asm ("%r4") = (long int) (_arg1); \ 231 register long int r5 asm ("%r5") = (long int) (_arg2) 232 #define SUBSTITUTE_ARGS_3(arg1, arg2, arg3) \ 233 long int _arg1 = (long int) (arg1); \ 234 long int _arg2 = (long int) (arg2); \ 235 long int _arg3 = (long int) (arg3); \ 236 register long int r4 asm ("%r4") = (long int) (_arg1); \ 237 register long int r5 asm ("%r5") = (long int) (_arg2); \ 238 register long int r6 asm ("%r6") = (long int) (_arg3) 239 #define SUBSTITUTE_ARGS_4(arg1, arg2, arg3, arg4) \ 240 long int _arg1 = (long int) (arg1); \ 241 long int _arg2 = (long int) (arg2); \ 242 long int _arg3 = (long int) (arg3); \ 243 long int _arg4 = (long int) (arg4); \ 244 register long int r4 asm ("%r4") = (long int) (_arg1); \ 245 register long int r5 asm ("%r5") = (long int) (_arg2); \ 246 register long int r6 asm ("%r6") = (long int) (_arg3); \ 247 register long int r7 asm ("%r7") = (long int) (_arg4) 248 #define SUBSTITUTE_ARGS_5(arg1, arg2, arg3, arg4, arg5) \ 249 long int _arg1 = (long int) (arg1); \ 250 long int _arg2 = (long int) (arg2); \ 251 long int _arg3 = (long int) (arg3); \ 252 long int _arg4 = (long int) (arg4); \ 253 long int _arg5 = (long int) (arg5); \ 254 register long int r4 asm ("%r4") = (long int) (_arg1); \ 255 register long int r5 asm ("%r5") = (long int) (_arg2); \ 256 register long int r6 asm ("%r6") = (long int) (_arg3); \ 257 register long int r7 asm ("%r7") = (long int) (_arg4); \ 258 register long int r0 asm ("%r0") = (long int) (_arg5) 259 #define SUBSTITUTE_ARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ 260 long int _arg1 = (long int) (arg1); \ 261 long int _arg2 = (long int) (arg2); \ 262 long int _arg3 = (long int) (arg3); \ 263 long int _arg4 = (long int) (arg4); \ 264 long int _arg5 = (long int) (arg5); \ 265 long int _arg6 = (long int) (arg6); \ 266 register long int r4 asm ("%r4") = (long int)(_arg1); \ 267 register long int r5 asm ("%r5") = (long int) (_arg2); \ 268 register long int r6 asm ("%r6") = (long int) (_arg3); \ 269 register long int r7 asm ("%r7") = (long int) (_arg4); \ 270 register long int r0 asm ("%r0") = (long int) (_arg5); \ 271 register long int r1 asm ("%r1") = (long int) (_arg6) 272 #define SUBSTITUTE_ARGS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 273 long int _arg1 = (long int) (arg1); \ 274 long int _arg2 = (long int) (arg2); \ 275 long int _arg3 = (long int) (arg3); \ 276 long int _arg4 = (long int) (arg4); \ 277 long int _arg5 = (long int) (arg5); \ 278 long int _arg6 = (long int) (arg6); \ 279 long int _arg7 = (long int) (arg7); \ 280 register long int r4 asm ("%r4") = (long int) (_arg1); \ 281 register long int r5 asm ("%r5") = (long int) (_arg2); \ 282 register long int r6 asm ("%r6") = (long int) (_arg3); \ 283 register long int r7 asm ("%r7") = (long int) (_arg4); \ 284 register long int r0 asm ("%r0") = (long int) (_arg5); \ 285 register long int r1 asm ("%r1") = (long int) (_arg6); \ 286 register long int r2 asm ("%r2") = (long int) (_arg7) 287 288 #undef INTERNAL_SYSCALL 289 #define INTERNAL_SYSCALL(name, nr, args...) \ 290 ({ \ 291 unsigned long int resultvar; \ 292 register long int r3 asm ("%r3") = SYS_ify (name); \ 293 SUBSTITUTE_ARGS_##nr(args); \ 294 \ 295 asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD \ 296 : "=z" (resultvar) \ 297 : "r" (r3) ASMFMT_##nr \ 298 : "memory", "t"); \ 299 \ 300 (int) resultvar; }) 301 302 /* The _NCS variant allows non-constant syscall numbers. */ 303 #define INTERNAL_SYSCALL_NCS(name, nr, args...) \ 304 ({ \ 305 unsigned long int resultvar; \ 306 register long int r3 asm ("%r3") = (name); \ 307 SUBSTITUTE_ARGS_##nr(args); \ 308 \ 309 asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD \ 310 : "=z" (resultvar) \ 311 : "r" (r3) ASMFMT_##nr \ 312 : "memory", "t"); \ 313 \ 314 (int) resultvar; }) 315 316 #endif /* __ASSEMBLER__ */ 317 318 /* Pointer mangling support. */ 319 #if IS_IN (rtld) 320 /* We cannot use the thread descriptor because in ld.so we use setjmp 321 earlier than the descriptor is initialized. Using a global variable 322 is too complicated here since we have no PC-relative addressing mode. */ 323 #else 324 # ifdef __ASSEMBLER__ 325 # define PTR_MANGLE(reg, tmp) \ 326 stc gbr,tmp; mov.l @(POINTER_GUARD,tmp),tmp; xor tmp,reg 327 # define PTR_MANGLE2(reg, tmp) xor tmp,reg 328 # define PTR_DEMANGLE(reg, tmp) PTR_MANGLE (reg, tmp) 329 # define PTR_DEMANGLE2(reg, tmp) PTR_MANGLE2 (reg, tmp) 330 # else 331 # define PTR_MANGLE(var) \ 332 (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ()) 333 # define PTR_DEMANGLE(var) PTR_MANGLE (var) 334 # endif 335 #endif 336 337 #endif /* linux/sh/sysdep.h */ 338