diff options
Diffstat (limited to 'libc/sysdeps/linux/mips/clone.S')
| -rw-r--r-- | libc/sysdeps/linux/mips/clone.S | 148 |
1 files changed, 99 insertions, 49 deletions
diff --git a/libc/sysdeps/linux/mips/clone.S b/libc/sysdeps/linux/mips/clone.S index 21cb8ec61..8486da783 100644 --- a/libc/sysdeps/linux/mips/clone.S +++ b/libc/sysdeps/linux/mips/clone.S @@ -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. - 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 modify it under the terms of the GNU Lesser General Public @@ -20,86 +20,121 @@ /* clone() is even more special than fork() as it mucks with stacks and invokes a function in the right context after its all over. */ -#include <asm/unistd.h> -#include <sys/regdef.h> +#include <sys/asm.h> +#include <sysdep.h> #define _ERRNO_H 1 #include <bits/errno.h> -#include <asm/asm.h> +#ifdef RESET_PID +#include <tls.h> +#endif + +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) */ +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + void *parent_tidptr, void *tls, void *child_tidptr) */ .text -.globl __clone ; - .align 2; - .type __clone,@function; - .ent __clone, 0; - -__clone: - .frame sp, 4*SZREG, sp -#ifdef __PIC__ - .set noreorder - .cpload $25 - .set reorder - subu sp,32 - .cprestore 16 +#if _MIPS_SIM == _ABIO32 +# define EXTRA_LOCALS 1 #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 /* Sanity check arguments. */ li v0,EINVAL - beqz a0,error /* No NULL function pointers. */ - beqz a1,error /* No NULL stack pointers. */ + beqz a0,L(error) /* No NULL function pointers. */ + beqz a1,L(error) /* No NULL stack pointers. */ + + PTR_SUBU a1,32 /* Reserve argument save space. */ + PTR_S a0,0(a1) /* Save function pointer. */ + PTR_S a3,PTRSIZE(a1) /* Save argument pointer. */ +#ifdef RESET_PID + LONG_S a2,(PTRSIZE*2)(a1) /* Save clone flags. */ +#endif - subu a1,32 /* Reserve argument save space. */ - sw a0,0(a1) /* Save function pointer. */ - sw a3,4(a1) /* Save argument pointer. */ + 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 */ - move a0,a2 li v0,__NR_clone syscall - bnez a3,error - beqz v0,__thread_start + bnez a3,L(error) + beqz v0,L(thread_start) /* Successful return from the parent */ - addiu sp,32 - j $31 ; nop + RESTORE_GP64 + PTR_ADDU sp, FRAMESZ + j ra + nop /* Something bad happened -- no child created */ -error: - addiu sp,32 - - /* uClibc change -- start */ - move a0,v0 /* Pass return val to C function. */ - /* uClibc change -- stop */ - +L(error): #ifdef __PIC__ - la t9,__syscall_error + PTR_LA t9,__syscall_error + RESTORE_GP64 + PTR_ADDU sp, FRAMESZ jr t9 #else + RESTORE_GP64 + PTR_ADDU sp, FRAMESZ j __syscall_error #endif - .end __clone + END(__clone) /* 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 debug info. */ -.globl __thread_start; - .align 2; - .ent __thread_start, 0; - -__thread_start: +LEAF(__thread_start) +L(thread_start): /* cp is already loaded. */ - .cprestore 16 + SAVE_GP (GPOFF) /* 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. */ - lw t9,0(sp) /* Function pointer. */ - lw a0,4(sp) /* Argument pointer. */ + PTR_L t9,0(sp) /* Function pointer. */ + PTR_L a0,PTRSIZE(sp) /* Argument pointer. */ /* Call the user's function. */ jal t9 @@ -107,12 +142,27 @@ __thread_start: /* Call _exit rather than doing it inline for breakpoint purposes. */ move a0,v0 #ifdef __PIC__ - la t9,_exit + PTR_LA t9,_exit jalr t9 #else jal _exit #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 clone; clone = __clone |
