1 /* Assembly macros for C-SKY. 2 Copyright (C) 2018-2022 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_CSKY_SYSDEP_H 20 #define _LINUX_CSKY_SYSDEP_H 1 21 22 /* There is some commonality. */ 23 #include <sysdeps/unix/sysv/linux/generic/sysdep.h> 24 #include <sysdeps/unix/sysv/linux/sysdep.h> 25 #include <sysdeps/csky/sysdep.h> 26 27 /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */ 28 #include <dl-sysdep.h> 29 30 #include <tls.h> 31 32 /* In order to get __set_errno() definition in INLINE_SYSCALL. */ 33 #ifndef __ASSEMBLER__ 34 # include <errno.h> 35 #endif 36 37 #undef SYS_ify 38 #define SYS_ify(syscall_name) (__NR_##syscall_name) 39 40 #ifdef __ASSEMBLER__ 41 /* Linux uses a negative return value to indicate syscall errors, 42 unlike most Unices, which use the condition codes' carry flag. 43 44 Since version 2.1 the return value of a system call might be 45 negative even if the call succeeded. E.g., the `lseek' system call 46 might return a large offset. Therefore we must not anymore test 47 for < 0, but test for a real error by making sure the value in R0 48 is a real error number. Linus said he will make sure the no syscall 49 returns a value in -1 .. -4095 as a valid result so we can safely 50 test with -4095. */ 51 52 # undef PSEUDO 53 # define PSEUDO(name, syscall_name, args) \ 54 .text; \ 55 ENTRY (name); \ 56 DO_CALL (syscall_name, args); 57 58 # define GETGB \ 59 grs t0, .Lgetpc; \ 60 .Lgetpc: \ 61 lrw gb, .Lgetpc@GOTPC; \ 62 addu gb, t0; 63 64 # if IS_IN (libc) 65 # ifdef __PIC__ 66 # define PSEUDO_RET \ 67 btsti a0, 31; \ 68 bf 1f; \ 69 subi sp, 8; \ 70 st.w lr, (sp); \ 71 st.w gb, (sp, 4); \ 72 GETGB; \ 73 lrw a2, SYSCALL_ERROR@PLT; \ 74 add a2, gb; \ 75 ld.w a2, (a2); \ 76 jsr a2; \ 77 ld.w lr, (sp); \ 78 ld.w gb, (sp, 4); \ 79 addi sp, 8; \ 80 1: \ 81 rts 82 # else 83 # define PSEUDO_RET \ 84 btsti a0, 31; \ 85 bf 1f; \ 86 jmpi SYSCALL_ERROR; \ 87 1: \ 88 rts 89 # endif 90 # else 91 # ifdef __PIC__ 92 # define PSEUDO_RET \ 93 btsti a0, 31; \ 94 bf 1f; \ 95 subi sp, 8; \ 96 st.w lr, (sp); \ 97 st.w gb, (sp, 4); \ 98 GETGB; \ 99 bsr SYSCALL_ERROR; \ 100 ld.w lr, (sp); \ 101 ld.w gb, (sp, 4); \ 102 addi sp, 8; \ 103 1: \ 104 rts 105 # else 106 # define PSEUDO_RET \ 107 btsti a0, 31; \ 108 bt SYSCALL_ERROR; \ 109 rts 110 # endif 111 # endif 112 113 # undef ret 114 # define ret PSEUDO_RET 115 116 # undef PSEUDO_END 117 # define PSEUDO_END(name) \ 118 .align 4; \ 119 SYSCALL_ERROR_HANDLER; \ 120 END (name) 121 122 # undef PSEUDO_NOERRNO 123 # define PSEUDO_NOERRNO(name, syscall_name, args) \ 124 .text; \ 125 ENTRY (name); \ 126 DO_CALL (syscall_name, args) 127 128 # define PSEUDO_RET_NOERRNO rts 129 130 # undef ret_NOERRNO 131 # define ret_NOERRNO PSEUDO_RET_NOERRNO 132 133 # undef PSEUDO_END_NOERRNO 134 # define PSEUDO_END_NOERRNO(name) END (name) 135 136 /* The function has to return the error code. */ 137 # undef PSEUDO_ERRVAL 138 # define PSEUDO_ERRVAL(name, syscall_name, args) \ 139 .text; \ 140 ENTRY (name) \ 141 DO_CALL (syscall_name, args); \ 142 not a0; \ 143 addi a0, 1 144 145 # undef PSEUDO_END_ERRVAL 146 # define PSEUDO_END_ERRVAL(name) END (name) 147 148 # define ret_ERRVAL rts 149 150 # if !IS_IN (libc) 151 # define SYSCALL_ERROR __local_syscall_error 152 # if RTLD_PRIVATE_ERRNO 153 # ifdef __PIC__ 154 # define SYSCALL_ERROR_HANDLER \ 155 __local_syscall_error: \ 156 lrw a1, rtld_errno@PLT; \ 157 addu a1, gb; \ 158 ldw a1, (a1); \ 159 rsubi a0, 0; \ 160 stw a0, (a1); \ 161 bmaski a0, 0; \ 162 rts 163 # else /* __PIC__ */ 164 # define SYSCALL_ERROR_HANDLER \ 165 __local_syscall_error: \ 166 lrw a1, rtld_errno; \ 167 rsubi a0, 0; \ 168 stw a0, (a1); \ 169 bmaski a0, 0; \ 170 rts 171 # endif /* __PIC__ */ 172 # else /* !RTLD_PRIVATE_ERRNO */ 173 # ifdef __PIC__ 174 # define SYSCALL_ERROR_HANDLER \ 175 __local_syscall_error: \ 176 subi sp, 8; \ 177 stw a0, (sp, 0); \ 178 stw r15, (sp, 4); \ 179 lrw a1, __errno_location@PLT; \ 180 add a1, gb; \ 181 ldw a1, (a1); \ 182 jsr a1; \ 183 ldw a1, (sp, 0); /* load errno*/ \ 184 ldw r15, (sp, 4); \ 185 addi sp, 8; \ 186 movi a2, 0; \ 187 rsub a1, a1, a2; \ 188 stw a1, (a0); \ 189 bmaski a0, 0; \ 190 rts 191 # else 192 # define SYSCALL_ERROR_HANDLER \ 193 __local_syscall_error: \ 194 subi sp, 8; \ 195 stw a0, (sp, 0); \ 196 stw r15, (sp, 4); \ 197 lrw a1, __errno_location; \ 198 jsr a1; \ 199 ldw a1, (sp, 0); /* load errno */ \ 200 ldw r15, (sp, 4); \ 201 addi sp, 8; \ 202 movi a2, 0; \ 203 rsub a1, a1, a2; \ 204 stw a1, (a0); \ 205 bmaski a0, 0; \ 206 rts 207 # endif /* __PIC__ */ 208 # endif/* RTLD_PRIVATE_ERROR */ 209 # else 210 # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ 211 # define SYSCALL_ERROR __syscall_error 212 # endif/* IS_IN (libc) */ 213 214 /* define DO_CALL */ 215 # undef DO_CALL 216 # define DO_CALL(syscall_name, args) \ 217 DOARGS_##args; \ 218 lrw r7, SYS_ify(syscall_name); \ 219 trap 0; \ 220 UNDOARGS_##args 221 222 # undef DOARGS_0 223 # define DOARGS_0 \ 224 subi sp, 8; \ 225 cfi_adjust_cfa_offset (8); \ 226 stw r7, (sp, 0); \ 227 cfi_rel_offset (r7, 0); 228 229 # undef DOARGS_1 230 # define DOARGS_1 DOARGS_0 231 # undef DOARGS_2 232 # define DOARGS_2 DOARGS_0 233 # undef DOARGS_3 234 # define DOARGS_3 DOARGS_0 235 # undef DOARGS_4 236 # define DOARGS_4 DOARGS_0 237 # undef DOARGS_5 238 # define DOARGS_5 \ 239 subi sp, 8; \ 240 cfi_adjust_cfa_offset (8); \ 241 stw r7, (sp, 0); \ 242 cfi_rel_offset (7, 0); \ 243 stw r4, (sp, 4); \ 244 cfi_rel_offset (4, 4); \ 245 ldw r4, (sp, 8) 246 # undef DOARGS_6 247 # define DOARGS_6 \ 248 subi sp, 16; \ 249 cfi_adjust_cfa_offset (16); \ 250 stw r7, (sp, 0); \ 251 cfi_rel_offset (7, 0); \ 252 stw r4, (sp, 4); \ 253 cfi_rel_offset (4, 4); \ 254 stw r5, (sp, 8); \ 255 cfi_rel_offset (5, 8); \ 256 ldw r4, (sp, 16); \ 257 ldw r5, (sp, 20) 258 259 # undef UNDOARGS_0 260 # define UNDOARGS_0 \ 261 ldw r7, (sp, 0); \ 262 cfi_restore (r7); \ 263 addi sp, 8; \ 264 cfi_adjust_cfa_offset (-8); 265 266 # undef UNDOARGS_1 267 # define UNDOARGS_1 UNDOARGS_0 268 # undef UNDOARGS_2 269 # define UNDOARGS_2 UNDOARGS_0 270 # undef UNDOARGS_3 271 # define UNDOARGS_3 UNDOARGS_0 272 # undef UNDOARGS_4 273 # define UNDOARGS_4 UNDOARGS_0 274 # undef UNDOARGS_5 275 # define UNDOARGS_5 \ 276 ldw r7, (sp, 0); \ 277 cfi_restore (r4); \ 278 ldw r4, (sp, 4); \ 279 cfi_restore (r4); \ 280 addi sp, 8; \ 281 cfi_adjust_cfa_offset (-8); 282 283 # undef UNDOARGS_6 284 # define UNDOARGS_6 \ 285 ldw r7, (sp, 0); \ 286 cfi_restore (r7); \ 287 ldw r4, (sp, 4); \ 288 cfi_restore (r4); \ 289 ldw r5, (sp, 8); \ 290 cfi_restore (r5); \ 291 addi sp, 16; \ 292 cfi_adjust_cfa_offset (-16); 293 294 #else /* not __ASSEMBLER__ */ 295 296 # undef INTERNAL_SYSCALL_RAW 297 # define INTERNAL_SYSCALL_RAW0(name, dummy...) \ 298 ({unsigned int __sys_result; \ 299 { \ 300 register int _a1 __asm__ ("a0"), _nr __asm__ ("r7"); \ 301 _nr = name; \ 302 __asm__ __volatile__ ("trap 0 \n\t" \ 303 : "=r" (_a1) \ 304 : "r" (_nr) \ 305 : "memory"); \ 306 __sys_result = _a1; \ 307 } \ 308 (int) __sys_result; }) 309 310 # define INTERNAL_SYSCALL_RAW1(name, arg1) \ 311 ({unsigned int __sys_result; \ 312 register int _tmp_arg1 = (int)(arg1); \ 313 { \ 314 register int _a1 __asm__ ("a0"), _nr __asm__ ("r7"); \ 315 _a1 = _tmp_arg1; \ 316 _nr = name; \ 317 __asm__ __volatile__ ("trap 0 \n\t" \ 318 : "=r" (_a1) \ 319 : "r" (_nr), "r" (_a1) \ 320 : "memory"); \ 321 __sys_result = _a1; \ 322 } \ 323 (int) __sys_result; }) 324 325 # define INTERNAL_SYSCALL_RAW2(name, arg1, arg2) \ 326 ({unsigned int __sys_result; \ 327 register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ 328 { \ 329 register int _nr __asm__ ("r7"); \ 330 register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ 331 _a1 = _tmp_arg1, _a2 = _tmp_arg2; \ 332 _nr = name; \ 333 __asm__ __volatile__ ("trap 0 \n\t" \ 334 : "=r" (_a1) \ 335 : "r" (_nr), "r" (_a1), "r" (_a2) \ 336 : "memory"); \ 337 __sys_result = _a1; \ 338 } \ 339 (int) __sys_result; }) 340 341 # define INTERNAL_SYSCALL_RAW3(name, arg1, arg2, arg3) \ 342 ({unsigned int __sys_result; \ 343 register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ 344 register int _tmp_arg3 = (int)(arg3); \ 345 { \ 346 register int _nr __asm__ ("r7"); \ 347 register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ 348 register int _a3 __asm__ ("a2"); \ 349 _a1 = _tmp_arg1; \ 350 _a2 = _tmp_arg2; \ 351 _a3 = _tmp_arg3; \ 352 _nr = name; \ 353 __asm__ __volatile__ ("trap 0 \n\t" \ 354 : "=r" (_a1) \ 355 : "r" (_nr), "r" (_a1), "r" (_a2), \ 356 "r" (_a3) \ 357 : "memory"); \ 358 __sys_result = _a1; \ 359 } \ 360 (int) __sys_result; }) 361 362 # define INTERNAL_SYSCALL_RAW4(name, arg1, arg2, arg3, arg4) \ 363 ({unsigned int __sys_result; \ 364 register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ 365 register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ 366 { \ 367 register int _nr __asm__ ("r7"); \ 368 register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ 369 register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ 370 _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ 371 _a4 = _tmp_arg4; \ 372 _nr = name; \ 373 __asm__ __volatile__ ("trap 0 \n\t" \ 374 : "=r" (_a1) \ 375 : "r" (_nr), "r" (_a1), "r" (_a2), \ 376 "r" (_a3), "r" (_a4) \ 377 : "memory"); \ 378 __sys_result = _a1; \ 379 } \ 380 (int) __sys_result; }) 381 382 # define INTERNAL_SYSCALL_RAW5(name, arg1, arg2, arg3, arg4, \ 383 arg5) \ 384 ({unsigned int __sys_result; \ 385 register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ 386 register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ 387 register int _tmp_arg5 = (int)(arg5); \ 388 { \ 389 register int _nr __asm__ ("r7"); \ 390 register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ 391 register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ 392 register int _a5 __asm__ ("r4"); \ 393 _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ 394 _a4 = _tmp_arg4, _a5 = _tmp_arg5; \ 395 _nr = name; \ 396 __asm__ __volatile__ ("trap 0 \n\t" \ 397 : "=r" (_a1) \ 398 : "r" (_nr), "r" (_a1), "r" (_a2), \ 399 "r" (_a3), "r" (_a4), "r" (_a5) \ 400 : "memory"); \ 401 __sys_result = _a1; \ 402 } \ 403 (int) __sys_result; }) 404 405 # define INTERNAL_SYSCALL_RAW6(name, arg1, arg2, arg3, arg4, \ 406 arg5, arg6) \ 407 ({unsigned int __sys_result; \ 408 register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ 409 register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ 410 register int _tmp_arg5 = (int)(arg5), _tmp_arg6 = (int)(arg6); \ 411 { \ 412 register int _nr __asm__ ("r7"); \ 413 register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ 414 register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ 415 register int _a5 __asm__ ("r4"), _a6 __asm__ ("r5"); \ 416 _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ 417 _a4 = _tmp_arg4, _a5 = _tmp_arg5, _a6 = _tmp_arg6; \ 418 _nr = name; \ 419 __asm__ __volatile__ ("trap 0 \n\t" \ 420 : "=r" (_a1) \ 421 : "r" (_nr), "r" (_a1), "r" (_a2), \ 422 "r" (_a3), "r" (_a4), "r" (_a5), \ 423 "r" (_a6) \ 424 : "memory"); \ 425 __sys_result = _a1; \ 426 } \ 427 (int) __sys_result; }) 428 429 # define INTERNAL_SYSCALL_RAW7(name, arg1, arg2, arg3, arg4, \ 430 arg5, arg6, arg7) \ 431 ({unsigned int __sys_result; \ 432 register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2); \ 433 register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4); \ 434 register int _tmp_arg5 = (int)(arg5), _tmp_arg6 = (int)(arg6); \ 435 register int _tmp_arg7 = (int)(arg7); \ 436 { \ 437 register int _nr __asm__ ("r7"); \ 438 register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1"); \ 439 register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3"); \ 440 register int _a5 __asm__ ("r4"), _a6 __asm__ ("r5"); \ 441 register int _a7 __asm__ ("r6"); \ 442 _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3; \ 443 _a4 = _tmp_arg4, _a5 = _tmp_arg5, _a6 = _tmp_arg6; \ 444 _a7 = _tmp_arg7; \ 445 _nr = name; \ 446 __asm__ __volatile__ ("trap 0 \n\t" \ 447 : "=r" (_a1) \ 448 : "r" (_nr), "r" (_a1), "r" (_a2), \ 449 "r" (_a3), "r" (_a4), "r" (_a5), \ 450 "r" (_a6), "r" (_a7) \ 451 : "memory"); \ 452 __sys_result = _a1; \ 453 } \ 454 (int) __sys_result; }) 455 456 # undef INTERNAL_SYSCALL 457 # define INTERNAL_SYSCALL(name, nr, args...) \ 458 INTERNAL_SYSCALL_RAW##nr(SYS_ify(name), args) 459 460 # undef INTERNAL_SYSCALL_NCS 461 # define INTERNAL_SYSCALL_NCS(number, nr, args...) \ 462 INTERNAL_SYSCALL_RAW##nr (number, args) 463 464 #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL 465 #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 466 467 #endif /* __ASSEMBLER__ */ 468 469 /* Pointer mangling support. */ 470 #if (IS_IN (rtld) \ 471 || (!defined SHARED && (IS_IN (libc) || IS_IN (libpthread)))) 472 # ifdef __ASSEMBLER__ 473 # define PTR_MANGLE(dst, src, guard) \ 474 grs t0, 1f; \ 475 1: \ 476 lrw guard, 1b@GOTPC; \ 477 addu t0, guard; \ 478 lrw guard, __pointer_chk_guard_local@GOT; \ 479 ldr.w guard, (t0, guard << 0); \ 480 ldw guard, (guard, 0); \ 481 xor dst, src, guard; 482 # define PTR_DEMANGLE(dst, src, guard) PTR_MANGLE (dst, src, guard) 483 # define PTR_MANGLE2(dst, src, guard) \ 484 xor dst, src, guard 485 # define PTR_DEMANGLE2(dst, src, guard) PTR_MANGLE2 (dst, src, guard) 486 # else 487 extern uintptr_t __pointer_chk_guard_local; 488 # define PTR_MANGLE(var) \ 489 (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local) 490 # define PTR_DEMANGLE(var) PTR_MANGLE (var) 491 # endif 492 #else 493 # ifdef __ASSEMBLER__ 494 # define PTR_MANGLE(dst, src, guard) \ 495 grs t0, 1f; \ 496 1: \ 497 lrw guard, 1b@GOTPC; \ 498 addu t0, guard; \ 499 lrw guard, __pointer_chk_guard@GOT; \ 500 ldr.w guard, (t0, guard << 0); \ 501 ldw guard, (guard, 0); \ 502 xor dst, src, guard; 503 # define PTR_DEMANGLE(dst, src, guard) PTR_MANGLE (dst, src, guard) 504 # define PTR_MANGLE2(dst, src, guard) \ 505 xor dst, src, guard 506 # define PTR_DEMANGLE2(dst, src, guard) PTR_MANGLE2 (dst, src, guard) 507 # else 508 extern uintptr_t __pointer_chk_guard; 509 # define PTR_MANGLE(var) \ 510 (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard) 511 # define PTR_DEMANGLE(var) PTR_MANGLE (var) 512 # endif 513 #endif 514 515 #endif /* linux/csky/sysdep.h */ 516