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.  For Mips/Hurd.
00002    Copyright (C) 1996,1997,1998,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 <hurd.h>
00021 #include <stdio.h>
00022 #include <unistd.h>
00023 #include <string.h>
00024 #include "hurdstartup.h"
00025 #include "set-hooks.h"
00026 #include "hurdmalloc.h"            /* XXX */
00027 
00028 extern void __mach_init (void);
00029 extern void __init_misc (int, char **, char **);
00030 #ifdef USE_NONOPTION_FLAGS
00031 extern void __getopt_clean_environment (char **);
00032 #endif
00033 #ifndef SHARED
00034 extern void _dl_non_dynamic_init (void) internal_function;
00035 #endif
00036 extern void __libc_global_ctors (void);
00037 
00038 unsigned int __hurd_threadvar_max;
00039 unsigned long int __hurd_threadvar_stack_offset;
00040 unsigned long int __hurd_threadvar_stack_mask;
00041 
00042 int __libc_multiple_libcs attribute_hidden = 1;
00043 
00044 int __libc_argc attribute_hidden;
00045 char **__libc_argv attribute_hidden;
00046 
00047 void *(*_cthread_init_routine) (void); /* Returns new SP to use.  */
00048 void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__));
00049 
00050 
00051 /* Things that want to be run before _hurd_init or much anything else.
00052    Importantly, these are called before anything tries to use malloc.  */
00053 DEFINE_HOOK (_hurd_preinit_hook, (void));
00054 
00055 static void
00056 init1 (int argc, char *arg0, ...)
00057 {
00058   char **argv = &arg0;
00059   char **envp = &argv[argc + 1];
00060   struct hurd_startup_data *d;
00061 
00062   __libc_argc = argc;
00063   __libc_argv = argv;
00064   __environ = envp;
00065   while (*envp)
00066     ++envp;
00067   d = (void *) ++envp;
00068 
00069   /* If we are the bootstrap task started by the kernel,
00070      then after the environment pointers there is no Hurd
00071      data block; the argument strings start there.  */
00072   if ((void *) d != argv[0])
00073     {
00074       _hurd_init_dtable = d->dtable;
00075       _hurd_init_dtablesize = d->dtablesize;
00076 
00077       {
00078        /* Check if the stack we are now on is different from
00079           the one described by _hurd_stack_{base,size}.  */
00080 
00081        char dummy;
00082        const vm_address_t newsp = (vm_address_t) &dummy;
00083 
00084        if (d->stack_size != 0 && (newsp < d->stack_base ||
00085                                newsp - d->stack_base > d->stack_size))
00086          /* The new stack pointer does not intersect with the
00087             stack the exec server set up for us, so free that stack.  */
00088          __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
00089       }
00090     }
00091 
00092   if (__hurd_threadvar_stack_mask == 0)
00093     {
00094       /* We are not using cthreads, so we will have just a single allocated
00095         area for the per-thread variables of the main user thread.  */
00096       unsigned long int i;
00097       __hurd_threadvar_stack_offset
00098        = (unsigned long int) malloc (__hurd_threadvar_max *
00099                                   sizeof (unsigned long int));
00100       if (__hurd_threadvar_stack_offset == 0)
00101        __libc_fatal ("Can't allocate single-threaded per-thread variables.");
00102       for (i = 0; i < __hurd_threadvar_max; ++i)
00103        ((unsigned long int *) __hurd_threadvar_stack_offset)[i] = 0;
00104     }
00105 
00106   if ((void *) d != argv[0] && (d->portarray || d->intarray))
00107     /* Initialize library data structures, start signal processing, etc.  */
00108     _hurd_init (d->flags, argv,
00109               d->portarray, d->portarraysize,
00110               d->intarray, d->intarraysize);
00111 
00112 #ifndef SHARED
00113   _dl_non_dynamic_init ();
00114 #endif
00115   __init_misc (argc, argv, __environ);
00116 
00117 #ifdef USE_NONOPTION_FLAGS
00118   /* This is a hack to make the special getopt in GNU libc working.  */
00119   __getopt_clean_environment (envp);
00120 #endif
00121 
00122 #ifdef SHARED
00123   __libc_global_ctors ();
00124 #endif
00125 
00126   (void) &init1;
00127 }
00128 
00129 static void *
00130 __init (int *data)
00131 {
00132   int argc = *data;
00133   char **argv = (void *) (data + 1);
00134   char **envp = &argv[argc + 1];
00135   struct hurd_startup_data *d;
00136 
00137   __environ = envp;
00138   while (*envp)
00139     ++envp;
00140   d = (void *) ++envp;
00141 
00142   /* The user might have defined a value for this, to get more variables.
00143      Otherwise it will be zero on startup.  We must make sure it is set
00144      properly before before cthreads initialization, so cthreads can know
00145      how much space to leave for thread variables.  */
00146   if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
00147     __hurd_threadvar_max = _HURD_THREADVAR_MAX;
00148 
00149 
00150   /* After possibly switching stacks, call `init1' (above) with the user
00151      code as the return address, and the argument data immediately above
00152      that on the stack.  */
00153 
00154   if (_cthread_init_routine)
00155     {
00156       /* Initialize cthreads, which will allocate us a new stack to run on.  */
00157       void *newsp = (*_cthread_init_routine) ();
00158       struct hurd_startup_data *od;
00159 
00160       /* Copy the argdata from the old stack to the new one.  */
00161       newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
00162                     (char *) d - (char *) data);
00163 
00164       /* Set up the Hurd startup data block immediately following
00165         the argument and environment pointers on the new stack.  */
00166       od = (newsp + ((char *) d - (char *) data));
00167       if ((void *) argv[0] == d)
00168        /* We were started up by the kernel with arguments on the stack.
00169           There is no Hurd startup data, so zero the block.  */
00170        memset (od, 0, sizeof *od);
00171       else
00172        /* Copy the Hurd startup data block to the new stack.  */
00173        *od = *d;
00174 
00175       /* Push the user code address on the top of the new stack.  It will
00176         be the return address for `init1'; we will jump there with NEWSP
00177         as the stack pointer.  */
00178       return newsp;
00179     }
00180 
00181   /* The argument data is just above the stack frame we will unwind by
00182      returning.  */
00183   return (void *) data;
00184 
00185   (void) &__init;
00186 }
00187 
00188 #ifdef SHARED
00189 /* This function is called to initialize the shared C library.
00190    It is called just before the user _start code from mips/elf/start.S,
00191    with the stack set up as that code gets it.  */
00192 
00193 /* NOTE!  The linker notices the magical name `_init' and sets the DT_INIT
00194    pointer in the dynamic section based solely on that.  It is convention
00195    for this function to be in the `.init' section, but the symbol name is
00196    the only thing that really matters!!  */
00197 /*void _init (int argc, ...) __attribute__ ((unused, section (".init")));*/
00198 
00199 #if __mips64
00200 asm ("\
00201        .section .init,\"ax\",@progbits\n\
00202        .align 3\n\
00203        .globl _init\n\
00204        .type _init,@function\n\
00205        .ent _init\n\
00206 _init:\n\
00207        .set noreorder\n\
00208        .cpload $25\n\
00209        .set reorder\n\
00210        dsubu $29, 8*8\n\
00211        .cprestore 6*8\n\
00212        sd $16, 4*8($29)\n\
00213        sd $31, 5*8($29)\n\
00214        jal preinit\n\
00215        sd $28, 6*8($29)\n\
00216        move $16, $29 # Save the old stack pointer to s0 ($16)\n\
00217        daddu $4, $29, 4*8\n\
00218        jal __init\n\
00219        # Restore saved registers from the old stack.\n\
00220        ld $28, 6*8($16)\n\
00221        ld $31, 5*8($16)\n\
00222        ld $16, 4*8($16)\n\
00223        move $29, $2 # set new sp to SP\n\
00224 call_init1:\n\
00225        ld $4, 0($29)\n\
00226        ld $5, 1*8($29)\n\
00227        ld $6, 2*8($29)\n\
00228        ld $7, 3*8($29)\n\
00229        dla $25, init1\n\
00230        jr $25\n\
00231        .end _init\n\
00232        .text\n\
00233 ");
00234 #else
00235 asm ("\
00236        .section .init,\"ax\",@progbits\n\
00237        .align 2\n\
00238        .globl _init\n\
00239        .type _init,@function\n\
00240        .ent _init\n\
00241 _init:\n\
00242        .set noreorder\n\
00243        .cpload $25\n\
00244        .set reorder\n\
00245        subu $29, 32\n\
00246        .cprestore 24\n\
00247        sw $16, 16($29)\n\
00248        sw $31, 20($29)\n\
00249        jal preinit\n\
00250        sw $28, 24($29)\n\
00251        move $16, $29 # Save the old stack pointer to s0 ($16)\n\
00252        addu $4, $29, 32\n\
00253        jal __init\n\
00254        # Restore saved registers from the old stack.\n\
00255        lw $28, 24($16)\n\
00256        lw $31, 20($16)\n\
00257        lw $16, 16($16)\n\
00258        move $29, $2 # set new sp to SP\n\
00259 call_init1:\n\
00260        lw $4, 0($29)\n\
00261        lw $5, 4($29)\n\
00262        lw $6, 8($29)\n\
00263        lw $7, 12($29)\n\
00264        la $25, init1\n\
00265        jr $25\n\
00266        .end _init\n\
00267        .text\n\
00268 ");
00269 #endif
00270 
00271 static void
00272 preinit (void)
00273 {
00274   /* Initialize data structures so we can do RPCs.  */
00275   __mach_init ();
00276 
00277   RUN_HOOK (_hurd_preinit_hook, ());
00278 
00279   (void) &preinit;
00280 }
00281 
00282 void __libc_init_first (int argc, ...)
00283 {
00284 }
00285 #endif
00286 
00287 #ifndef SHARED
00288 /* An assembler code wrapping c function __init.  */
00289 #ifdef __mips64
00290 asm ("\
00291        .text\n\
00292        .align 3\n\
00293 init:\n\
00294        dsubu $29, 8*8\n\
00295        sd $16, 4*8($29)\n\
00296        sd $31, 5*8($29)\n\
00297        move $16, $29\n\
00298        jal __init\n\
00299        ld $31, 5*8($16)\n\
00300        ld $16, 4*8($16)\n\
00301        move $29, $2 # set new sp to SP\n\
00302 call_init1:\n\
00303        ld $4, 0($29)\n\
00304        ld $5, 1*8($29)\n\
00305        ld $6, 2*8($29)\n\
00306        ld $7, 3*8($29)\n\
00307        dla $25, init1\n\
00308        jr $25\n\
00309 ");
00310 #else
00311 asm ("\
00312        .text\n\
00313        .align 2\n\
00314 init:\n\
00315        subu $29, 32\n\
00316        sw $16, 16($29)\n\
00317        sw $31, 20($29)\n\
00318        move $16, $29\n\
00319        jal __init\n\
00320        lw $31, 20($16)\n\
00321        lw $16, 16($16)\n\
00322        move $29, $2 # set new sp to SP\n\
00323 call_init1:\n\
00324        lw $4, 0($29)\n\
00325        lw $5, 4($29)\n\
00326        lw $6, 8($29)\n\
00327        lw $7, 12($29)\n\
00328        la $25, init1\n\
00329        jr $25\n\
00330 ");
00331 #endif
00332 
00333 /* An assembler code wrapping c function ___libc_init_first.
00334    ___libc_init_first does an RPC call to flush cache to put doinit
00335    function on the stack, so we should call __mach_init first in
00336    this wrap. */
00337 #ifdef __mips64
00338 asm ("\
00339        .text\n\
00340        .align 3\n\
00341        .globl __libc_init_first\n\
00342 __libc_init_first:\n\
00343        dsubu $29, 8\n\
00344        sd $31, 0($29)\n\
00345        jal __mach_init\n\
00346        ld $4, 0($29)\n\
00347        ld $5, 1*8($29)\n\
00348        ld $6, 2*8($29)\n\
00349        ld $7, 3*8($29)\n\
00350        j ___libc_init_first\n\
00351 ");
00352 #else
00353 asm ("\
00354        .text\n\
00355        .align 2\n\
00356        .globl __libc_init_first\n\
00357 __libc_init_first:\n\
00358        subu $29, 4\n\
00359        sw $31, 0($29)\n\
00360        jal __mach_init\n\
00361        lw $4, 0($29)\n\
00362        lw $5, 4($29)\n\
00363        lw $6, 8($29)\n\
00364        lw $7, 12($29)\n\
00365        j ___libc_init_first\n\
00366 ");
00367 #endif
00368 
00369 static void
00370 ___libc_init_first (int return_addr, int argc, ...)
00371 {
00372   void doinit (int *data)
00373     {
00374 #if 0
00375       /* This function gets called with the argument data at TOS.  */
00376       void doinit1 (int argc, ...)
00377        {
00378          init (&argc);
00379        }
00380 #endif
00381       extern void init (int *data);
00382 
00383       /* Push the user return address after the argument data, and then
00384         jump to `doinit1' (above), so it is as if __libc_init_first's
00385         caller had called `init' with the argument data already on the
00386         stack.  */
00387       *--data = return_addr;
00388 
00389 #ifdef __mips64
00390       asm volatile ("ld $31, 0(%0)\n" /* Load the original return address.  */
00391                   "daddu $29, %0, 8\n" /* Switch to new outermost stack.  */
00392                   "move $4, $29\n"
00393                   "jr %1" : : "r" (data), "r" (&init));
00394 #else
00395       asm volatile ("lw $31, 0(%0)\n" /* Load the original return address.  */
00396                   "addu $29, %0, 4\n" /* Switch to new outermost stack.  */
00397                   "move $4, $29\n"
00398                   "jr %1" : : "r" (data), "r" (&init));
00399 #endif
00400       /* NOTREACHED */
00401     }
00402 
00403 #if 0
00404   /* Initialize data structures so we can do RPCs.  */
00405   __mach_init ();
00406 #endif
00407 
00408   RUN_HOOK (_hurd_preinit_hook, ());
00409 
00410   _hurd_startup ((void **) &argc, &doinit);
00411 
00412   (void) &___libc_init_first;
00413 }
00414 #endif