authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-08-01 23:46:09+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-07 01:19:51-07:00
logf9f894200891c8af6ce3a3ad222cd0bf1ee15587
tree098010c79f4246d7a7bb15b7ca24809bfa6c6b32
parent75f78bfb77d62ee3e143cb7718a21f492a0d4fa6

std.os.linux: Move clone() here and stop exporting it.


13 files changed, 414 insertions(+), 441 deletions(-)

lib/c.zig-402
......@@ -29,10 +29,6 @@ comptime {
2929 @export(wasm_start, .{ .name = "_start", .linkage = .strong });
3030 }
3131
32 if (native_os == .linux) {
33 @export(clone, .{ .name = "clone" });
34 }
35
3632 if (builtin.link_libc) {
3733 @export(strcmp, .{ .name = "strcmp", .linkage = .strong });
3834 @export(strncmp, .{ .name = "strncmp", .linkage = .strong });
......@@ -188,401 +184,3 @@ test "strncmp" {
188184 try std.testing.expect(strncmp("b", "a", 1) > 0);
189185 try std.testing.expect(strncmp("\xff", "\x02", 1) > 0);
190186}
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.
195fn 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;
6565pub const syscall_pipe = syscall_bits.syscall_pipe;
6666pub const syscall_fork = syscall_bits.syscall_fork;
6767
68pub 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
6889pub const ARCH = arch_bits.ARCH;
6990pub const Elf_Symndx = arch_bits.Elf_Symndx;
7091pub const F = arch_bits.F;
......@@ -77,7 +98,6 @@ pub const Stat = arch_bits.Stat;
7798pub const VDSO = arch_bits.VDSO;
7899pub const blkcnt_t = arch_bits.blkcnt_t;
79100pub const blksize_t = arch_bits.blksize_t;
80pub const clone = arch_bits.clone;
81101pub const dev_t = arch_bits.dev_t;
82102pub const ino_t = arch_bits.ino_t;
83103pub const mcontext_t = arch_bits.mcontext_t;
lib/std/os/linux/arm-eabi.zig+30-4
......@@ -98,10 +98,36 @@ pub fn syscall6(
9898 );
9999}
100100
101const CloneFn = *const fn (arg: usize) callconv(.C) u8;
102
103/// This matches the libc clone function.
104pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
101pub 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}
105131
106132pub fn restore() callconv(.Naked) noreturn {
107133 switch (@import("builtin").zig_backend) {
lib/std/os/linux/arm64.zig+29-4
......@@ -98,10 +98,35 @@ pub fn syscall6(
9898 );
9999}
100100
101const CloneFn = *const fn (arg: usize) callconv(.C) u8;
102
103/// This matches the libc clone function.
104pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
101pub 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}
105130
106131pub const restore = restore_rt;
107132
lib/std/os/linux/mips.zig+42-4
......@@ -190,10 +190,48 @@ pub fn syscall7(
190190 );
191191}
192192
193const CloneFn = *const fn (arg: usize) callconv(.C) u8;
194
195/// This matches the libc clone function.
196pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
193pub 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}
197235
198236pub fn restore() callconv(.Naked) noreturn {
199237 asm volatile (
lib/std/os/linux/powerpc.zig+65-4
......@@ -126,10 +126,71 @@ pub fn syscall6(
126126 );
127127}
128128
129const CloneFn = *const fn (arg: usize) callconv(.C) u8;
130
131/// This matches the libc clone function.
132pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
129pub 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}
133194
134195pub const restore = restore_rt;
135196
lib/std/os/linux/powerpc64.zig+45-4
......@@ -126,10 +126,51 @@ pub fn syscall6(
126126 );
127127}
128128
129const CloneFn = *const fn (arg: usize) callconv(.C) u8;
130
131/// This matches the libc clone function.
132pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
129pub 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}
133174
134175pub const restore = restore_rt;
135176
lib/std/os/linux/riscv32.zig+34-3
......@@ -95,9 +95,40 @@ pub fn syscall6(
9595 );
9696}
9797
98const CloneFn = *const fn (arg: usize) callconv(.C) u8;
99
100pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
98pub 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}
101132
102133pub const restore = restore_rt;
103134
lib/std/os/linux/riscv64.zig+34-3
......@@ -95,9 +95,40 @@ pub fn syscall6(
9595 );
9696}
9797
98const CloneFn = *const fn (arg: usize) callconv(.C) u8;
99
100pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
98pub 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}
101132
102133pub const restore = restore_rt;
103134
lib/std/os/linux/sparc64.zig+45-4
......@@ -178,10 +178,51 @@ pub fn syscall6(
178178 );
179179}
180180
181const CloneFn = *const fn (arg: usize) callconv(.C) u8;
182
183/// This matches the libc clone function.
184pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
181pub 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}
185226
186227pub const restore = restore_rt;
187228
lib/std/os/linux/thumb.zig+2
......@@ -141,6 +141,8 @@ pub fn syscall6(
141141 );
142142}
143143
144pub const clone = @import("arm-eabi.zig").clone;
145
144146pub fn restore() callconv(.Naked) noreturn {
145147 asm volatile (
146148 \\ mov r7, %[number]
lib/std/os/linux/x86.zig+42-4
......@@ -118,10 +118,48 @@ pub fn socketcall(call: usize, args: [*]const usize) usize {
118118 );
119119}
120120
121const CloneFn = *const fn (arg: usize) callconv(.C) u8;
122
123/// This matches the libc clone function.
124pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
121pub 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}
125163
126164pub fn restore() callconv(.Naked) noreturn {
127165 switch (@import("builtin").zig_backend) {
lib/std/os/linux/x86_64.zig+25-4
......@@ -100,10 +100,31 @@ pub fn syscall6(
100100 );
101101}
102102
103const CloneFn = *const fn (arg: usize) callconv(.C) u8;
104
105/// This matches the libc clone function.
106pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
103pub 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}
107128
108129pub const restore = restore_rt;
109130