Back to index

glibc  2.9
hurdstartup.c
Go to the documentation of this file.
00001 /* Initial program startup for running under the GNU Hurd.
00002    Copyright (C) 1991,92,93,94,95,96,97,98,2002 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 <errno.h>
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <hurd.h>
00025 #include <hurd/exec_startup.h>
00026 #include <sysdep.h>
00027 #include <hurd/threadvar.h>
00028 #include <unistd.h>
00029 #include <elf.h>
00030 #include <set-hooks.h>
00031 #include "hurdstartup.h"
00032 #include <argz.h>
00033 
00034 mach_port_t *_hurd_init_dtable;
00035 mach_msg_type_number_t _hurd_init_dtablesize;
00036 
00037 extern void __mach_init (void);
00038 
00039 /* Entry point.  This is the first thing in the text segment.
00040 
00041    The exec server started the initial thread in our task with this spot the
00042    PC, and a stack that is presumably big enough.  We do basic Mach
00043    initialization so mig-generated stubs work, and then do an exec_startup
00044    RPC on our bootstrap port, to which the exec server responds with the
00045    information passed in the exec call, as well as our original bootstrap
00046    port, and the base address and size of the preallocated stack.
00047 
00048    If using cthreads, we are given a new stack by cthreads initialization and
00049    deallocate the stack set up by the exec server.  On the new stack we call
00050    `start1' (above) to do the rest of the startup work.  Since the stack may
00051    disappear out from under us in a machine-dependent way, we use a pile of
00052    static variables to communicate the information from exec_startup to start1.
00053    This is unfortunate but preferable to machine-dependent frobnication to copy
00054    the state from the old stack to the new one.  */
00055 
00056 
00057 void
00058 _hurd_startup (void **argptr, void (*main) (intptr_t *data))
00059 {
00060   error_t err;
00061   mach_port_t in_bootstrap;
00062   char *args, *env;
00063   mach_msg_type_number_t argslen, envlen;
00064   struct hurd_startup_data data;
00065   char **argv, **envp;
00066   int argc, envc;
00067   intptr_t *argcptr;
00068   vm_address_t addr;
00069 
00070   /* Attempt to map page zero redzoned before we receive any RPC
00071      data that might get allocated there.  We can ignore errors.  */
00072   addr = 0;
00073   __vm_map (__mach_task_self (),
00074            &addr, __vm_page_size, 0, 0, MACH_PORT_NULL, 0, 1,
00075            VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
00076 
00077   if (err = __task_get_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT,
00078                                  &in_bootstrap))
00079     LOSE;
00080 
00081   if (in_bootstrap != MACH_PORT_NULL)
00082     {
00083       /* Call the exec server on our bootstrap port and
00084         get all our standard information from it.  */
00085 
00086       argslen = envlen = 0;
00087       data.dtablesize = data.portarraysize = data.intarraysize = 0;
00088 
00089       err = __exec_startup_get_info (in_bootstrap,
00090                                  &data.user_entry,
00091                                  &data.phdr, &data.phdrsz,
00092                                  &data.stack_base, &data.stack_size,
00093                                  &data.flags,
00094                                  &args, &argslen,
00095                                  &env, &envlen,
00096                                  &data.dtable, &data.dtablesize,
00097                                  &data.portarray, &data.portarraysize,
00098                                  &data.intarray, &data.intarraysize);
00099       __mach_port_deallocate (__mach_task_self (), in_bootstrap);
00100     }
00101 
00102   if (err || in_bootstrap == MACH_PORT_NULL || (data.flags & EXEC_STACK_ARGS))
00103     {
00104       /* Either we have no bootstrap port, or the RPC to the exec server
00105         failed, or whoever started us up passed the flag saying args are
00106         on the stack.  Try to snarf the args in the canonical Mach way.
00107         Hopefully either they will be on the stack as expected, or the
00108         stack will be zeros so we don't crash.  */
00109 
00110       argcptr = (intptr_t *) argptr;
00111       argc = argcptr[0];
00112       argv = (char **) &argcptr[1];
00113       envp = &argv[argc + 1];
00114       envc = 0;
00115       while (envp[envc])
00116        ++envc;
00117     }
00118   else
00119     {
00120       /* Turn the block of null-separated strings we were passed for the
00121         arguments and environment into vectors of pointers to strings.  */
00122 
00123       /* Count up the arguments so we can allocate ARGV.  */
00124       argc = __argz_count (args, argslen);
00125       /* Count up the environment variables so we can allocate ENVP.  */
00126       envc = __argz_count (env, envlen);
00127 
00128       /* There were some arguments.  Allocate space for the vectors of
00129         pointers and fill them in.  We allocate the space for the
00130         environment pointers immediately after the argv pointers because
00131         the ELF ABI will expect it.  */
00132       argcptr = __alloca (sizeof (intptr_t) +
00133                        (argc + 1 + envc + 1) * sizeof (char *) +
00134                        sizeof (struct hurd_startup_data));
00135       *argcptr = argc;
00136       argv = (void *) (argcptr + 1);
00137       __argz_extract (args, argslen, argv);
00138 
00139       /* There was some environment.  */
00140       envp = &argv[argc + 1];
00141       __argz_extract (env, envlen, envp);
00142     }
00143 
00144   if (err || in_bootstrap == MACH_PORT_NULL)
00145     {
00146       /* Either we have no bootstrap port, or the RPC to the exec server
00147         failed.  Set all our other variables to have empty information.  */
00148 
00149       data.flags = 0;
00150       args = env = NULL;
00151       argslen = envlen = 0;
00152       data.dtable = NULL;
00153       data.dtablesize = 0;
00154       data.portarray = NULL;
00155       data.portarraysize = 0;
00156       data.intarray = NULL;
00157       data.intarraysize = 0;
00158     }
00159   else if ((void *) &envp[envc + 1] == argv[0])
00160     {
00161       /* The arguments arrived on the stack from the kernel, but our
00162         protocol requires some space after them for a `struct
00163         hurd_startup_data'.  Move them.  */
00164       struct
00165        {
00166          intptr_t count;
00167          char *argv[argc + 1];
00168          char *envp[envc + 1];
00169          struct hurd_startup_data data;
00170        } *args = alloca (sizeof *args);
00171       if ((void *) &args[1] == (void *) argcptr)
00172        args = alloca (-((char *) &args->data - (char *) args));
00173       memmove (args, argcptr, (char *) &args->data - (char *) args);
00174       argcptr = (void *) args;
00175       argv = args->argv;
00176       envp = args->envp;
00177     }
00178 
00179   {
00180     struct hurd_startup_data *d = (void *) &envp[envc + 1];
00181 
00182     if ((void *) d != argv[0])
00183       {
00184        *d = data;
00185        _hurd_init_dtable = d->dtable;
00186        _hurd_init_dtablesize = d->dtablesize;
00187       }
00188 
00189     (*main) (argcptr);
00190   }
00191 
00192   /* Should never get here.  */
00193   LOSE;
00194   abort ();
00195 }