|
@@ -1,6 +1,6 @@
|
|
-/* Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
|
|
+/* Copyright (C) 1996, 1997, 2000, 2003, 2005 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
This file is part of the GNU C Library.
|
|
- Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>, 1996.
|
|
+ Contributed by Ralf Baechle <ralf@linux-mips.org>, 1996.
|
|
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
modify it under the terms of the GNU Lesser General Public
|
|
@@ -21,35 +21,43 @@
|
|
and invokes a function in the right context after its all over. */
|
|
and invokes a function in the right context after its all over. */
|
|
|
|
|
|
#include <features.h>
|
|
#include <features.h>
|
|
-#include <asm/unistd.h>
|
|
|
|
-#include <sys/regdef.h>
|
|
|
|
-#define _ERRNO_H 1
|
|
|
|
-#include <bits/errno.h>
|
|
|
|
#include <sys/asm.h>
|
|
#include <sys/asm.h>
|
|
|
|
+#include <sysdep.h>
|
|
|
|
+#define _ERRNO_H 1
|
|
|
|
+#include <bits/errno.h>
|
|
|
|
+#ifdef RESET_PID
|
|
|
|
+#include <tls.h>
|
|
|
|
+#endif
|
|
|
|
|
|
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) */
|
|
+#define CLONE_VM 0x00000100
|
|
|
|
+#define CLONE_THREAD 0x00010000
|
|
|
|
+
|
|
|
|
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
|
|
|
|
+ void *parent_tidptr, void *tls, void *child_tidptr) */
|
|
|
|
|
|
.text
|
|
.text
|
|
-.globl clone ;
|
|
+#if _MIPS_SIM == _ABIO32
|
|
- .align 2;
|
|
+# define EXTRA_LOCALS 1
|
|
- .type clone,@function;
|
|
|
|
- .ent clone, 0;
|
|
|
|
-
|
|
|
|
-clone:
|
|
|
|
- .frame sp, 4*SZREG, sp
|
|
|
|
-#ifdef __PIC__
|
|
|
|
-#if _MIPS_SIM == _MIPS_SIM_ABI32
|
|
|
|
- .set noreorder
|
|
|
|
- .cpload $25
|
|
|
|
- .set reorder
|
|
|
|
- subu sp,32
|
|
|
|
- .cprestore 16
|
|
|
|
-#else /* N32 */
|
|
|
|
- PTR_SUBU sp,32 /* fn, arg, gp, pad */
|
|
|
|
- .cpsetup $25, 16, clone
|
|
|
|
-#endif /* N32 */
|
|
|
|
#else
|
|
#else
|
|
- subu sp,32
|
|
+# define EXTRA_LOCALS 0
|
|
|
|
+#endif
|
|
|
|
+LOCALSZ= 4
|
|
|
|
+FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
|
|
|
|
+GPOFF= FRAMESZ-(1*SZREG)
|
|
|
|
+NESTED(clone,4*SZREG,sp)
|
|
|
|
+#ifdef __PIC__
|
|
|
|
+ SETUP_GP
|
|
|
|
+#endif
|
|
|
|
+ PTR_SUBU sp, FRAMESZ
|
|
|
|
+ SETUP_GP64 (GPOFF, clone)
|
|
|
|
+#ifdef __PIC__
|
|
|
|
+ SAVE_GP (GPOFF)
|
|
|
|
+#endif
|
|
|
|
+#ifdef PROF
|
|
|
|
+ .set noat
|
|
|
|
+ move $1,ra
|
|
|
|
+ jal _mcount
|
|
|
|
+ .set at
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
@@ -58,64 +66,78 @@ clone:
|
|
beqz a0,L(error) /* No NULL function pointers. */
|
|
beqz a0,L(error) /* No NULL function pointers. */
|
|
beqz a1,L(error) /* No NULL stack pointers. */
|
|
beqz a1,L(error) /* No NULL stack pointers. */
|
|
|
|
|
|
-#if _MIPS_SIM != _MIPS_SIM_ABI32
|
|
|
|
- and a1,~(16-1) /* force alignment */
|
|
|
|
-#endif
|
|
|
|
PTR_SUBU a1,32 /* Reserve argument save space. */
|
|
PTR_SUBU a1,32 /* Reserve argument save space. */
|
|
PTR_S a0,0(a1) /* Save function pointer. */
|
|
PTR_S a0,0(a1) /* Save function pointer. */
|
|
PTR_S a3,PTRSIZE(a1) /* Save argument pointer. */
|
|
PTR_S a3,PTRSIZE(a1) /* Save argument pointer. */
|
|
|
|
+#ifdef RESET_PID
|
|
|
|
+ LONG_S a2,(PTRSIZE*2)(a1) /* Save clone flags. */
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
+ move a0,a2
|
|
|
|
+
|
|
|
|
+ /* Shuffle in the last three arguments - arguments 5, 6, and 7 to
|
|
|
|
+ this function, but arguments 3, 4, and 5 to the syscall. */
|
|
|
|
+#if _MIPS_SIM == _ABIO32
|
|
|
|
+ PTR_L a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp)
|
|
|
|
+ PTR_S a2,16(sp)
|
|
|
|
+ PTR_L a2,(FRAMESZ+16)(sp)
|
|
|
|
+ PTR_L a3,(FRAMESZ+PTRSIZE+16)(sp)
|
|
|
|
+#else
|
|
|
|
+ move a2,a4
|
|
|
|
+ move a3,a5
|
|
|
|
+ move a4,a6
|
|
|
|
+#endif
|
|
|
|
|
|
/* Do the system call */
|
|
/* Do the system call */
|
|
- move a0,a2
|
|
|
|
li v0,__NR_clone
|
|
li v0,__NR_clone
|
|
syscall
|
|
syscall
|
|
|
|
|
|
bnez a3,L(error)
|
|
bnez a3,L(error)
|
|
- beqz v0,L(__thread_start)
|
|
+ beqz v0,L(thread_start)
|
|
|
|
|
|
/* Successful return from the parent */
|
|
/* Successful return from the parent */
|
|
-#if _MIPS_SIM != _MIPS_SIM_ABI32
|
|
+ RESTORE_GP64
|
|
- .cpreturn
|
|
+ PTR_ADDU sp, FRAMESZ
|
|
-#endif
|
|
|
|
- PTR_ADDU sp,32
|
|
|
|
j $31 ; nop
|
|
j $31 ; nop
|
|
|
|
|
|
/* Something bad happened -- no child created */
|
|
/* Something bad happened -- no child created */
|
|
L(error):
|
|
L(error):
|
|
-#if _MIPS_SIM != _MIPS_SIM_ABI32
|
|
|
|
- .cpreturn
|
|
|
|
-#endif
|
|
|
|
- PTR_ADDU sp,32
|
|
|
|
-
|
|
|
|
- /* uClibc change -- start */
|
|
|
|
- move a0,v0 /* Pass return val to C function. */
|
|
|
|
- /* uClibc change -- stop */
|
|
|
|
-
|
|
|
|
#ifdef __PIC__
|
|
#ifdef __PIC__
|
|
PTR_LA t9,__syscall_error
|
|
PTR_LA t9,__syscall_error
|
|
|
|
+ RESTORE_GP64
|
|
|
|
+ PTR_ADDU sp, FRAMESZ
|
|
|
|
+ /* uClibc change -- start */
|
|
|
|
+ move a0,v0 /* Pass return val to C function. */
|
|
|
|
+ /* uClibc change -- stop */
|
|
jr t9
|
|
jr t9
|
|
#else
|
|
#else
|
|
|
|
+ RESTORE_GP64
|
|
|
|
+ PTR_ADDU sp, FRAMESZ
|
|
|
|
+ /* uClibc change -- start */
|
|
|
|
+ move a0,v0 /* Pass return val to C function. */
|
|
|
|
+ /* uClibc change -- stop */
|
|
j __syscall_error
|
|
j __syscall_error
|
|
#endif
|
|
#endif
|
|
- .end clone
|
|
+ END(clone)
|
|
|
|
|
|
/* Load up the arguments to the function. Put this block of code in
|
|
/* Load up the arguments to the function. Put this block of code in
|
|
its own function so that we can terminate the stack trace with our
|
|
its own function so that we can terminate the stack trace with our
|
|
debug info. */
|
|
debug info. */
|
|
|
|
|
|
- .globl __thread_start;
|
|
+ENTRY(__thread_start)
|
|
- .align 2;
|
|
+L(thread_start):
|
|
- .ent __thread_start, 0;
|
|
|
|
-
|
|
|
|
-__thread_start:
|
|
|
|
-L(__thread_start):
|
|
|
|
-#if _MIPS_SIM == _MIPS_SIM_ABI32
|
|
|
|
- .frame sp, 24, sp
|
|
|
|
/* cp is already loaded. */
|
|
/* cp is already loaded. */
|
|
- .cprestore 16
|
|
+ SAVE_GP (GPOFF)
|
|
-#endif
|
|
|
|
/* The stackframe has been created on entry of clone(). */
|
|
/* The stackframe has been created on entry of clone(). */
|
|
|
|
+
|
|
|
|
+#ifdef RESET_PID
|
|
|
|
+ /* Check and see if we need to reset the PID. */
|
|
|
|
+ LONG_L a0,(PTRSIZE*2)(sp)
|
|
|
|
+ and a1,a0,CLONE_THREAD
|
|
|
|
+ beqz a1,L(restore_pid)
|
|
|
|
+L(donepid):
|
|
|
|
+#endif
|
|
|
|
+
|
|
/* Restore the arg for user's function. */
|
|
/* Restore the arg for user's function. */
|
|
PTR_L t9,0(sp) /* Function pointer. */
|
|
PTR_L t9,0(sp) /* Function pointer. */
|
|
PTR_L a0,PTRSIZE(sp) /* Argument pointer. */
|
|
PTR_L a0,PTRSIZE(sp) /* Argument pointer. */
|
|
@@ -126,10 +148,26 @@ L(__thread_start):
|
|
/* Call _exit rather than doing it inline for breakpoint purposes. */
|
|
/* Call _exit rather than doing it inline for breakpoint purposes. */
|
|
move a0,v0
|
|
move a0,v0
|
|
#ifdef __PIC__
|
|
#ifdef __PIC__
|
|
- PTR_LA t9,_exit
|
|
+ PTR_LA t9,_exit
|
|
- jalr t9
|
|
+ jalr t9
|
|
#else
|
|
#else
|
|
- jal _exit
|
|
+ jal _exit
|
|
#endif
|
|
#endif
|
|
- .end __thread_start
|
|
+
|
|
|
|
+#ifdef RESET_PID
|
|
|
|
+L(restore_pid):
|
|
|
|
+ and a1,a0,CLONE_VM
|
|
|
|
+ li v0,-1
|
|
|
|
+ bnez a1,L(gotpid)
|
|
|
|
+ li v0,__NR_getpid
|
|
|
|
+ syscall
|
|
|
|
+L(gotpid):
|
|
|
|
+ READ_THREAD_POINTER(v1)
|
|
|
|
+ INT_S v0,PID_OFFSET(v1)
|
|
|
|
+ INT_S v0,TID_OFFSET(v1)
|
|
|
|
+ b L(donepid)
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ END(__thread_start)
|
|
|
|
+
|
|
weak_alias(clone, __clone)
|
|
weak_alias(clone, __clone)
|