.
[glibc/history.git] / sysdeps / mach / hurd / i386 / init-first.c
blobf9a7a58deb6c0d916ea204143a0554990752c348
1 /* Initialization code run first thing by the ELF startup code. For i386/Hurd.
2 Copyright (C) 1995,96,97,98,99,2000,01,02,03,04,05
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <assert.h>
22 #include <hurd.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <sysdep.h>
27 #include <set-hooks.h>
28 #include "hurdstartup.h"
29 #include "hurdmalloc.h" /* XXX */
30 #include "../locale/localeinfo.h"
32 #include <ldsodefs.h>
33 #include <fpu_control.h>
35 extern void __mach_init (void);
36 extern void __init_misc (int, char **, char **);
37 #ifdef USE_NONOPTION_FLAGS
38 extern void __getopt_clean_environment (char **);
39 #endif
40 #ifndef SHARED
41 extern void _dl_non_dynamic_init (void) internal_function;
42 #endif
43 extern void __libc_global_ctors (void);
45 unsigned int __hurd_threadvar_max;
46 unsigned long int __hurd_threadvar_stack_offset;
47 unsigned long int __hurd_threadvar_stack_mask;
49 #ifndef SHARED
50 int __libc_enable_secure;
51 #endif
52 int __libc_multiple_libcs attribute_hidden = 1;
54 extern int __libc_argc attribute_hidden;
55 extern char **__libc_argv attribute_hidden;
56 extern char **_dl_argv;
58 extern void *(*_cthread_init_routine) (void) __attribute__ ((weak));
59 void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__));
61 /* Things that want to be run before _hurd_init or much anything else.
62 Importantly, these are called before anything tries to use malloc. */
63 DEFINE_HOOK (_hurd_preinit_hook, (void));
66 /* We call this once the Hurd magic is all set up and we are ready to be a
67 Posixoid program. This does the same things the generic version does. */
68 static void
69 posixland_init (int argc, char **argv, char **envp)
71 __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
73 /* Make sure we don't initialize twice. */
74 if (!__libc_multiple_libcs)
76 /* Set the FPU control word to the proper default value. */
77 __setfpucw (__fpu_control);
80 /* Save the command-line arguments. */
81 __libc_argc = argc;
82 __libc_argv = argv;
83 __environ = envp;
85 #ifndef SHARED
86 _dl_non_dynamic_init ();
87 #endif
88 __init_misc (argc, argv, envp);
90 #ifdef USE_NONOPTION_FLAGS
91 /* This is a hack to make the special getopt in GNU libc working. */
92 __getopt_clean_environment (envp);
93 #endif
95 #ifdef SHARED
96 __libc_global_ctors ();
97 #endif
101 static void
102 init1 (int argc, char *arg0, ...)
104 char **argv = &arg0;
105 char **envp = &argv[argc + 1];
106 struct hurd_startup_data *d;
107 #ifndef SHARED
108 extern ElfW(Phdr) *_dl_phdr;
109 extern size_t _dl_phnum;
110 #endif
112 while (*envp)
113 ++envp;
114 d = (void *) ++envp;
116 /* If we are the bootstrap task started by the kernel,
117 then after the environment pointers there is no Hurd
118 data block; the argument strings start there. */
119 if ((void *) d == argv[0])
121 #ifndef SHARED
122 /* We may need to see our own phdrs, e.g. for TLS setup.
123 Try the usual kludge to find the headers without help from
124 the exec server. */
125 extern const void _start;
126 const ElfW(Ehdr) *const ehdr = &_start;
127 _dl_phdr = (ElfW(Phdr) *) ((const void *) ehdr + ehdr->e_phoff);
128 _dl_phnum = ehdr->e_phnum;
129 assert (ehdr->e_phentsize == sizeof (ElfW(Phdr)));
130 #endif
131 return;
134 #ifndef SHARED
135 __libc_enable_secure = d->flags & EXEC_SECURE;
137 _dl_phdr = (ElfW(Phdr) *) d->phdr;
138 _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr));
139 assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0);
140 #endif
142 _hurd_init_dtable = d->dtable;
143 _hurd_init_dtablesize = d->dtablesize;
146 /* Check if the stack we are now on is different from
147 the one described by _hurd_stack_{base,size}. */
149 char dummy;
150 const vm_address_t newsp = (vm_address_t) &dummy;
152 if (d->stack_size != 0 && (newsp < d->stack_base ||
153 newsp - d->stack_base > d->stack_size))
154 /* The new stack pointer does not intersect with the
155 stack the exec server set up for us, so free that stack. */
156 __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
159 if (d->portarray || d->intarray)
160 /* Initialize library data structures, start signal processing, etc. */
161 _hurd_init (d->flags, argv,
162 d->portarray, d->portarraysize,
163 d->intarray, d->intarraysize);
167 static inline void
168 init (int *data)
170 int argc = *data;
171 char **argv = (void *) (data + 1);
172 char **envp = &argv[argc + 1];
173 struct hurd_startup_data *d;
174 unsigned long int threadvars[_HURD_THREADVAR_MAX];
176 /* Provide temporary storage for thread-specific variables on the
177 startup stack so the cthreads initialization code can use them
178 for malloc et al, or so we can use malloc below for the real
179 threadvars array. */
180 memset (threadvars, 0, sizeof threadvars);
181 threadvars[_HURD_THREADVAR_LOCALE] = (unsigned long int) &_nl_global_locale;
182 __hurd_threadvar_stack_offset = (unsigned long int) threadvars;
184 /* Since the cthreads initialization code uses malloc, and the
185 malloc initialization code needs to get at the environment, make
186 sure we can find it. We'll need to do this again later on since
187 switching stacks changes the location where the environment is
188 stored. */
189 __environ = envp;
191 while (*envp)
192 ++envp;
193 d = (void *) ++envp;
195 /* The user might have defined a value for this, to get more variables.
196 Otherwise it will be zero on startup. We must make sure it is set
197 properly before before cthreads initialization, so cthreads can know
198 how much space to leave for thread variables. */
199 if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
200 __hurd_threadvar_max = _HURD_THREADVAR_MAX;
203 /* After possibly switching stacks, call `init1' (above) with the user
204 code as the return address, and the argument data immediately above
205 that on the stack. */
207 if (&_cthread_init_routine && _cthread_init_routine)
209 /* Initialize cthreads, which will allocate us a new stack to run on. */
210 int *newsp = (*_cthread_init_routine) ();
211 struct hurd_startup_data *od;
213 void switch_stacks (void);
215 /* Copy per-thread variables from that temporary
216 area onto the new cthread stack. */
217 memcpy (__hurd_threadvar_location_from_sp (0, newsp),
218 threadvars, sizeof threadvars);
220 /* Copy the argdata from the old stack to the new one. */
221 newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
222 (char *) d - (char *) data);
224 #ifdef SHARED
225 /* And readjust the dynamic linker's idea of where the argument
226 vector lives. */
227 assert (_dl_argv == argv);
228 _dl_argv = (void *) (newsp + 1);
229 #endif
231 /* Set up the Hurd startup data block immediately following
232 the argument and environment pointers on the new stack. */
233 od = ((void *) newsp + ((char *) d - (char *) data));
234 if ((void *) argv[0] == d)
235 /* We were started up by the kernel with arguments on the stack.
236 There is no Hurd startup data, so zero the block. */
237 memset (od, 0, sizeof *od);
238 else
239 /* Copy the Hurd startup data block to the new stack. */
240 *od = *d;
242 /* Push the user code address on the top of the new stack. It will
243 be the return address for `init1'; we will jump there with NEWSP
244 as the stack pointer. */
245 *--newsp = data[-1];
246 ((void **) data)[-1] = switch_stacks;
247 /* Force NEWSP into %ecx and &init1 into %eax, which are not restored
248 by function return. */
249 asm volatile ("# a %0 c %1" : : "a" (newsp), "c" (&init1));
251 else
253 /* We are not using cthreads, so we will have just a single allocated
254 area for the per-thread variables of the main user thread. */
255 unsigned long int *array;
256 unsigned int i;
257 int usercode;
259 void call_init1 (void);
261 array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
262 if (array == NULL)
263 __libc_fatal ("Can't allocate single-threaded thread variables.");
265 /* Copy per-thread variables from the temporary array into the
266 newly malloc'd space. */
267 memcpy (array, threadvars, sizeof threadvars);
268 __hurd_threadvar_stack_offset = (unsigned long int) array;
269 for (i = _HURD_THREADVAR_MAX; i < __hurd_threadvar_max; ++i)
270 array[i] = 0;
272 /* The argument data is just above the stack frame we will unwind by
273 returning. Mutate our own return address to run the code below. */
274 usercode = data[-1];
275 data[-1] = (int) &call_init1;
276 /* Force USERCODE into %eax and &init1 into %ecx, which are not
277 restored by function return. */
278 asm volatile ("# a %0 c %1" : : "a" (usercode), "c" (&init1));
282 /* These bits of inline assembler used to be located inside `init'.
283 However they were optimized away by gcc 2.95. */
285 /* The return address of `init' above, was redirected to here, so at
286 this point our stack is unwound and callers' registers restored.
287 Only %ecx and %eax are call-clobbered and thus still have the
288 values we set just above. Fetch from there the new stack pointer
289 we will run on, and jmp to the run-time address of `init1'; when it
290 returns, it will run the user code with the argument data at the
291 top of the stack. */
292 asm ("switch_stacks:\n"
293 " movl %eax, %esp\n"
294 " jmp *%ecx");
296 /* As in the stack-switching case, at this point our stack is unwound
297 and callers' registers restored, and only %ecx and %eax communicate
298 values from the lines above. In this case we have stashed in %eax
299 the user code return address. Push it on the top of the stack so
300 it acts as init1's return address, and then jump there. */
301 asm ("call_init1:\n"
302 " push %eax\n"
303 " jmp *%ecx\n");
306 /* Do the first essential initializations that must precede all else. */
307 static inline void
308 first_init (void)
310 /* Initialize data structures so we can do RPCs. */
311 __mach_init ();
313 RUN_HOOK (_hurd_preinit_hook, ());
316 #ifdef SHARED
317 /* This function is called specially by the dynamic linker to do early
318 initialization of the shared C library before normal initializers
319 expecting a Posixoid environment can run. It gets called with the
320 stack set up just as the user will see it, so it can switch stacks. */
322 void
323 _dl_init_first (void)
325 first_init ();
327 init ((int *) __builtin_frame_address (0) + 2);
329 #endif
332 #ifdef SHARED
333 /* The regular posixland initialization is what goes into libc's
334 normal initializer. */
335 /* NOTE! The linker notices the magical name `_init' and sets the DT_INIT
336 pointer in the dynamic section based solely on that. It is convention
337 for this function to be in the `.init' section, but the symbol name is
338 the only thing that really matters!! */
339 strong_alias (posixland_init, _init);
341 void
342 __libc_init_first (int argc, char **argv, char **envp)
344 /* Everything was done in the shared library initializer, _init. */
346 #else
347 strong_alias (posixland_init, __libc_init_first);
350 /* XXX This is all a crock and I am not happy with it.
351 This poorly-named function is called by static-start.S,
352 which should not exist at all. */
353 void
354 _hurd_stack_setup (void)
356 intptr_t caller = (intptr_t) __builtin_return_address (0);
358 void doinit (intptr_t *data)
360 /* This function gets called with the argument data at TOS. */
361 void doinit1 (void)
363 init ((int *) __builtin_frame_address (0) + 2);
366 /* Push the user return address after the argument data, and then
367 jump to `doinit1' (above), so it is as if __libc_init_first's
368 caller had called `doinit1' with the argument data already on the
369 stack. */
370 *--data = caller;
371 asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack. */
372 "movl $0, %%ebp\n" /* Clear outermost frame pointer. */
373 "jmp *%1" : : "r" (data), "r" (&doinit1) : "sp");
374 /* NOTREACHED */
377 first_init ();
379 _hurd_startup ((void **) __builtin_frame_address (0) + 2, &doinit);
381 #endif
384 /* This function is defined here so that if this file ever gets into
385 ld.so we will get a link error. Having this file silently included
386 in ld.so causes disaster, because the _init definition above will
387 cause ld.so to gain an init function, which is not a cool thing. */
389 void
390 _dl_start (void)
392 abort ();