c18b6a82ac85beec3e0212c208023ad5ca30931a
[kopensolaris-gnu/glibc.git] / sysdeps / mach / hurd / i386 / init-first.c
1 /* Initialization code run first thing by the ELF startup code.  For i386/Hurd.
2    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <hurd.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <sysdep.h>
25 #include <set-hooks.h>
26 #include "hurdstartup.h"
27 #include "hurdmalloc.h"         /* XXX */
28
29 extern void __mach_init (void);
30 extern void __libc_init (int, char **, char **);
31 extern void __getopt_clean_environment (char **);
32 extern void __libc_global_ctors (void);
33
34 unsigned int __hurd_threadvar_max;
35 unsigned long int __hurd_threadvar_stack_offset;
36 unsigned long int __hurd_threadvar_stack_mask;
37
38 #ifndef PIC
39 int __libc_enable_secure;
40 #endif
41 int __libc_multiple_libcs = 1;
42
43 extern int __libc_argc;
44 extern char **__libc_argv;
45
46 void *(*_cthread_init_routine) (void); /* Returns new SP to use.  */
47 void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__));
48
49 /* Things that want to be run before _hurd_init or much anything else.
50    Importantly, these are called before anything tries to use malloc.  */
51 DEFINE_HOOK (_hurd_preinit_hook, (void));
52
53
54 /* We call this once the Hurd magic is all set up and we are ready to be a
55    Posixoid program.  This does the same things the generic version does.  */
56 static void internal_function
57 posixland_init (int argc, char **argv)
58 {
59   __libc_init (argc, argv, __environ);
60
61   /* This is a hack to make the special getopt in GNU libc working.  */
62   __getopt_clean_environment (__environ);
63
64 #ifdef PIC
65   __libc_global_ctors ();
66 #endif
67 }
68
69
70 static void
71 init1 (int argc, char *arg0, ...)
72 {
73   char **argv = &arg0;
74   char **envp = &argv[argc + 1];
75   struct hurd_startup_data *d;
76
77   __libc_argc = argc;
78   __libc_argv = argv;
79   __environ = envp;
80
81   while (*envp)
82     ++envp;
83   d = (void *) ++envp;
84
85   /* If we are the bootstrap task started by the kernel,
86      then after the environment pointers there is no Hurd
87      data block; the argument strings start there.  */
88   if ((void *) d != argv[0])
89     {
90       _hurd_init_dtable = d->dtable;
91       _hurd_init_dtablesize = d->dtablesize;
92
93       {
94         /* Check if the stack we are now on is different from
95            the one described by _hurd_stack_{base,size}.  */
96
97         char dummy;
98         const vm_address_t newsp = (vm_address_t) &dummy;
99
100         if (d->stack_size != 0 && (newsp < d->stack_base ||
101                                    newsp - d->stack_base > d->stack_size))
102           /* The new stack pointer does not intersect with the
103              stack the exec server set up for us, so free that stack.  */
104           __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
105       }
106     }
107
108   if ((void *) d != argv[0] && (d->portarray || d->intarray))
109     /* Initialize library data structures, start signal processing, etc.  */
110     _hurd_init (d->flags, argv,
111                 d->portarray, d->portarraysize,
112                 d->intarray, d->intarraysize);
113
114 #ifndef PIC
115   __libc_enable_secure = d->flags & EXEC_SECURE;
116 #else
117   posixland_init(argc, argv);
118 #endif
119 }
120
121
122 static inline void
123 init (int *data)
124 {
125   int argc = *data;
126   char **argv = (void *) (data + 1);
127   char **envp = &argv[argc + 1];
128   struct hurd_startup_data *d;
129   unsigned long int threadvars[_HURD_THREADVAR_MAX];
130
131   /* Provide temporary storage for thread-specific variables on the startup
132      stack so the cthreads initialization code can use them for malloc et al,
133   or so we can use malloc below for the real threadvars array.  */
134   memset (threadvars, 0, sizeof threadvars);
135   __hurd_threadvar_stack_offset = (unsigned long int) threadvars;
136
137   __environ = envp;
138   while (*envp)
139     ++envp;
140   d = (void *) ++envp;
141
142   /* The user might have defined a value for this, to get more variables.
143      Otherwise it will be zero on startup.  We must make sure it is set
144      properly before before cthreads initialization, so cthreads can know
145      how much space to leave for thread variables.  */
146   if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
147     __hurd_threadvar_max = _HURD_THREADVAR_MAX;
148
149
150   /* After possibly switching stacks, call `init1' (above) with the user
151      code as the return address, and the argument data immediately above
152      that on the stack.  */
153
154   if (_cthread_init_routine)
155     {
156       /* Initialize cthreads, which will allocate us a new stack to run on.  */
157       void *newsp = (*_cthread_init_routine) ();
158       struct hurd_startup_data *od;
159
160       /* Copy per-thread variables from that temporary
161          area onto the new cthread stack.  */
162       memcpy (__hurd_threadvar_location_from_sp (0, newsp),
163               threadvars, sizeof threadvars);
164
165       /* Copy the argdata from the old stack to the new one.  */
166       newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
167                       (char *) d - (char *) data);
168
169       /* Set up the Hurd startup data block immediately following
170          the argument and environment pointers on the new stack.  */
171       od = (newsp + ((char *) d - (char *) data));
172       if ((void *) argv[0] == d)
173         /* We were started up by the kernel with arguments on the stack.
174            There is no Hurd startup data, so zero the block.  */
175         memset (od, 0, sizeof *od);
176       else
177         /* Copy the Hurd startup data block to the new stack.  */
178         *od = *d;
179
180       /* Push the user code address on the top of the new stack.  It will
181          be the return address for `init1'; we will jump there with NEWSP
182          as the stack pointer.  */
183       *--(int *) newsp = data[-1];
184       ((void **) data)[-1] = &&switch_stacks;
185       /* Force NEWSP into %ecx and &init1 into %eax, which are not restored
186          by function return.  */
187       asm volatile ("# a %0 c %1" : : "a" (newsp), "c" (&init1));
188     }
189   else
190     {
191       /* We are not using cthreads, so we will have just a single allocated
192          area for the per-thread variables of the main user thread.  */
193       unsigned long int *array;
194       unsigned int i;
195       int usercode;
196
197       array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
198       if (array == NULL)
199         __libc_fatal ("Can't allocate single-threaded thread variables.");
200
201       /* Copy per-thread variables from the temporary array into the
202          newly malloc'd space.  */
203       memcpy (array, threadvars, sizeof threadvars);
204       __hurd_threadvar_stack_offset = (unsigned long int) array;
205       for (i = _HURD_THREADVAR_MAX; i < __hurd_threadvar_max; ++i)
206         array[i] = 0;
207
208       /* The argument data is just above the stack frame we will unwind by
209          returning.  Mutate our own return address to run the code below.  */
210       usercode = data[-1];
211       ((void **) data)[-1] = &&call_init1;
212       /* Force USERCODE into %eax and &init1 into %ecx, which are not
213          restored by function return.  */
214       asm volatile ("# a %0 c %1" : : "a" (usercode), "c" (&init1));
215     }
216
217   return;
218
219  switch_stacks:
220   /* Our return address was redirected to here, so at this point our stack
221      is unwound and callers' registers restored.  Only %ecx and %eax are
222      call-clobbered and thus still have the values we set just above.
223      Fetch from there the new stack pointer we will run on, and jmp to the
224      run-time address of `init1'; when it returns, it will run the user
225      code with the argument data at the top of the stack.  */
226   asm volatile ("movl %eax, %esp; jmp *%ecx");
227   /* NOTREACHED */
228
229  call_init1:
230   /* As in the stack-switching case, at this point our stack is unwound and
231      callers' registers restored, and only %ecx and %eax communicate values
232      from the lines above.  In this case we have stashed in %eax the user
233      code return address.  Push it on the top of the stack so it acts as
234      init1's return address, and then jump there.  */
235   asm volatile ("pushl %eax; jmp *%ecx");
236   /* NOTREACHED */
237 }
238
239
240 #ifdef PIC
241 /* This function is called to initialize the shared C library.
242    It is called just before the user _start code from i386/elf/start.S,
243    with the stack set up as that code gets it.  */
244
245 /* NOTE!  The linker notices the magical name `_init' and sets the DT_INIT
246    pointer in the dynamic section based solely on that.  It is convention
247    for this function to be in the `.init' section, but the symbol name is
248    the only thing that really matters!!  */
249 void
250 _init (int argc, ...)
251 {
252   /* Initialize data structures so we can do RPCs.  */
253   __mach_init ();
254
255   RUN_HOOK (_hurd_preinit_hook, ());
256
257   init (&argc);
258 }
259 #endif
260
261
262 void
263 __libc_init_first (int argc, char **argv, char **envp)
264 #ifdef PIC
265 {
266   /* Everything was done in the shared library initializer, _init.  */
267 }
268 #else
269 {
270   posixland_init(argc, argv);
271 }
272
273 /* XXX This is all a crock and I am not happy with it.
274    This poorly-named function is called by static-start.S,
275    which should not exist at all.  */
276 void
277 _hurd_stack_setup (int argc __attribute__ ((unused)), ...)
278 {
279   void doinit (int *data)
280     {
281       /* This function gets called with the argument data at TOS.  */
282       void doinit1 (int argc, ...)
283         {
284           init (&argc);
285         }
286
287       /* Push the user return address after the argument data, and then
288          jump to `doinit1' (above), so it is as if __libc_init_first's
289          caller had called `doinit1' with the argument data already on the
290       stack.  */
291       *--data = (&argc)[-1];
292       asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack.  */
293                     "movl $0, %%ebp\n" /* Clear outermost frame pointer.  */
294                     "jmp *%1" : : "r" (data), "r" (&doinit1));
295       /* NOTREACHED */
296     }
297
298   /* Initialize data structures so we can do RPCs.  */
299   __mach_init ();
300
301   RUN_HOOK (_hurd_preinit_hook, ());
302
303   _hurd_startup ((void **) &argc, &doinit);
304 }
305 #endif
306
307
308 /* This function is defined here so that if this file ever gets into
309    ld.so we will get a link error.  Having this file silently included
310    in ld.so causes disaster, because the _init definition above will
311    cause ld.so to gain an init function, which is not a cool thing. */
312
313 void
314 _dl_start (void)
315 {
316   abort ();
317 }