Warning: That file was not part of the compilation database. It may have many parsing errors.
| 1 | /* Copyright (C) 1992-2024 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 | #define HAVE_CLONE3_WRAPPER 1 |
| 366 | |
| 367 | #define LOAD_ARGS_0() |
| 368 | #define ASM_ARGS_0 |
| 369 | #define LOAD_ARGS_1(a1) \ |
| 370 | int _a1tmp = (int) (a1); \ |
| 371 | LOAD_ARGS_0 () \ |
| 372 | _a1 = _a1tmp; |
| 373 | #define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) |
| 374 | #define LOAD_ARGS_2(a1, a2) \ |
| 375 | int _a2tmp = (int) (a2); \ |
| 376 | LOAD_ARGS_1 (a1) \ |
| 377 | register int _a2 asm ("a2") = _a2tmp; |
| 378 | #define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) |
| 379 | #define LOAD_ARGS_3(a1, a2, a3) \ |
| 380 | int _a3tmp = (int) (a3); \ |
| 381 | LOAD_ARGS_2 (a1, a2) \ |
| 382 | register int _a3 asm ("a3") = _a3tmp; |
| 383 | #define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) |
| 384 | #define LOAD_ARGS_4(a1, a2, a3, a4) \ |
| 385 | int _a4tmp = (int) (a4); \ |
| 386 | LOAD_ARGS_3 (a1, a2, a3) \ |
| 387 | register int _a4 asm ("a4") = _a4tmp; |
| 388 | #define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) |
| 389 | #define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ |
| 390 | int _v1tmp = (int) (a5); \ |
| 391 | LOAD_ARGS_4 (a1, a2, a3, a4) \ |
| 392 | register int _v1 asm ("v1") = _v1tmp; |
| 393 | #define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1) |
| 394 | #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ |
| 395 | int _v2tmp = (int) (a6); \ |
| 396 | LOAD_ARGS_5 (a1, a2, a3, a4, a5) \ |
| 397 | register int _v2 asm ("v2") = _v2tmp; |
| 398 | #define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2) |
| 399 | #ifndef __thumb__ |
| 400 | # define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \ |
| 401 | int _v3tmp = (int) (a7); \ |
| 402 | LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) \ |
| 403 | register int _v3 asm ("v3") = _v3tmp; |
| 404 | # define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3) |
| 405 | #endif |
| 406 | |
| 407 | /* For EABI, non-constant syscalls are actually pretty easy... */ |
| 408 | #undef INTERNAL_SYSCALL_NCS |
| 409 | #define INTERNAL_SYSCALL_NCS(number, nr, args...) \ |
| 410 | INTERNAL_SYSCALL_RAW (number, nr, args) |
| 411 | |
| 412 | #endif /* __ASSEMBLER__ */ |
| 413 | |
| 414 | #endif /* linux/arm/sysdep.h */ |
| 415 |
Warning: That file was not part of the compilation database. It may have many parsing errors.
