diff options
Diffstat (limited to 'libc/sysdeps/linux/arc/clone.S')
-rw-r--r-- | libc/sysdeps/linux/arc/clone.S | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/libc/sysdeps/linux/arc/clone.S b/libc/sysdeps/linux/arc/clone.S new file mode 100644 index 000000000..79ebd065a --- /dev/null +++ b/libc/sysdeps/linux/arc/clone.S @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#include <asm/errno.h> +#include <sys/syscall.h> +#include <sysdep.h> + +; Per man, libc clone( ) is as follows +; +; int clone(int (*fn)(void *), void *child_stack, +; int flags, void *arg, ... +; /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */); +; +; NOTE: I'm assuming that the last 3 args are NOT var-args and in case all +; 3 are not relevant, caller will nevertheless pass those as NULL. +; Current (Jul 2012) upstream powerpc/clone.S assumes similarly. +; Our LTP (from 2007) doesn't seem to have tests to prove otherwise + +; clone syscall in kernel +; +; int sys_clone(unsigned long clone_flags, unsigned long newsp, +; int __user *parent_tidptr, void *tls, +; int __user *child_tidptr) + + +ENTRY(clone) + cmp r0, 0 ; @fn can't be NULL + cmp.ne r1, 0 ; @child_stack can't be NULL + bz .L__sys_err + + ; @fn and @args needed after the syscall for child + ; However r3 containing @arg will be clobbered BEFORE syscall + ; r0 containg @fn will be clobbered AFTER syscall (with ret val) + mov r10, r0 + mov r11, r3 + + ; adjust libc args for syscall + mov r0, r2 ; libc @flags is 1st syscall arg + mov r2, r4 ; libc @ptid + mov r3, r5 ; libc @tls + mov r4, r6 ; libc @ctid + mov r8, __NR_clone + ARC_TRAP_INSN + + cmp r0, 0 ; return code : 0 new process, !0 parent + blt .L__sys_err2 ; < 0 (signed) error + jnz [blink] ; Parent returns + + ; child jumps off to @fn with @arg as argument + j.d [r10] + mov r0, r11 + + ; falls thru to _exit() with result from @fn (already in r0) + b HIDDEN_JUMPTARGET(_exit) + +.L__sys_err: + mov r0, -EINVAL +.L__sys_err2: + ; (1) No need to make -ve kernel error code as positive errno + ; __syscall_error expects the -ve error code returned by kernel + ; (2) r0 still had orig -ve kernel error code + ; (3) Tail call to __syscall_error so we dont have to come back + ; here hence instead of jmp-n-link (reg push/pop) we do jmp + ; (4) No need to route __syscall_error via PLT, B is inherently + ; position independent + b __syscall_error +END(clone) +libc_hidden_def(clone) |