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.  Alpha/Hurd.
00002    Copyright (C) 1995,96,97,98,99,2000,01,02,03 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 /* Things that want to be run before _hurd_init or much anything else.
00057    Importantly, these are called before anything tries to use malloc.  */
00058 DEFINE_HOOK (_hurd_preinit_hook, (void));
00059 
00060 
00061 /* We call this once the Hurd magic is all set up and we are ready to be a
00062    Posixoid program.  This does the same things the generic version does.  */
00063 static void
00064 posixland_init (int argc, char **argv, char **envp)
00065 {
00066   __libc_argc = argc;
00067   __libc_argv = argv;
00068   __environ = envp;
00069 
00070 #ifndef SHARED
00071   _dl_non_dynamic_init ();
00072 #endif
00073   __init_misc (argc, argv, envp);
00074 
00075 #ifdef USE_NONOPTION_FLAGS
00076   /* This is a hack to make the special getopt in GNU libc working.  */
00077   __getopt_clean_environment (envp);
00078 #endif
00079 
00080 #ifdef SHARED
00081   __libc_global_ctors ();
00082 #endif
00083 }
00084 
00085 
00086 static void
00087 init1 (intptr_t *data)
00088 {
00089   int argc = (intptr_t) *data;
00090   char **argv = (char **) &data[1];
00091   char **envp = &argv[argc + 1];
00092   struct hurd_startup_data *d;
00093 
00094   while (*envp)
00095     ++envp;
00096   d = (void *) ++envp;
00097 
00098   /* If we are the bootstrap task started by the kernel,
00099      then after the environment pointers there is no Hurd
00100      data block; the argument strings start there.  */
00101   /* OSF Mach starts the bootstrap task with argc == 0.
00102      XXX This fails if a non-bootstrap task gets started
00103      with argc == 0.  */
00104   if (argc && (void *) d != argv[0])
00105     {
00106       _hurd_init_dtable = d->dtable;
00107       _hurd_init_dtablesize = d->dtablesize;
00108 
00109       {
00110        /* Check if the stack we are now on is different from
00111           the one described by _hurd_stack_{base,size}.  */
00112 
00113        char dummy;
00114        const vm_address_t newsp = (vm_address_t) &dummy;
00115 
00116        if (d->stack_size != 0 && (newsp < d->stack_base ||
00117                                newsp - d->stack_base > d->stack_size))
00118          /* The new stack pointer does not intersect with the
00119             stack the exec server set up for us, so free that stack.  */
00120          __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
00121       }
00122     }
00123 
00124   if ((void *) d != argv[0] && (d->portarray || d->intarray))
00125     /* Initialize library data structures, start signal processing, etc.  */
00126     _hurd_init (d->flags, argv,
00127               d->portarray, d->portarraysize,
00128               d->intarray, d->intarraysize);
00129 
00130 #ifndef SHARED
00131   __libc_enable_secure = d->flags & EXEC_SECURE;
00132 #endif
00133 }
00134 
00135 
00136 static inline void
00137 init (intptr_t *data)
00138 {
00139   int argc = *data;
00140   char **argv = (void *) (data + 1);
00141   char **envp = &argv[argc + 1];
00142   struct hurd_startup_data *d;
00143   unsigned long int threadvars[_HURD_THREADVAR_MAX];
00144 
00145   /* Provide temporary storage for thread-specific variables on the
00146      startup stack so the cthreads initialization code can use them
00147      for malloc et al, or so we can use malloc below for the real
00148      threadvars array.  */
00149   memset (threadvars, 0, sizeof threadvars);
00150   __hurd_threadvar_stack_offset = (unsigned long int) threadvars;
00151 
00152   /* Since the cthreads initialization code uses malloc, and the
00153      malloc initialization code needs to get at the environment, make
00154      sure we can find it.  We'll need to do this again later on since
00155      switching stacks changes the location where the environment is
00156      stored.  */
00157   __environ = envp;
00158 
00159   while (*envp)
00160     ++envp;
00161   d = (void *) ++envp;
00162 
00163   /* The user might have defined a value for this, to get more variables.
00164      Otherwise it will be zero on startup.  We must make sure it is set
00165      properly before before cthreads initialization, so cthreads can know
00166      how much space to leave for thread variables.  */
00167   if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
00168     __hurd_threadvar_max = _HURD_THREADVAR_MAX;
00169 
00170 
00171   /* After possibly switching stacks, call `init1' (above) with the user
00172      code as the return address, and the argument data immediately above
00173      that on the stack.  */
00174 
00175   if (_cthread_init_routine)
00176     {
00177       /* Initialize cthreads, which will allocate us a new stack to run on.  */
00178       void *newsp = (*_cthread_init_routine) ();
00179       struct hurd_startup_data *od;
00180 
00181       void switch_stacks (void);
00182 
00183       /* Copy per-thread variables from that temporary
00184         area onto the new cthread stack.  */
00185       memcpy (__hurd_threadvar_location_from_sp (0, newsp),
00186              threadvars, sizeof threadvars);
00187 
00188       /* Copy the argdata from the old stack to the new one.  */
00189       newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
00190                     (char *) d - (char *) data);
00191 
00192 #ifdef SHARED
00193       /* And readjust the dynamic linker's idea of where the argument
00194          vector lives.  */
00195       assert (_dl_argv == argv);
00196       _dl_argv = (void *) ((int *) newsp + 1);
00197 #endif
00198 
00199       /* Set up the Hurd startup data block immediately following
00200         the argument and environment pointers on the new stack.  */
00201       od = (newsp + ((char *) d - (char *) data));
00202       if ((void *) argv[0] == d)
00203        /* We were started up by the kernel with arguments on the stack.
00204           There is no Hurd startup data, so zero the block.  */
00205        memset (od, 0, sizeof *od);
00206       else
00207        /* Copy the Hurd startup data block to the new stack.  */
00208        *od = *d;
00209 
00210       /*
00211          Force NEWSP into sp and &init1 into pv, then branch to pv (call init1).
00212        */
00213       asm volatile ("lda $30,0(%0); lda $27,0(%1); jsr $26,($27)"
00214                   : : "r" (newsp), "r" (&init1));
00215     }
00216   else
00217     {
00218       /* We are not using cthreads, so we will have just a single allocated
00219         area for the per-thread variables of the main user thread.  */
00220       unsigned long int *array;
00221       unsigned int i;
00222 
00223       array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
00224       if (array == NULL)
00225        __libc_fatal ("Can't allocate single-threaded thread variables.");
00226 
00227       /* Copy per-thread variables from the temporary array into the
00228         newly malloc'd space.  */
00229       memcpy (array, threadvars, sizeof threadvars);
00230       __hurd_threadvar_stack_offset = (unsigned long int) array;
00231       for (i = _HURD_THREADVAR_MAX; i < __hurd_threadvar_max; ++i)
00232        array[i] = 0;
00233 
00234       init1 (data);
00235     }
00236 }
00237 
00238 
00239 /* Do the first essential initializations that must precede all else.  */
00240 static inline void
00241 first_init (void)
00242 {
00243   /* Initialize data structures so we can do RPCs.  */
00244   __mach_init ();
00245 
00246   RUN_HOOK (_hurd_preinit_hook, ());
00247 }
00248 
00249 #ifdef SHARED
00250 /* This function is called specially by the dynamic linker to do early
00251    initialization of the shared C library before normal initializers
00252    expecting a Posixoid environment can run.  It gets called with the
00253    stack set up just as the user will see it, so it can switch stacks.  */
00254 
00255 void
00256 _dl_init_first (intptr_t argc, ...)
00257 {
00258   first_init ();
00259 
00260   init (&argc);
00261 }
00262 #endif
00263 
00264 
00265 #ifdef SHARED
00266 /* The regular posixland initialization is what goes into libc's
00267    normal initializer.  */
00268 /* NOTE!  The linker notices the magical name `_init' and sets the DT_INIT
00269    pointer in the dynamic section based solely on that.  It is convention
00270    for this function to be in the `.init' section, but the symbol name is
00271    the only thing that really matters!!  */
00272 strong_alias (posixland_init, _init);
00273 
00274 void
00275 __libc_init_first (int argc, char **argv, char **envp)
00276 {
00277   /* Everything was done in the shared library initializer, _init.  */
00278 }
00279 #else
00280 strong_alias (posixland_init, __libc_init_first);
00281 
00282 
00283 void
00284 _hurd_stack_setup (volatile intptr_t argc, ...)
00285 {
00286   first_init ();
00287 
00288   _hurd_startup ((void **) &argc, &init);
00289 }
00290 #endif
00291 
00292 
00293 /* This function is defined here so that if this file ever gets into
00294    ld.so we will get a link error.  Having this file silently included
00295    in ld.so causes disaster, because the _init definition above will
00296    cause ld.so to gain an init function, which is not a cool thing. */
00297 
00298 void
00299 _dl_start (void)
00300 {
00301   abort ();
00302 }