| author | |
| committer | |
| log | f9f894200891c8af6ce3a3ad222cd0bf1ee15587 |
| tree | 098010c79f4246d7a7bb15b7ca24809bfa6c6b32 |
| parent | 75f78bfb77d62ee3e143cb7718a21f492a0d4fa6 |
13 files changed, 414 insertions(+), 441 deletions(-)
lib/c.zig-402| ... | ... | @@ -29,10 +29,6 @@ comptime { |
| 29 | 29 | @export(wasm_start, .{ .name = "_start", .linkage = .strong }); |
| 30 | 30 | } |
| 31 | 31 | |
| 32 | if (native_os == .linux) { | |
| 33 | @export(clone, .{ .name = "clone" }); | |
| 34 | } | |
| 35 | ||
| 36 | 32 | if (builtin.link_libc) { |
| 37 | 33 | @export(strcmp, .{ .name = "strcmp", .linkage = .strong }); |
| 38 | 34 | @export(strncmp, .{ .name = "strncmp", .linkage = .strong }); |
| ... | ... | @@ -188,401 +184,3 @@ test "strncmp" { |
| 188 | 184 | try std.testing.expect(strncmp("b", "a", 1) > 0); |
| 189 | 185 | try std.testing.expect(strncmp("\xff", "\x02", 1) > 0); |
| 190 | 186 | } |
| 191 | ||
| 192 | // TODO we should be able to put this directly in std/linux/x86_64.zig but | |
| 193 | // it causes a segfault in release mode. this is a workaround of calling it | |
| 194 | // across .o file boundaries. fix comptime @ptrCast of nakedcc functions. | |
| 195 | fn clone() callconv(.Naked) void { | |
| 196 | switch (native_arch) { | |
| 197 | .x86 => { | |
| 198 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 199 | // +8, +12, +16, +20, +24, +28, +32 | |
| 200 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 201 | // eax, ebx, ecx, edx, esi, edi | |
| 202 | asm volatile ( | |
| 203 | \\ pushl %%ebp | |
| 204 | \\ movl %%esp,%%ebp | |
| 205 | \\ pushl %%ebx | |
| 206 | \\ pushl %%esi | |
| 207 | \\ pushl %%edi | |
| 208 | \\ // Setup the arguments | |
| 209 | \\ movl 16(%%ebp),%%ebx | |
| 210 | \\ movl 12(%%ebp),%%ecx | |
| 211 | \\ andl $-16,%%ecx | |
| 212 | \\ subl $20,%%ecx | |
| 213 | \\ movl 20(%%ebp),%%eax | |
| 214 | \\ movl %%eax,4(%%ecx) | |
| 215 | \\ movl 8(%%ebp),%%eax | |
| 216 | \\ movl %%eax,0(%%ecx) | |
| 217 | \\ movl 24(%%ebp),%%edx | |
| 218 | \\ movl 28(%%ebp),%%esi | |
| 219 | \\ movl 32(%%ebp),%%edi | |
| 220 | \\ movl $120,%%eax | |
| 221 | \\ int $128 | |
| 222 | \\ testl %%eax,%%eax | |
| 223 | \\ jnz 1f | |
| 224 | \\ popl %%eax | |
| 225 | \\ xorl %%ebp,%%ebp | |
| 226 | \\ calll *%%eax | |
| 227 | \\ movl %%eax,%%ebx | |
| 228 | \\ movl $1,%%eax | |
| 229 | \\ int $128 | |
| 230 | \\1: | |
| 231 | \\ popl %%edi | |
| 232 | \\ popl %%esi | |
| 233 | \\ popl %%ebx | |
| 234 | \\ popl %%ebp | |
| 235 | \\ retl | |
| 236 | ); | |
| 237 | }, | |
| 238 | .x86_64 => { | |
| 239 | asm volatile ( | |
| 240 | \\ movl $56,%%eax // SYS_clone | |
| 241 | \\ movq %%rdi,%%r11 | |
| 242 | \\ movq %%rdx,%%rdi | |
| 243 | \\ movq %%r8,%%rdx | |
| 244 | \\ movq %%r9,%%r8 | |
| 245 | \\ movq 8(%%rsp),%%r10 | |
| 246 | \\ movq %%r11,%%r9 | |
| 247 | \\ andq $-16,%%rsi | |
| 248 | \\ subq $8,%%rsi | |
| 249 | \\ movq %%rcx,(%%rsi) | |
| 250 | \\ syscall | |
| 251 | \\ testq %%rax,%%rax | |
| 252 | \\ jnz 1f | |
| 253 | \\ xorl %%ebp,%%ebp | |
| 254 | \\ popq %%rdi | |
| 255 | \\ callq *%%r9 | |
| 256 | \\ movl %%eax,%%edi | |
| 257 | \\ movl $60,%%eax // SYS_exit | |
| 258 | \\ syscall | |
| 259 | \\1: ret | |
| 260 | \\ | |
| 261 | ); | |
| 262 | }, | |
| 263 | .aarch64, .aarch64_be => { | |
| 264 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 265 | // x0, x1, w2, x3, x4, x5, x6 | |
| 266 | ||
| 267 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 268 | // x8, x0, x1, x2, x3, x4 | |
| 269 | asm volatile ( | |
| 270 | \\ // align stack and save func,arg | |
| 271 | \\ and x1,x1,#-16 | |
| 272 | \\ stp x0,x3,[x1,#-16]! | |
| 273 | \\ | |
| 274 | \\ // syscall | |
| 275 | \\ uxtw x0,w2 | |
| 276 | \\ mov x2,x4 | |
| 277 | \\ mov x3,x5 | |
| 278 | \\ mov x4,x6 | |
| 279 | \\ mov x8,#220 // SYS_clone | |
| 280 | \\ svc #0 | |
| 281 | \\ | |
| 282 | \\ cbz x0,1f | |
| 283 | \\ // parent | |
| 284 | \\ ret | |
| 285 | \\ // child | |
| 286 | \\1: ldp x1,x0,[sp],#16 | |
| 287 | \\ blr x1 | |
| 288 | \\ mov x8,#93 // SYS_exit | |
| 289 | \\ svc #0 | |
| 290 | ); | |
| 291 | }, | |
| 292 | .arm, .armeb, .thumb, .thumbeb => { | |
| 293 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 294 | // r0, r1, r2, r3, +0, +4, +8 | |
| 295 | ||
| 296 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 297 | // r7 r0, r1, r2, r3, r4 | |
| 298 | asm volatile ( | |
| 299 | \\ stmfd sp!,{r4,r5,r6,r7} | |
| 300 | \\ mov r7,#120 | |
| 301 | \\ mov r6,r3 | |
| 302 | \\ mov r5,r0 | |
| 303 | \\ mov r0,r2 | |
| 304 | \\ and r1,r1,#-16 | |
| 305 | \\ ldr r2,[sp,#16] | |
| 306 | \\ ldr r3,[sp,#20] | |
| 307 | \\ ldr r4,[sp,#24] | |
| 308 | \\ svc 0 | |
| 309 | \\ tst r0,r0 | |
| 310 | \\ beq 1f | |
| 311 | \\ ldmfd sp!,{r4,r5,r6,r7} | |
| 312 | \\ bx lr | |
| 313 | \\ | |
| 314 | \\1: mov r0,r6 | |
| 315 | \\ bl 3f | |
| 316 | \\2: mov r7,#1 | |
| 317 | \\ svc 0 | |
| 318 | \\ b 2b | |
| 319 | \\3: bx r5 | |
| 320 | ); | |
| 321 | }, | |
| 322 | .riscv32 => { | |
| 323 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 324 | // a0, a1, a2, a3, a4, a5, a6 | |
| 325 | ||
| 326 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 327 | // a7 a0, a1, a2, a3, a4 | |
| 328 | asm volatile ( | |
| 329 | \\ # Save func and arg to stack | |
| 330 | \\ addi a1, a1, -8 | |
| 331 | \\ sw a0, 0(a1) | |
| 332 | \\ sw a3, 4(a1) | |
| 333 | \\ | |
| 334 | \\ # Call SYS_clone | |
| 335 | \\ mv a0, a2 | |
| 336 | \\ mv a2, a4 | |
| 337 | \\ mv a3, a5 | |
| 338 | \\ mv a4, a6 | |
| 339 | \\ li a7, 220 # SYS_clone | |
| 340 | \\ ecall | |
| 341 | \\ | |
| 342 | \\ beqz a0, 1f | |
| 343 | \\ # Parent | |
| 344 | \\ ret | |
| 345 | \\ | |
| 346 | \\ # Child | |
| 347 | \\1: lw a1, 0(sp) | |
| 348 | \\ lw a0, 4(sp) | |
| 349 | \\ jalr a1 | |
| 350 | \\ | |
| 351 | \\ # Exit | |
| 352 | \\ li a7, 93 # SYS_exit | |
| 353 | \\ ecall | |
| 354 | ); | |
| 355 | }, | |
| 356 | .riscv64 => { | |
| 357 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 358 | // a0, a1, a2, a3, a4, a5, a6 | |
| 359 | ||
| 360 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 361 | // a7 a0, a1, a2, a3, a4 | |
| 362 | asm volatile ( | |
| 363 | \\ # Save func and arg to stack | |
| 364 | \\ addi a1, a1, -16 | |
| 365 | \\ sd a0, 0(a1) | |
| 366 | \\ sd a3, 8(a1) | |
| 367 | \\ | |
| 368 | \\ # Call SYS_clone | |
| 369 | \\ mv a0, a2 | |
| 370 | \\ mv a2, a4 | |
| 371 | \\ mv a3, a5 | |
| 372 | \\ mv a4, a6 | |
| 373 | \\ li a7, 220 # SYS_clone | |
| 374 | \\ ecall | |
| 375 | \\ | |
| 376 | \\ beqz a0, 1f | |
| 377 | \\ # Parent | |
| 378 | \\ ret | |
| 379 | \\ | |
| 380 | \\ # Child | |
| 381 | \\1: ld a1, 0(sp) | |
| 382 | \\ ld a0, 8(sp) | |
| 383 | \\ jalr a1 | |
| 384 | \\ | |
| 385 | \\ # Exit | |
| 386 | \\ li a7, 93 # SYS_exit | |
| 387 | \\ ecall | |
| 388 | ); | |
| 389 | }, | |
| 390 | .mips, .mipsel, .mips64, .mips64el => { | |
| 391 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 392 | // 3, 4, 5, 6, 7, 8, 9 | |
| 393 | ||
| 394 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 395 | // 2 4, 5, 6, 7, 8 | |
| 396 | asm volatile ( | |
| 397 | \\ # Save function pointer and argument pointer on new thread stack | |
| 398 | \\ and $5, $5, -8 | |
| 399 | \\ subu $5, $5, 16 | |
| 400 | \\ sw $4, 0($5) | |
| 401 | \\ sw $7, 4($5) | |
| 402 | \\ # Shuffle (fn,sp,fl,arg,ptid,tls,ctid) to (fl,sp,ptid,tls,ctid) | |
| 403 | \\ move $4, $6 | |
| 404 | \\ lw $6, 16($sp) | |
| 405 | \\ lw $7, 20($sp) | |
| 406 | \\ lw $9, 24($sp) | |
| 407 | \\ subu $sp, $sp, 16 | |
| 408 | \\ sw $9, 16($sp) | |
| 409 | \\ li $2, 4120 | |
| 410 | \\ syscall | |
| 411 | \\ beq $7, $0, 1f | |
| 412 | \\ nop | |
| 413 | \\ addu $sp, $sp, 16 | |
| 414 | \\ jr $ra | |
| 415 | \\ subu $2, $0, $2 | |
| 416 | \\1: | |
| 417 | \\ beq $2, $0, 1f | |
| 418 | \\ nop | |
| 419 | \\ addu $sp, $sp, 16 | |
| 420 | \\ jr $ra | |
| 421 | \\ nop | |
| 422 | \\1: | |
| 423 | \\ lw $25, 0($sp) | |
| 424 | \\ lw $4, 4($sp) | |
| 425 | \\ jalr $25 | |
| 426 | \\ nop | |
| 427 | \\ move $4, $2 | |
| 428 | \\ li $2, 4001 | |
| 429 | \\ syscall | |
| 430 | ); | |
| 431 | }, | |
| 432 | .powerpc, .powerpcle => { | |
| 433 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 434 | // 3, 4, 5, 6, 7, 8, 9 | |
| 435 | ||
| 436 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 437 | // 0 3, 4, 5, 6, 7 | |
| 438 | asm volatile ( | |
| 439 | \\ # store non-volatile regs r30, r31 on stack in order to put our | |
| 440 | \\ # start func and its arg there | |
| 441 | \\ stwu 30, -16(1) | |
| 442 | \\ stw 31, 4(1) | |
| 443 | \\ | |
| 444 | \\ # save r3 (func) into r30, and r6(arg) into r31 | |
| 445 | \\ mr 30, 3 | |
| 446 | \\ mr 31, 6 | |
| 447 | \\ | |
| 448 | \\ # create initial stack frame for new thread | |
| 449 | \\ clrrwi 4, 4, 4 | |
| 450 | \\ li 0, 0 | |
| 451 | \\ stwu 0, -16(4) | |
| 452 | \\ | |
| 453 | \\ #move c into first arg | |
| 454 | \\ mr 3, 5 | |
| 455 | \\ #mr 4, 4 | |
| 456 | \\ mr 5, 7 | |
| 457 | \\ mr 6, 8 | |
| 458 | \\ mr 7, 9 | |
| 459 | \\ | |
| 460 | \\ # move syscall number into r0 | |
| 461 | \\ li 0, 120 | |
| 462 | \\ | |
| 463 | \\ sc | |
| 464 | \\ | |
| 465 | \\ # check for syscall error | |
| 466 | \\ bns+ 1f # jump to label 1 if no summary overflow. | |
| 467 | \\ #else | |
| 468 | \\ neg 3, 3 #negate the result (errno) | |
| 469 | \\ 1: | |
| 470 | \\ # compare sc result with 0 | |
| 471 | \\ cmpwi cr7, 3, 0 | |
| 472 | \\ | |
| 473 | \\ # if not 0, jump to end | |
| 474 | \\ bne cr7, 2f | |
| 475 | \\ | |
| 476 | \\ #else: we're the child | |
| 477 | \\ #call funcptr: move arg (d) into r3 | |
| 478 | \\ mr 3, 31 | |
| 479 | \\ #move r30 (funcptr) into CTR reg | |
| 480 | \\ mtctr 30 | |
| 481 | \\ # call CTR reg | |
| 482 | \\ bctrl | |
| 483 | \\ # mov SYS_exit into r0 (the exit param is already in r3) | |
| 484 | \\ li 0, 1 | |
| 485 | \\ sc | |
| 486 | \\ | |
| 487 | \\ 2: | |
| 488 | \\ | |
| 489 | \\ # restore stack | |
| 490 | \\ lwz 30, 0(1) | |
| 491 | \\ lwz 31, 4(1) | |
| 492 | \\ addi 1, 1, 16 | |
| 493 | \\ | |
| 494 | \\ blr | |
| 495 | ); | |
| 496 | }, | |
| 497 | .powerpc64, .powerpc64le => { | |
| 498 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 499 | // 3, 4, 5, 6, 7, 8, 9 | |
| 500 | ||
| 501 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 502 | // 0 3, 4, 5, 6, 7 | |
| 503 | asm volatile ( | |
| 504 | \\ # create initial stack frame for new thread | |
| 505 | \\ clrrdi 4, 4, 4 | |
| 506 | \\ li 0, 0 | |
| 507 | \\ stdu 0,-32(4) | |
| 508 | \\ | |
| 509 | \\ # save fn and arg to child stack | |
| 510 | \\ std 3, 8(4) | |
| 511 | \\ std 6, 16(4) | |
| 512 | \\ | |
| 513 | \\ # shuffle args into correct registers and call SYS_clone | |
| 514 | \\ mr 3, 5 | |
| 515 | \\ #mr 4, 4 | |
| 516 | \\ mr 5, 7 | |
| 517 | \\ mr 6, 8 | |
| 518 | \\ mr 7, 9 | |
| 519 | \\ li 0, 120 # SYS_clone = 120 | |
| 520 | \\ sc | |
| 521 | \\ | |
| 522 | \\ # if error, negate return (errno) | |
| 523 | \\ bns+ 1f | |
| 524 | \\ neg 3, 3 | |
| 525 | \\ | |
| 526 | \\1: | |
| 527 | \\ # if we're the parent, return | |
| 528 | \\ cmpwi cr7, 3, 0 | |
| 529 | \\ bnelr cr7 | |
| 530 | \\ | |
| 531 | \\ # we're the child. call fn(arg) | |
| 532 | \\ ld 3, 16(1) | |
| 533 | \\ ld 12, 8(1) | |
| 534 | \\ mtctr 12 | |
| 535 | \\ bctrl | |
| 536 | \\ | |
| 537 | \\ # call SYS_exit. exit code is already in r3 from fn return value | |
| 538 | \\ li 0, 1 # SYS_exit = 1 | |
| 539 | \\ sc | |
| 540 | ); | |
| 541 | }, | |
| 542 | .sparc64 => { | |
| 543 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 544 | // i0, i1, i2, i3, i4, i5, sp | |
| 545 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 546 | // g1 o0, o1, o2, o3, o4 | |
| 547 | asm volatile ( | |
| 548 | \\ save %%sp, -192, %%sp | |
| 549 | \\ # Save the func pointer and the arg pointer | |
| 550 | \\ mov %%i0, %%g2 | |
| 551 | \\ mov %%i3, %%g3 | |
| 552 | \\ # Shuffle the arguments | |
| 553 | \\ mov 217, %%g1 | |
| 554 | \\ mov %%i2, %%o0 | |
| 555 | \\ # Add some extra space for the initial frame | |
| 556 | \\ sub %%i1, 176 + 2047, %%o1 | |
| 557 | \\ mov %%i4, %%o2 | |
| 558 | \\ mov %%i5, %%o3 | |
| 559 | \\ ldx [%%fp + 0x8af], %%o4 | |
| 560 | \\ t 0x6d | |
| 561 | \\ bcs,pn %%xcc, 2f | |
| 562 | \\ nop | |
| 563 | \\ # The child pid is returned in o0 while o1 tells if this | |
| 564 | \\ # process is # the child (=1) or the parent (=0). | |
| 565 | \\ brnz %%o1, 1f | |
| 566 | \\ nop | |
| 567 | \\ # Parent process, return the child pid | |
| 568 | \\ mov %%o0, %%i0 | |
| 569 | \\ ret | |
| 570 | \\ restore | |
| 571 | \\1: | |
| 572 | \\ # Child process, call func(arg) | |
| 573 | \\ mov %%g0, %%fp | |
| 574 | \\ call %%g2 | |
| 575 | \\ mov %%g3, %%o0 | |
| 576 | \\ # Exit | |
| 577 | \\ mov 1, %%g1 | |
| 578 | \\ t 0x6d | |
| 579 | \\2: | |
| 580 | \\ # The syscall failed | |
| 581 | \\ sub %%g0, %%o0, %%i0 | |
| 582 | \\ ret | |
| 583 | \\ restore | |
| 584 | ); | |
| 585 | }, | |
| 586 | else => @compileError("Implement clone() for this arch."), | |
| 587 | } | |
| 588 | } |
lib/std/os/linux.zig+21-1| ... | ... | @@ -65,6 +65,27 @@ pub const socketcall = syscall_bits.socketcall; |
| 65 | 65 | pub const syscall_pipe = syscall_bits.syscall_pipe; |
| 66 | 66 | pub const syscall_fork = syscall_bits.syscall_fork; |
| 67 | 67 | |
| 68 | pub fn clone( | |
| 69 | func: *const fn (arg: usize) callconv(.C) u8, | |
| 70 | stack: usize, | |
| 71 | flags: u32, | |
| 72 | arg: usize, | |
| 73 | ptid: *i32, | |
| 74 | tp: usize, // aka tls | |
| 75 | ctid: *i32, | |
| 76 | ) usize { | |
| 77 | // Can't directly call a naked function; cast to C calling convention first. | |
| 78 | return @as(*const fn ( | |
| 79 | *const fn (arg: usize) callconv(.C) u8, | |
| 80 | usize, | |
| 81 | u32, | |
| 82 | usize, | |
| 83 | *i32, | |
| 84 | usize, | |
| 85 | *i32, | |
| 86 | ) callconv(.C) usize, @ptrCast(&syscall_bits.clone))(func, stack, flags, arg, ptid, tp, ctid); | |
| 87 | } | |
| 88 | ||
| 68 | 89 | pub const ARCH = arch_bits.ARCH; |
| 69 | 90 | pub const Elf_Symndx = arch_bits.Elf_Symndx; |
| 70 | 91 | pub const F = arch_bits.F; |
| ... | ... | @@ -77,7 +98,6 @@ pub const Stat = arch_bits.Stat; |
| 77 | 98 | pub const VDSO = arch_bits.VDSO; |
| 78 | 99 | pub const blkcnt_t = arch_bits.blkcnt_t; |
| 79 | 100 | pub const blksize_t = arch_bits.blksize_t; |
| 80 | pub const clone = arch_bits.clone; | |
| 81 | 101 | pub const dev_t = arch_bits.dev_t; |
| 82 | 102 | pub const ino_t = arch_bits.ino_t; |
| 83 | 103 | pub const mcontext_t = arch_bits.mcontext_t; |
lib/std/os/linux/arm-eabi.zig+30-4| ... | ... | @@ -98,10 +98,36 @@ pub fn syscall6( |
| 98 | 98 | ); |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 102 | ||
| 103 | /// This matches the libc clone function. | |
| 104 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 101 | pub fn clone() callconv(.Naked) usize { | |
| 102 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 103 | // r0, r1, r2, r3, +0, +4, +8 | |
| 104 | // | |
| 105 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 106 | // r7 r0, r1, r2, r3, r4 | |
| 107 | asm volatile ( | |
| 108 | \\ stmfd sp!,{r4,r5,r6,r7} | |
| 109 | \\ mov r7,#120 // SYS_clone | |
| 110 | \\ mov r6,r3 | |
| 111 | \\ mov r5,r0 | |
| 112 | \\ mov r0,r2 | |
| 113 | \\ and r1,r1,#-16 | |
| 114 | \\ ldr r2,[sp,#16] | |
| 115 | \\ ldr r3,[sp,#20] | |
| 116 | \\ ldr r4,[sp,#24] | |
| 117 | \\ svc 0 | |
| 118 | \\ tst r0,r0 | |
| 119 | \\ beq 1f | |
| 120 | \\ ldmfd sp!,{r4,r5,r6,r7} | |
| 121 | \\ bx lr | |
| 122 | \\ | |
| 123 | \\1: mov r0,r6 | |
| 124 | \\ bl 3f | |
| 125 | \\2: mov r7,#1 // SYS_exit | |
| 126 | \\ svc 0 | |
| 127 | \\ b 2b | |
| 128 | \\3: bx r5 | |
| 129 | ); | |
| 130 | } | |
| 105 | 131 | |
| 106 | 132 | pub fn restore() callconv(.Naked) noreturn { |
| 107 | 133 | switch (@import("builtin").zig_backend) { |
lib/std/os/linux/arm64.zig+29-4| ... | ... | @@ -98,10 +98,35 @@ pub fn syscall6( |
| 98 | 98 | ); |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 102 | ||
| 103 | /// This matches the libc clone function. | |
| 104 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 101 | pub fn clone() callconv(.Naked) usize { | |
| 102 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 103 | // x0, x1, w2, x3, x4, x5, x6 | |
| 104 | // | |
| 105 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 106 | // x8, x0, x1, x2, x3, x4 | |
| 107 | asm volatile ( | |
| 108 | \\ // align stack and save func,arg | |
| 109 | \\ and x1,x1,#-16 | |
| 110 | \\ stp x0,x3,[x1,#-16]! | |
| 111 | \\ | |
| 112 | \\ // syscall | |
| 113 | \\ uxtw x0,w2 | |
| 114 | \\ mov x2,x4 | |
| 115 | \\ mov x3,x5 | |
| 116 | \\ mov x4,x6 | |
| 117 | \\ mov x8,#220 // SYS_clone | |
| 118 | \\ svc #0 | |
| 119 | \\ | |
| 120 | \\ cbz x0,1f | |
| 121 | \\ // parent | |
| 122 | \\ ret | |
| 123 | \\ // child | |
| 124 | \\1: ldp x1,x0,[sp],#16 | |
| 125 | \\ blr x1 | |
| 126 | \\ mov x8,#93 // SYS_exit | |
| 127 | \\ svc #0 | |
| 128 | ); | |
| 129 | } | |
| 105 | 130 | |
| 106 | 131 | pub const restore = restore_rt; |
| 107 | 132 |
lib/std/os/linux/mips.zig+42-4| ... | ... | @@ -190,10 +190,48 @@ pub fn syscall7( |
| 190 | 190 | ); |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 194 | ||
| 195 | /// This matches the libc clone function. | |
| 196 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 193 | pub fn clone() callconv(.Naked) usize { | |
| 194 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 195 | // 3, 4, 5, 6, 7, 8, 9 | |
| 196 | // | |
| 197 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 198 | // 2 4, 5, 6, 7, 8 | |
| 199 | asm volatile ( | |
| 200 | \\ # Save function pointer and argument pointer on new thread stack | |
| 201 | \\ and $5, $5, -8 | |
| 202 | \\ subu $5, $5, 16 | |
| 203 | \\ sw $4, 0($5) | |
| 204 | \\ sw $7, 4($5) | |
| 205 | \\ # Shuffle (fn,sp,fl,arg,ptid,tls,ctid) to (fl,sp,ptid,tls,ctid) | |
| 206 | \\ move $4, $6 | |
| 207 | \\ lw $6, 16($sp) | |
| 208 | \\ lw $7, 20($sp) | |
| 209 | \\ lw $9, 24($sp) | |
| 210 | \\ subu $sp, $sp, 16 | |
| 211 | \\ sw $9, 16($sp) | |
| 212 | \\ li $2, 4120 # SYS_clone | |
| 213 | \\ syscall | |
| 214 | \\ beq $7, $0, 1f | |
| 215 | \\ nop | |
| 216 | \\ addu $sp, $sp, 16 | |
| 217 | \\ jr $ra | |
| 218 | \\ subu $2, $0, $2 | |
| 219 | \\1: | |
| 220 | \\ beq $2, $0, 1f | |
| 221 | \\ nop | |
| 222 | \\ addu $sp, $sp, 16 | |
| 223 | \\ jr $ra | |
| 224 | \\ nop | |
| 225 | \\1: | |
| 226 | \\ lw $25, 0($sp) | |
| 227 | \\ lw $4, 4($sp) | |
| 228 | \\ jalr $25 | |
| 229 | \\ nop | |
| 230 | \\ move $4, $2 | |
| 231 | \\ li $2, 4001 # SYS_exit | |
| 232 | \\ syscall | |
| 233 | ); | |
| 234 | } | |
| 197 | 235 | |
| 198 | 236 | pub fn restore() callconv(.Naked) noreturn { |
| 199 | 237 | asm volatile ( |
lib/std/os/linux/powerpc.zig+65-4| ... | ... | @@ -126,10 +126,71 @@ pub fn syscall6( |
| 126 | 126 | ); |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 130 | ||
| 131 | /// This matches the libc clone function. | |
| 132 | pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 129 | pub fn clone() callconv(.Naked) usize { | |
| 130 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 131 | // 3, 4, 5, 6, 7, 8, 9 | |
| 132 | // | |
| 133 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 134 | // 0 3, 4, 5, 6, 7 | |
| 135 | asm volatile ( | |
| 136 | \\ # store non-volatile regs r30, r31 on stack in order to put our | |
| 137 | \\ # start func and its arg there | |
| 138 | \\ stwu 30, -16(1) | |
| 139 | \\ stw 31, 4(1) | |
| 140 | \\ | |
| 141 | \\ # save r3 (func) into r30, and r6(arg) into r31 | |
| 142 | \\ mr 30, 3 | |
| 143 | \\ mr 31, 6 | |
| 144 | \\ | |
| 145 | \\ # create initial stack frame for new thread | |
| 146 | \\ clrrwi 4, 4, 4 | |
| 147 | \\ li 0, 0 | |
| 148 | \\ stwu 0, -16(4) | |
| 149 | \\ | |
| 150 | \\ #move c into first arg | |
| 151 | \\ mr 3, 5 | |
| 152 | \\ #mr 4, 4 | |
| 153 | \\ mr 5, 7 | |
| 154 | \\ mr 6, 8 | |
| 155 | \\ mr 7, 9 | |
| 156 | \\ | |
| 157 | \\ # move syscall number into r0 | |
| 158 | \\ li 0, 120 # SYS_clone | |
| 159 | \\ | |
| 160 | \\ sc | |
| 161 | \\ | |
| 162 | \\ # check for syscall error | |
| 163 | \\ bns+ 1f # jump to label 1 if no summary overflow. | |
| 164 | \\ #else | |
| 165 | \\ neg 3, 3 #negate the result (errno) | |
| 166 | \\ 1: | |
| 167 | \\ # compare sc result with 0 | |
| 168 | \\ cmpwi cr7, 3, 0 | |
| 169 | \\ | |
| 170 | \\ # if not 0, jump to end | |
| 171 | \\ bne cr7, 2f | |
| 172 | \\ | |
| 173 | \\ #else: we're the child | |
| 174 | \\ #call funcptr: move arg (d) into r3 | |
| 175 | \\ mr 3, 31 | |
| 176 | \\ #move r30 (funcptr) into CTR reg | |
| 177 | \\ mtctr 30 | |
| 178 | \\ # call CTR reg | |
| 179 | \\ bctrl | |
| 180 | \\ # mov SYS_exit into r0 (the exit param is already in r3) | |
| 181 | \\ li 0, 1 | |
| 182 | \\ sc | |
| 183 | \\ | |
| 184 | \\ 2: | |
| 185 | \\ | |
| 186 | \\ # restore stack | |
| 187 | \\ lwz 30, 0(1) | |
| 188 | \\ lwz 31, 4(1) | |
| 189 | \\ addi 1, 1, 16 | |
| 190 | \\ | |
| 191 | \\ blr | |
| 192 | ); | |
| 193 | } | |
| 133 | 194 | |
| 134 | 195 | pub const restore = restore_rt; |
| 135 | 196 |
lib/std/os/linux/powerpc64.zig+45-4| ... | ... | @@ -126,10 +126,51 @@ pub fn syscall6( |
| 126 | 126 | ); |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 130 | ||
| 131 | /// This matches the libc clone function. | |
| 132 | pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 129 | pub fn clone() callconv(.Naked) usize { | |
| 130 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 131 | // 3, 4, 5, 6, 7, 8, 9 | |
| 132 | // | |
| 133 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 134 | // 0 3, 4, 5, 6, 7 | |
| 135 | asm volatile ( | |
| 136 | \\ # create initial stack frame for new thread | |
| 137 | \\ clrrdi 4, 4, 4 | |
| 138 | \\ li 0, 0 | |
| 139 | \\ stdu 0,-32(4) | |
| 140 | \\ | |
| 141 | \\ # save fn and arg to child stack | |
| 142 | \\ std 3, 8(4) | |
| 143 | \\ std 6, 16(4) | |
| 144 | \\ | |
| 145 | \\ # shuffle args into correct registers and call SYS_clone | |
| 146 | \\ mr 3, 5 | |
| 147 | \\ #mr 4, 4 | |
| 148 | \\ mr 5, 7 | |
| 149 | \\ mr 6, 8 | |
| 150 | \\ mr 7, 9 | |
| 151 | \\ li 0, 120 # SYS_clone = 120 | |
| 152 | \\ sc | |
| 153 | \\ | |
| 154 | \\ # if error, negate return (errno) | |
| 155 | \\ bns+ 1f | |
| 156 | \\ neg 3, 3 | |
| 157 | \\ | |
| 158 | \\1: | |
| 159 | \\ # if we're the parent, return | |
| 160 | \\ cmpwi cr7, 3, 0 | |
| 161 | \\ bnelr cr7 | |
| 162 | \\ | |
| 163 | \\ # we're the child. call fn(arg) | |
| 164 | \\ ld 3, 16(1) | |
| 165 | \\ ld 12, 8(1) | |
| 166 | \\ mtctr 12 | |
| 167 | \\ bctrl | |
| 168 | \\ | |
| 169 | \\ # call SYS_exit. exit code is already in r3 from fn return value | |
| 170 | \\ li 0, 1 # SYS_exit = 1 | |
| 171 | \\ sc | |
| 172 | ); | |
| 173 | } | |
| 133 | 174 | |
| 134 | 175 | pub const restore = restore_rt; |
| 135 | 176 |
lib/std/os/linux/riscv32.zig+34-3| ... | ... | @@ -95,9 +95,40 @@ pub fn syscall6( |
| 95 | 95 | ); |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 99 | ||
| 100 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 98 | pub fn clone() callconv(.Naked) usize { | |
| 99 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 100 | // a0, a1, a2, a3, a4, a5, a6 | |
| 101 | // | |
| 102 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 103 | // a7 a0, a1, a2, a3, a4 | |
| 104 | asm volatile ( | |
| 105 | \\ # Save func and arg to stack | |
| 106 | \\ addi a1, a1, -8 | |
| 107 | \\ sw a0, 0(a1) | |
| 108 | \\ sw a3, 4(a1) | |
| 109 | \\ | |
| 110 | \\ # Call SYS_clone | |
| 111 | \\ mv a0, a2 | |
| 112 | \\ mv a2, a4 | |
| 113 | \\ mv a3, a5 | |
| 114 | \\ mv a4, a6 | |
| 115 | \\ li a7, 220 # SYS_clone | |
| 116 | \\ ecall | |
| 117 | \\ | |
| 118 | \\ beqz a0, 1f | |
| 119 | \\ # Parent | |
| 120 | \\ ret | |
| 121 | \\ | |
| 122 | \\ # Child | |
| 123 | \\1: lw a1, 0(sp) | |
| 124 | \\ lw a0, 4(sp) | |
| 125 | \\ jalr a1 | |
| 126 | \\ | |
| 127 | \\ # Exit | |
| 128 | \\ li a7, 93 # SYS_exit | |
| 129 | \\ ecall | |
| 130 | ); | |
| 131 | } | |
| 101 | 132 | |
| 102 | 133 | pub const restore = restore_rt; |
| 103 | 134 |
lib/std/os/linux/riscv64.zig+34-3| ... | ... | @@ -95,9 +95,40 @@ pub fn syscall6( |
| 95 | 95 | ); |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 99 | ||
| 100 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 98 | pub fn clone() callconv(.Naked) usize { | |
| 99 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 100 | // a0, a1, a2, a3, a4, a5, a6 | |
| 101 | // | |
| 102 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 103 | // a7 a0, a1, a2, a3, a4 | |
| 104 | asm volatile ( | |
| 105 | \\ # Save func and arg to stack | |
| 106 | \\ addi a1, a1, -16 | |
| 107 | \\ sd a0, 0(a1) | |
| 108 | \\ sd a3, 8(a1) | |
| 109 | \\ | |
| 110 | \\ # Call SYS_clone | |
| 111 | \\ mv a0, a2 | |
| 112 | \\ mv a2, a4 | |
| 113 | \\ mv a3, a5 | |
| 114 | \\ mv a4, a6 | |
| 115 | \\ li a7, 220 # SYS_clone | |
| 116 | \\ ecall | |
| 117 | \\ | |
| 118 | \\ beqz a0, 1f | |
| 119 | \\ # Parent | |
| 120 | \\ ret | |
| 121 | \\ | |
| 122 | \\ # Child | |
| 123 | \\1: ld a1, 0(sp) | |
| 124 | \\ ld a0, 8(sp) | |
| 125 | \\ jalr a1 | |
| 126 | \\ | |
| 127 | \\ # Exit | |
| 128 | \\ li a7, 93 # SYS_exit | |
| 129 | \\ ecall | |
| 130 | ); | |
| 131 | } | |
| 101 | 132 | |
| 102 | 133 | pub const restore = restore_rt; |
| 103 | 134 |
lib/std/os/linux/sparc64.zig+45-4| ... | ... | @@ -178,10 +178,51 @@ pub fn syscall6( |
| 178 | 178 | ); |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 182 | ||
| 183 | /// This matches the libc clone function. | |
| 184 | pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 181 | pub fn clone() callconv(.Naked) usize { | |
| 182 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 183 | // i0, i1, i2, i3, i4, i5, sp | |
| 184 | // | |
| 185 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 186 | // g1 o0, o1, o2, o3, o4 | |
| 187 | asm volatile ( | |
| 188 | \\ save %%sp, -192, %%sp | |
| 189 | \\ # Save the func pointer and the arg pointer | |
| 190 | \\ mov %%i0, %%g2 | |
| 191 | \\ mov %%i3, %%g3 | |
| 192 | \\ # Shuffle the arguments | |
| 193 | \\ mov 217, %%g1 # SYS_clone | |
| 194 | \\ mov %%i2, %%o0 | |
| 195 | \\ # Add some extra space for the initial frame | |
| 196 | \\ sub %%i1, 176 + 2047, %%o1 | |
| 197 | \\ mov %%i4, %%o2 | |
| 198 | \\ mov %%i5, %%o3 | |
| 199 | \\ ldx [%%fp + 0x8af], %%o4 | |
| 200 | \\ t 0x6d | |
| 201 | \\ bcs,pn %%xcc, 2f | |
| 202 | \\ nop | |
| 203 | \\ # The child pid is returned in o0 while o1 tells if this | |
| 204 | \\ # process is # the child (=1) or the parent (=0). | |
| 205 | \\ brnz %%o1, 1f | |
| 206 | \\ nop | |
| 207 | \\ # Parent process, return the child pid | |
| 208 | \\ mov %%o0, %%i0 | |
| 209 | \\ ret | |
| 210 | \\ restore | |
| 211 | \\1: | |
| 212 | \\ # Child process, call func(arg) | |
| 213 | \\ mov %%g0, %%fp | |
| 214 | \\ call %%g2 | |
| 215 | \\ mov %%g3, %%o0 | |
| 216 | \\ # Exit | |
| 217 | \\ mov 1, %%g1 # SYS_exit | |
| 218 | \\ t 0x6d | |
| 219 | \\2: | |
| 220 | \\ # The syscall failed | |
| 221 | \\ sub %%g0, %%o0, %%i0 | |
| 222 | \\ ret | |
| 223 | \\ restore | |
| 224 | ); | |
| 225 | } | |
| 185 | 226 | |
| 186 | 227 | pub const restore = restore_rt; |
| 187 | 228 |
lib/std/os/linux/thumb.zig+2| ... | ... | @@ -141,6 +141,8 @@ pub fn syscall6( |
| 141 | 141 | ); |
| 142 | 142 | } |
| 143 | 143 | |
| 144 | pub const clone = @import("arm-eabi.zig").clone; | |
| 145 | ||
| 144 | 146 | pub fn restore() callconv(.Naked) noreturn { |
| 145 | 147 | asm volatile ( |
| 146 | 148 | \\ mov r7, %[number] |
lib/std/os/linux/x86.zig+42-4| ... | ... | @@ -118,10 +118,48 @@ pub fn socketcall(call: usize, args: [*]const usize) usize { |
| 118 | 118 | ); |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 122 | ||
| 123 | /// This matches the libc clone function. | |
| 124 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 121 | pub fn clone() callconv(.Naked) usize { | |
| 122 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | |
| 123 | // +8, +12, +16, +20, +24, +28, +32 | |
| 124 | // | |
| 125 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | |
| 126 | // eax, ebx, ecx, edx, esi, edi | |
| 127 | asm volatile ( | |
| 128 | \\ pushl %%ebp | |
| 129 | \\ movl %%esp,%%ebp | |
| 130 | \\ pushl %%ebx | |
| 131 | \\ pushl %%esi | |
| 132 | \\ pushl %%edi | |
| 133 | \\ // Setup the arguments | |
| 134 | \\ movl 16(%%ebp),%%ebx | |
| 135 | \\ movl 12(%%ebp),%%ecx | |
| 136 | \\ andl $-16,%%ecx | |
| 137 | \\ subl $20,%%ecx | |
| 138 | \\ movl 20(%%ebp),%%eax | |
| 139 | \\ movl %%eax,4(%%ecx) | |
| 140 | \\ movl 8(%%ebp),%%eax | |
| 141 | \\ movl %%eax,0(%%ecx) | |
| 142 | \\ movl 24(%%ebp),%%edx | |
| 143 | \\ movl 28(%%ebp),%%esi | |
| 144 | \\ movl 32(%%ebp),%%edi | |
| 145 | \\ movl $120,%%eax // SYS_clone | |
| 146 | \\ int $128 | |
| 147 | \\ testl %%eax,%%eax | |
| 148 | \\ jnz 1f | |
| 149 | \\ popl %%eax | |
| 150 | \\ xorl %%ebp,%%ebp | |
| 151 | \\ calll *%%eax | |
| 152 | \\ movl %%eax,%%ebx | |
| 153 | \\ movl $1,%%eax // SYS_exit | |
| 154 | \\ int $128 | |
| 155 | \\1: | |
| 156 | \\ popl %%edi | |
| 157 | \\ popl %%esi | |
| 158 | \\ popl %%ebx | |
| 159 | \\ popl %%ebp | |
| 160 | \\ retl | |
| 161 | ); | |
| 162 | } | |
| 125 | 163 | |
| 126 | 164 | pub fn restore() callconv(.Naked) noreturn { |
| 127 | 165 | switch (@import("builtin").zig_backend) { |
lib/std/os/linux/x86_64.zig+25-4| ... | ... | @@ -100,10 +100,31 @@ pub fn syscall6( |
| 100 | 100 | ); |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | const CloneFn = *const fn (arg: usize) callconv(.C) u8; | |
| 104 | ||
| 105 | /// This matches the libc clone function. | |
| 106 | pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | |
| 103 | pub fn clone() callconv(.Naked) usize { | |
| 104 | asm volatile ( | |
| 105 | \\ movl $56,%%eax // SYS_clone | |
| 106 | \\ movq %%rdi,%%r11 | |
| 107 | \\ movq %%rdx,%%rdi | |
| 108 | \\ movq %%r8,%%rdx | |
| 109 | \\ movq %%r9,%%r8 | |
| 110 | \\ movq 8(%%rsp),%%r10 | |
| 111 | \\ movq %%r11,%%r9 | |
| 112 | \\ andq $-16,%%rsi | |
| 113 | \\ subq $8,%%rsi | |
| 114 | \\ movq %%rcx,(%%rsi) | |
| 115 | \\ syscall | |
| 116 | \\ testq %%rax,%%rax | |
| 117 | \\ jnz 1f | |
| 118 | \\ xorl %%ebp,%%ebp | |
| 119 | \\ popq %%rdi | |
| 120 | \\ callq *%%r9 | |
| 121 | \\ movl %%eax,%%edi | |
| 122 | \\ movl $60,%%eax // SYS_exit | |
| 123 | \\ syscall | |
| 124 | \\1: ret | |
| 125 | \\ | |
| 126 | ); | |
| 127 | } | |
| 107 | 128 | |
| 108 | 129 | pub const restore = restore_rt; |
| 109 | 130 |