1/* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3   Contributed by Richard Henderson (rth@tamu.edu)
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, write to the Free
17   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18   02111-1307 USA.  */
19
20/* clone() is even more special than fork() as it mucks with stacks
21   and invokes a function in the right context after its all over.  */
22
23#include <sysdep.h>
24#define _ERRNO_H	1
25#include <bits/errno.h>
26#include <asm/unistd.h>
27#include <bp-sym.h>
28#include <bp-asm.h>
29
30/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
31
32#define PARMS	LINKAGE		/* no space for saved regs */
33#define FUNC	PARMS
34#define STACK	FUNC+4
35#define FLAGS	STACK+PTR_SIZE
36#define ARG	FLAGS+4
37
38        .text
39ENTRY (BP_SYM (__clone))
40	/* Sanity check arguments.  */
41	movl	$-EINVAL,%eax
42	movl	FUNC(%esp),%ecx		/* no NULL function pointers */
43#ifdef PIC
44	jecxz	SYSCALL_ERROR_LABEL
45#else
46	testl	%ecx,%ecx
47	jz	SYSCALL_ERROR_LABEL
48#endif
49	movl	STACK(%esp),%ecx	/* no NULL stack pointers */
50#ifdef PIC
51	jecxz	SYSCALL_ERROR_LABEL
52#else
53	testl	%ecx,%ecx
54	jz	SYSCALL_ERROR_LABEL
55#endif
56
57	/* Insert the argument onto the new stack.  */
58	subl	$8,%ecx
59	movl	ARG(%esp),%eax		/* no negative argument counts */
60	movl	%eax,4(%ecx)
61
62	/* Save the function pointer as the zeroth argument.
63	   It will be popped off in the child in the ebx frobbing below.  */
64	movl	FUNC(%esp),%eax
65	movl	%eax,0(%ecx)
66
67	/* Do the system call */
68	pushl	%ebx
69	movl	FLAGS+4(%esp),%ebx
70	movl	$SYS_ify(clone),%eax
71	int	$0x80
72	popl	%ebx
73
74	test	%eax,%eax
75	jl	SYSCALL_ERROR_LABEL
76	jz	thread_start
77
78L(pseudo_end):
79	ret
80
81thread_start:
82	subl	%ebp,%ebp	/* terminate the stack frame */
83	call	*%ebx
84#ifdef PIC
85	call	L(here)
86L(here):
87	popl	%ebx
88	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx
89#endif
90	pushl	%eax
91	call	JUMPTARGET (_exit)
92
93PSEUDO_END (BP_SYM (__clone))
94
95weak_alias (BP_SYM (__clone), BP_SYM (clone))
96