2.9
[glibc/nacl-glibc.git] / sysdeps / unix / sysv / linux / i386 / clone.S
blobf73a4b5195720cd319c0e9c6679a268868b1ee35
1 /* Copyright (C) 1996-2000,02,03,04,2005 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Richard Henderson (rth@tamu.edu)
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.
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.
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.  */
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.  */
23 #include <sysdep.h>
24 #define _ERRNO_H        1
25 #include <bits/errno.h>
26 #include <asm-syntax.h>
27 #include <bp-sym.h>
28 #include <bp-asm.h>
30 /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
31              pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
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
42 #define __NR_clone 120
43 #define SYS_clone 120
45 #define CLONE_VM        0x00000100
46 #define CLONE_THREAD    0x00010000
48         .text
49 ENTRY (BP_SYM (__clone))
50         /* Sanity check arguments.  */
51         movl    $-EINVAL,%eax
52         movl    FUNC(%esp),%ecx         /* no NULL function pointers */
53 #ifdef PIC
54         jecxz   SYSCALL_ERROR_LABEL
55 #else
56         testl   %ecx,%ecx
57         jz      SYSCALL_ERROR_LABEL
58 #endif
59         movl    STACK(%esp),%ecx        /* no NULL stack pointers */
60 #ifdef PIC
61         jecxz   SYSCALL_ERROR_LABEL
62 #else
63         testl   %ecx,%ecx
64         jz      SYSCALL_ERROR_LABEL
65 #endif
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)
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 #ifndef RESET_PID
81         movl    $0,(%ecx)
82 #endif
84         /* Do the system call */
85         pushl   %ebx
86         cfi_adjust_cfa_offset (4)
87         pushl   %esi
88         cfi_adjust_cfa_offset (4)
89         pushl   %edi
90         cfi_adjust_cfa_offset (4)
92         movl    TLS+12(%esp),%esi
93         cfi_rel_offset (esi, 4)
94         movl    PTID+12(%esp),%edx
95         movl    FLAGS+12(%esp),%ebx
96         cfi_rel_offset (ebx, 8)
97         movl    CTID+12(%esp),%edi
98         cfi_rel_offset (edi, 0)
99         movl    $SYS_ify(clone),%eax
101 #ifdef RESET_PID
102         /* Remember the flag value.  */
103         movl    %ebx, (%ecx)
104 #endif
106         /* End FDE now, because in the child the unwind info will be
107            wrong.  */
108         cfi_endproc
110         int     $0x80
111         popl    %edi
112         popl    %esi
113         popl    %ebx
115         test    %eax,%eax
116         jl      SYSCALL_ERROR_LABEL
117         jz      L(thread_start)
119 L(pseudo_end):
120         ret
122 L(thread_start):
123         cfi_startproc;
124         /* Clearing frame pointer is insufficient, use CFI.  */
125         cfi_undefined (eip);
126         /* Note: %esi is zero.  */
127         movl    %esi,%ebp       /* terminate the stack frame */
128 #ifdef RESET_PID
129         testl   $CLONE_THREAD, %edi
130         je      L(newpid)
131 L(haspid):
132 #endif
133         call    *%ebx
134 #ifdef PIC
135         call    L(here)
136 L(here):
137         popl    %ebx
138         addl    $_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx
139 #endif
140         movl    %eax, %ebx
141         movl    $SYS_ify(exit), %eax
142         ENTER_KERNEL
144 #ifdef RESET_PID
145         .subsection 2
146 L(newpid):
147         testl   $CLONE_VM, %edi
148         movl    $-1, %eax
149         jne     L(nomoregetpid)
150         movl    $SYS_ify(getpid), %eax
151         ENTER_KERNEL
152 L(nomoregetpid):
153         movl    %eax, %gs:PID
154         movl    %eax, %gs:TID
155         jmp     L(haspid)
156         .previous
157 #endif
158         cfi_endproc;
160         cfi_startproc
161 PSEUDO_END (BP_SYM (__clone))
163 weak_alias (BP_SYM (__clone), BP_SYM (clone))