Back to index

glibc  2.9
init-first.c
Go to the documentation of this file.
00001 /* Initialization code run first thing by the ELF startup code.  PowerPC/Hurd.
00002    Copyright (C) 1995-2001, 2002, 2003 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <assert.h>
00021 #include <hurd.h>
00022 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <string.h>
00025 #include <sysdep.h>
00026 #include <set-hooks.h>
00027 #include "hurdstartup.h"
00028 #include "hurdmalloc.h"            /* XXX */
00029 
00030 extern void __mach_init (void);
00031 extern void __init_misc (int, char **, char **);
00032 #ifdef USE_NONOPTION_FLAGS
00033 extern void __getopt_clean_environment (char **);
00034 #endif
00035 #ifndef SHARED
00036 extern void _dl_non_dynamic_init (void) internal_function;
00037 #endif
00038 extern void __libc_global_ctors (void);
00039 
00040 unsigned int __hurd_threadvar_max;
00041 unsigned long int __hurd_threadvar_stack_offset;
00042 unsigned long int __hurd_threadvar_stack_mask;
00043 
00044 #ifndef SHARED
00045 int __libc_enable_secure;
00046 #endif
00047 int __libc_multiple_libcs attribute_hidden = 1;
00048 
00049 extern int __libc_argc attribute_hidden;
00050 extern char **__libc_argv attribute_hidden;
00051 extern char **_dl_argv;
00052 
00053 void *(*_cthread_init_routine) (void); /* Returns new SP to use.  */
00054 void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__));
00055 
00056 #ifndef SHARED
00057 static unsigned int return_address;  /* Make init1 return to _start.  */
00058 #endif
00059 
00060 /* Things that want to be run before _hurd_init or much anything else.
00061    Importantly, these are called before anything tries to use malloc.  */
00062 DEFINE_HOOK (_hurd_preinit_hook, (void));
00063 
00064 
00065 /* We call this once the Hurd magic is all set up and we are ready to be a
00066    Posixoid program.  This does the same things the generic version does.  */
00067 static void internal_function
00068 posixland_init (int argc, char **argv, char **envp)
00069 {
00070   asm ("li 3,0xbb; .long 0");
00071   __libc_argc = argc;
00072   __libc_argv = argv;
00073   __environ = envp;
00074 
00075 #ifndef SHARED
00076   _dl_non_dynamic_init ();
00077 #endif
00078   __init_misc (argc, argv, envp);
00079 
00080 #ifdef USE_NONOPTION_FLAGS
00081   /* This is a hack to make the special getopt in GNU libc working.  */
00082   __getopt_clean_environment (__environ);
00083 #endif
00084 
00085 #ifdef SHARED
00086   __libc_global_ctors ();
00087 #endif
00088 }
00089 
00090 
00091 static void
00092 init1 (int *data)
00093 {
00094   int argc = *data;
00095   char **argv = (char **) &data[1];
00096   char **envp = &argv[argc + 1];
00097   struct hurd_startup_data *d;
00098 
00099   while (*envp)
00100     ++envp;
00101   d = (void *) ++envp;
00102 
00103   /* If we are the bootstrap task started by the kernel,
00104      then after the environment pointers there is no Hurd
00105      data block; the argument strings start there.  */
00106   /* OSF Mach starts the bootstrap task with argc == 0.
00107      XXX This fails if a non-bootstrap task gets started
00108      with argc == 0.  */
00109   if (argc && (void *) d != argv[0])
00110     {
00111       _hurd_init_dtable = d->dtable;
00112       _hurd_init_dtablesize = d->dtablesize;
00113 
00114 #if 0  /* We can't free the old stack because it contains the argument strings.  */
00115       {
00116        /* Check if the stack we are now on is different from
00117           the one described by _hurd_stack_{base,size}.  */
00118 
00119        char dummy;
00120        const vm_address_t newsp = (vm_address_t) &dummy;
00121 
00122        if (d->stack_size != 0 && (newsp < d->stack_base ||
00123                                newsp - d->stack_base > d->stack_size))
00124          /* The new stack pointer does not intersect with the
00125             stack the exec server set up for us, so free that stack.  */
00126          __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
00127       }
00128 #endif
00129     }
00130 
00131   if (argc && (void *) d != argv[0] && (d->portarray || d->intarray))
00132     /* Initialize library data structures, start signal processing, etc.  */
00133     _hurd_init (d->flags, argv,
00134               d->portarray, d->portarraysize,
00135               d->intarray, d->intarraysize);
00136 
00137 #ifndef SHARED
00138   __libc_enable_secure = d->flags & EXEC_SECURE;
00139 #endif
00140 }
00141 
00142 
00143 static inline void
00144 init (int *data)
00145 {
00146   int argc = *data;
00147   char **argv = (void *) (data + 1);
00148   char **envp = &argv[argc + 1];
00149   struct hurd_startup_data *d;
00150   unsigned long int threadvars[_HURD_THREADVAR_MAX];
00151 
00152   /* Provide temporary storage for thread-specific variables on the startup
00153      stack so the cthreads initialization code can use them for malloc et al,
00154      or so we can use malloc below for the real threadvars array.  */
00155   memset (threadvars, 0, sizeof threadvars);
00156   __hurd_threadvar_stack_offset = (unsigned long int) threadvars;
00157 
00158   while (*envp)
00159     ++envp;
00160   d = (void *) ++envp;
00161 
00162   /* The user might have defined a value for this, to get more variables.
00163      Otherwise it will be zero on startup.  We must make sure it is set
00164      properly before before cthreads initialization, so cthreads can know
00165      how much space to leave for thread variables.  */
00166   if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
00167     __hurd_threadvar_max = _HURD_THREADVAR_MAX;
00168 
00169 
00170   /* After possibly switching stacks, call `init1' (above) with the user
00171      code as the return address, and the argument data immediately above
00172      that on the stack.  */
00173 
00174   if (_cthread_init_routine)
00175     {
00176       /* Initialize cthreads, which will allocate us a new stack to run on.  */
00177       void *newsp = (*_cthread_init_routine) ();
00178       struct hurd_startup_data *od;
00179 #ifdef SHARED
00180       void *oldsp;
00181       unsigned int i, data_offset;
00182 #endif
00183 
00184       /* Copy per-thread variables from that temporary
00185         area onto the new cthread stack.  */
00186       memcpy (__hurd_threadvar_location_from_sp (0, newsp),
00187              threadvars, sizeof threadvars);
00188 
00189       /* Copy the argdata from the old stack to the new one.  */
00190       newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
00191                     (char *) d - (char *) data);
00192 
00193 #ifdef SHARED
00194       /* And readjust the dynamic linker's idea of where the argument
00195          vector lives.  */
00196       assert (_dl_argv == argv);
00197       _dl_argv = (void *) ((int *) newsp + 1);
00198 #endif
00199 
00200       /* Set up the Hurd startup data block immediately following
00201         the argument and environment pointers on the new stack.  */
00202       od = (newsp + ((char *) d - (char *) data));
00203       if (!argc || (void *) argv[0] == d)
00204        /* We were started up by the kernel with arguments on the stack.
00205           There is no Hurd startup data, so zero the block.  */
00206        memset (od, 0, sizeof *od);
00207       else
00208        /* Copy the Hurd startup data block to the new stack.  */
00209        *od = *d;
00210 
00211 #ifndef SHARED
00212       asm ("mtlr %0; mr 1,%1; li 0,0; mr 3,%1; stwu 0,-16(1); b init1"
00213           : : "r" (return_address), "r" (newsp));
00214       (void) init1;  /* To avoid `defined but not used' warning.  */
00215       /* NOTREACHED */
00216 #else
00217       /* Copy the rest of the stack.  Don't call a function to do that,
00218         because that will alter the current stack.  */
00219       asm ("mr %0,1" : "=r" (oldsp));
00220       data_offset = (unsigned int) data - (unsigned int) oldsp;
00221       newsp -= data_offset;
00222       for (i = 0; i < data_offset / 4; i++)
00223         ((unsigned int *)newsp)[i] = ((unsigned int *)oldsp)[i];
00224 
00225       /* Relocate stack frames.  */
00226       {
00227        unsigned int *oldframe0 = (unsigned int *)oldsp;
00228        unsigned int *oldframe1 = *(unsigned int **)oldframe0;
00229        unsigned int *oldframe2 = *(unsigned int **)oldframe1;
00230        unsigned int *newframe0 = (unsigned int *)newsp;
00231        unsigned int *newframe1 = newframe0 + (unsigned int)(oldframe1 - oldframe0);
00232        unsigned int *newframe2 = newframe1 + (unsigned int)(oldframe2 - oldframe1);
00233        *(unsigned int **)newframe0 = newframe1;
00234        *(unsigned int **)newframe1 = newframe2;
00235       }
00236 
00237       asm ("mr 1,%0; mr 31,%0" : : "r" (newsp));  /* XXX */
00238       init1 (newsp + data_offset);
00239 #endif
00240     }
00241   else
00242     {
00243       /* We are not using cthreads, so we will have just a single allocated
00244         area for the per-thread variables of the main user thread.  */
00245       unsigned long int *array;
00246       unsigned int i;
00247 
00248       array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
00249       if (array == NULL)
00250        __libc_fatal ("Can't allocate single-threaded thread variables.");
00251 
00252       /* Copy per-thread variables from the temporary array into the
00253         newly malloc'd space.  */
00254       memcpy (array, threadvars, sizeof threadvars);
00255       __hurd_threadvar_stack_offset = (unsigned long int) array;
00256       for (i = _HURD_THREADVAR_MAX; i < __hurd_threadvar_max; ++i)
00257        array[i] = 0;
00258 
00259 #ifndef SHARED
00260       asm ("mr 3,%0; mtlr %1; addi 1,3,-16; b init1"
00261           : : "r" (data), "r" (return_address));
00262       /* NOTREACHED */
00263 #else
00264       init1 (data);
00265 #endif
00266     }
00267 }
00268 
00269 
00270 /* Do the first essential initializations that must precede all else.  */
00271 static inline void
00272 first_init (void)
00273 {
00274   /* Initialize data structures so we can do RPCs.  */
00275   __mach_init ();
00276 
00277   RUN_HOOK (_hurd_preinit_hook, ());
00278 }
00279 
00280 #ifdef SHARED
00281 /* This function is called specially by the dynamic linker to do early
00282    initialization of the shared C library before normal initializers
00283    expecting a Posixoid environment can run.  It gets called with the
00284    stack set up just as the user will see it, so it can switch stacks.  */
00285 
00286 void
00287 _dl_init_first (int argc, ...)
00288 {
00289   asm ("li 3,0xaa; .long 0");
00290   first_init ();
00291 
00292   init (&argc);
00293 }
00294 #endif
00295 
00296 
00297 #ifdef SHARED
00298 /* The regular posixland initialization is what goes into libc's
00299    normal initializer.  */
00300 /* NOTE!  The linker notices the magical name `_init' and sets the DT_INIT
00301    pointer in the dynamic section based solely on that.  It is convention
00302    for this function to be in the `.init' section, but the symbol name is
00303    the only thing that really matters!!  */
00304 strong_alias (posixland_init, _init);
00305 
00306 
00307 void
00308 __libc_init_first (int argc, char **argv, char **envp)
00309 {
00310   /* Everything was done in the shared library initializer, _init.  */
00311 }
00312 #else
00313 strong_alias (posixland_init, __libc_init_first);
00314 
00315 
00316 void
00317 _hurd_stack_setup (int *data)
00318 {
00319   register unsigned int address;
00320   asm ("mflr %0" : "=r" (address));
00321   return_address = address;
00322 
00323   first_init ();
00324 
00325   _hurd_startup ((void **) data, &init);
00326 }
00327 #endif
00328 
00329 
00330 /* This function is defined here so that if this file ever gets into
00331    ld.so we will get a link error.  Having this file silently included
00332    in ld.so causes disaster, because the _init definition above will
00333    cause ld.so to gain an init function, which is not a cool thing. */
00334 
00335 void
00336 _dl_start (void)
00337 {
00338   abort ();
00339 }