1/* clone() implementation for ARC.
2 Copyright (C) 2020-2024 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
20#include <sysdep.h>
21#define _ERRNO_H 1
22#include <bits/errno.h>
23
24/* int clone(int (*fn)(void *), void *child_stack,
25 int flags, void *arg, ...
26 < pid_t *ptid, struct user_desc *tls, pid_t *ctid > );
27
28 NOTE: I'm assuming that the last 3 args are NOT var-args and in case all
29 3 are not relevant, caller will nevertheless pass those as NULL.
30
31 clone syscall in kernel (ABI: CONFIG_CLONE_BACKWARDS)
32
33 int sys_clone(unsigned long int clone_flags,
34 unsigned long int newsp,
35 int __user *parent_tidptr,
36 void *tls,
37 int __user *child_tidptr). */
38
39ENTRY (__clone)
40 cmp r0, 0 /* @fn can't be NULL. */
41 and r1,r1,-4 /* @child_stack be 4 bytes aligned per ABI. */
42 cmp.ne r1, 0 /* @child_stack can't be NULL. */
43 bz L (__sys_err)
44
45 /* save some of the orig args
46 r0 containing @fn will be clobbered AFTER syscall (with ret val)
47 rest are clobbered BEFORE syscall due to different arg ordering. */
48 mov r10, r0 /* @fn. */
49 mov r11, r3 /* @args. */
50 mov r12, r2 /* @clone_flags. */
51 mov r9, r5 /* @tls. */
52
53 /* adjust libc args for syscall. */
54
55 mov r0, r2 /* libc @flags is 1st syscall arg. */
56 mov r2, r4 /* libc @ptid. */
57 mov r3, r5 /* libc @tls. */
58 mov r4, r6 /* libc @ctid. */
59 mov r8, __NR_clone
60 ARC_TRAP_INSN
61
62 cmp r0, 0 /* return code : 0 new process, !0 parent. */
63 beq thread_start_clone
64 blt L (__sys_err2) /* < 0 (signed) error. */
65 j [blink] /* Parent returns. */
66
67L (__sys_err):
68 mov r0, -EINVAL
69L (__sys_err2):
70 /* (1) No need to make -ve kernel error code as positive errno
71 __syscall_error expects the -ve error code returned by kernel
72 (2) r0 still had orig -ve kernel error code
73 (3) Tail call to __syscall_error so we dont have to come back
74 here hence instead of jmp-n-link (reg push/pop) we do jmp
75 (4) No need to route __syscall_error via PLT, B is inherently
76 position independent. */
77 b __syscall_error
78PSEUDO_END (__clone)
79
80
81 .align 4
82 .type thread_start_clone, %function
83thread_start_clone:
84 cfi_startproc
85 /* Terminate call stack by noting ra is undefined. */
86 cfi_undefined (blink)
87
88 /* Child jumps off to @fn with @arg as argument. */
89 jl.d [r10]
90 mov r0, r11
91
92 /* exit() with result from @fn (already in r0). */
93 mov r8, __NR_exit
94 ARC_TRAP_INSN
95
96 /* In case it ever came back. */
97 flag 1
98
99 cfi_endproc
100 .size thread_start_clone, .-thread_start_clone
101
102libc_hidden_def (__clone)
103weak_alias (__clone, clone)
104

source code of glibc/sysdeps/unix/sysv/linux/arc/clone.S