1/* Copyright (C) 1996-2000,02,03,04,2005 Free Software Foundation, Inc.
2   Contributed by Richard Henderson (rth@tamu.edu)
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   <http://www.gnu.org/licenses/>.  */
17
18/* clone() is even more special than fork() as it mucks with stacks
19   and invokes a function in the right context after its all over.
20
21   Hacked up for uClibc by Erik Andersen <andersen@codepoet.org>
22*/
23
24#define _ERRNO_H	1
25#include <bits/errno.h>
26#include <sys/syscall.h>
27
28/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
29	     pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
30
31#define LINKAGE     4
32#define PTR_SIZE    4
33#define PARMS       LINKAGE        /* no space for saved regs */
34#define FUNC        PARMS
35#define STACK       FUNC+4
36#define FLAGS       STACK+PTR_SIZE
37#define ARG         FLAGS+4
38#define PTID        ARG+PTR_SIZE
39#define TLS         PTID+PTR_SIZE
40#define CTID        TLS+PTR_SIZE
41
42.text
43.global clone
44.type   clone,%function
45clone:
46	/* Sanity check arguments.  */
47	movl	$-EINVAL,%eax
48
49	/* no NULL function pointers */
50	movl	FUNC(%esp),%ecx
51#ifdef __PIC__
52	jecxz	__error
53#else
54	testl	%ecx,%ecx
55	jz	__error
56#endif
57
58	/* no NULL stack pointers */
59	movl	STACK(%esp),%ecx
60#ifdef __PIC__
61	jecxz	__error
62#else
63	testl	%ecx,%ecx
64	jz	__error
65#endif
66
67	/* Insert the argument onto the new stack.  Make sure the new
68	   thread is started with an alignment of (mod 16).  */
69	andl	$0xfffffff0, %ecx
70	subl	$28,%ecx
71	movl	ARG(%esp),%eax		/* no negative argument counts */
72	movl	%eax,12(%ecx)
73
74	/* Save the function pointer as the zeroth argument.
75	   It will be popped off in the child in the ebx frobbing below.  */
76	movl	FUNC(%esp),%eax
77	movl	%eax,8(%ecx)
78	/* Don't leak any information.  */
79	movl	$0,4(%ecx)
80
81	/* Do the system call */
82	pushl	%ebx
83	pushl	%esi
84	pushl	%edi
85	movl	TLS+12(%esp),%esi
86	movl	PTID+12(%esp),%edx
87	movl	FLAGS+12(%esp),%ebx
88	movl	CTID+12(%esp),%edi
89	movl	$__NR_clone,%eax
90	int	$0x80
91	popl	%edi
92	popl	%esi
93	popl	%ebx
94
95	test	%eax,%eax
96	jl	__error
97	jz	.Lthread_start
98	ret
99
100.Lthread_start:
101	/* Note: %esi is zero.  */
102	movl	%esi,%ebp	/* terminate the stack frame */
103	call	*%ebx
104#ifdef __PIC__
105	call	.Lhere
106.Lhere:
107	popl	%ebx
108	addl	$_GLOBAL_OFFSET_TABLE_+[.-.Lhere], %ebx
109#endif
110	movl	%eax, %ebx
111	movl	$__NR_exit, %eax
112	int	$0x80
113
114/* Need to indirect jump to syscall error
115 * or we end up with TEXTREL's
116 */
117__error:
118	jmp __syscall_error
119
120.size clone,.-clone
121weak_alias(clone, __clone)
122