(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[glibc.git] / sysdeps / mach / hurd / mips / init-first.c
blob6f53e839b3eaadd82b2919b6c82711df106595bc
1 /* Initialization code run first thing by the ELF startup code. For Mips/Hurd.
2 Copyright (C) 1996,1997,1998,2000,01,02,03 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <hurd.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include "hurdstartup.h"
25 #include "set-hooks.h"
26 #include "hurdmalloc.h" /* XXX */
28 extern void __mach_init (void);
29 extern void __init_misc (int, char **, char **);
30 #ifdef USE_NONOPTION_FLAGS
31 extern void __getopt_clean_environment (char **);
32 #endif
33 #ifndef SHARED
34 extern void _dl_non_dynamic_init (void) internal_function;
35 #endif
36 extern void __libc_global_ctors (void);
38 unsigned int __hurd_threadvar_max;
39 unsigned long int __hurd_threadvar_stack_offset;
40 unsigned long int __hurd_threadvar_stack_mask;
42 int __libc_multiple_libcs attribute_hidden = 1;
44 int __libc_argc attribute_hidden;
45 char **__libc_argv attribute_hidden;
47 void *(*_cthread_init_routine) (void); /* Returns new SP to use. */
48 void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__));
51 /* Things that want to be run before _hurd_init or much anything else.
52 Importantly, these are called before anything tries to use malloc. */
53 DEFINE_HOOK (_hurd_preinit_hook, (void));
55 static void
56 init1 (int argc, char *arg0, ...)
58 char **argv = &arg0;
59 char **envp = &argv[argc + 1];
60 struct hurd_startup_data *d;
62 __libc_argc = argc;
63 __libc_argv = argv;
64 __environ = envp;
65 while (*envp)
66 ++envp;
67 d = (void *) ++envp;
69 /* If we are the bootstrap task started by the kernel,
70 then after the environment pointers there is no Hurd
71 data block; the argument strings start there. */
72 if ((void *) d != argv[0])
74 _hurd_init_dtable = d->dtable;
75 _hurd_init_dtablesize = d->dtablesize;
78 /* Check if the stack we are now on is different from
79 the one described by _hurd_stack_{base,size}. */
81 char dummy;
82 const vm_address_t newsp = (vm_address_t) &dummy;
84 if (d->stack_size != 0 && (newsp < d->stack_base ||
85 newsp - d->stack_base > d->stack_size))
86 /* The new stack pointer does not intersect with the
87 stack the exec server set up for us, so free that stack. */
88 __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
92 if (__hurd_threadvar_stack_mask == 0)
94 /* We are not using cthreads, so we will have just a single allocated
95 area for the per-thread variables of the main user thread. */
96 unsigned long int i;
97 __hurd_threadvar_stack_offset
98 = (unsigned long int) malloc (__hurd_threadvar_max *
99 sizeof (unsigned long int));
100 if (__hurd_threadvar_stack_offset == 0)
101 __libc_fatal ("Can't allocate single-threaded per-thread variables.");
102 for (i = 0; i < __hurd_threadvar_max; ++i)
103 ((unsigned long int *) __hurd_threadvar_stack_offset)[i] = 0;
106 if ((void *) d != argv[0] && (d->portarray || d->intarray))
107 /* Initialize library data structures, start signal processing, etc. */
108 _hurd_init (d->flags, argv,
109 d->portarray, d->portarraysize,
110 d->intarray, d->intarraysize);
112 #ifndef SHARED
113 _dl_non_dynamic_init ();
114 #endif
115 __init_misc (argc, argv, __environ);
117 #ifdef USE_NONOPTION_FLAGS
118 /* This is a hack to make the special getopt in GNU libc working. */
119 __getopt_clean_environment (envp);
120 #endif
122 #ifdef SHARED
123 __libc_global_ctors ();
124 #endif
126 (void) &init1;
129 static void *
130 __init (int *data)
132 int argc = *data;
133 char **argv = (void *) (data + 1);
134 char **envp = &argv[argc + 1];
135 struct hurd_startup_data *d;
137 __environ = envp;
138 while (*envp)
139 ++envp;
140 d = (void *) ++envp;
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;
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. */
154 if (_cthread_init_routine)
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;
160 /* Copy the argdata from the old stack to the new one. */
161 newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
162 (char *) d - (char *) data);
164 /* Set up the Hurd startup data block immediately following
165 the argument and environment pointers on the new stack. */
166 od = (newsp + ((char *) d - (char *) data));
167 if ((void *) argv[0] == d)
168 /* We were started up by the kernel with arguments on the stack.
169 There is no Hurd startup data, so zero the block. */
170 memset (od, 0, sizeof *od);
171 else
172 /* Copy the Hurd startup data block to the new stack. */
173 *od = *d;
175 /* Push the user code address on the top of the new stack. It will
176 be the return address for `init1'; we will jump there with NEWSP
177 as the stack pointer. */
178 return newsp;
181 /* The argument data is just above the stack frame we will unwind by
182 returning. */
183 return (void *) data;
185 (void) &__init;
188 #ifdef SHARED
189 /* This function is called to initialize the shared C library.
190 It is called just before the user _start code from mips/elf/start.S,
191 with the stack set up as that code gets it. */
193 /* NOTE! The linker notices the magical name `_init' and sets the DT_INIT
194 pointer in the dynamic section based solely on that. It is convention
195 for this function to be in the `.init' section, but the symbol name is
196 the only thing that really matters!! */
197 /*void _init (int argc, ...) __attribute__ ((unused, section (".init")));*/
199 #if __mips64
200 asm ("\
201 .section .init,\"ax\",@progbits\n\
202 .align 3\n\
203 .globl _init\n\
204 .type _init,@function\n\
205 .ent _init\n\
206 _init:\n\
207 .set noreorder\n\
208 .cpload $25\n\
209 .set reorder\n\
210 dsubu $29, 8*8\n\
211 .cprestore 6*8\n\
212 sd $16, 4*8($29)\n\
213 sd $31, 5*8($29)\n\
214 jal preinit\n\
215 sd $28, 6*8($29)\n\
216 move $16, $29 # Save the old stack pointer to s0 ($16)\n\
217 daddu $4, $29, 4*8\n\
218 jal __init\n\
219 # Restore saved registers from the old stack.\n\
220 ld $28, 6*8($16)\n\
221 ld $31, 5*8($16)\n\
222 ld $16, 4*8($16)\n\
223 move $29, $2 # set new sp to SP\n\
224 call_init1:\n\
225 ld $4, 0($29)\n\
226 ld $5, 1*8($29)\n\
227 ld $6, 2*8($29)\n\
228 ld $7, 3*8($29)\n\
229 dla $25, init1\n\
230 jr $25\n\
231 .end _init\n\
232 .text\n\
234 #else
235 asm ("\
236 .section .init,\"ax\",@progbits\n\
237 .align 2\n\
238 .globl _init\n\
239 .type _init,@function\n\
240 .ent _init\n\
241 _init:\n\
242 .set noreorder\n\
243 .cpload $25\n\
244 .set reorder\n\
245 subu $29, 32\n\
246 .cprestore 24\n\
247 sw $16, 16($29)\n\
248 sw $31, 20($29)\n\
249 jal preinit\n\
250 sw $28, 24($29)\n\
251 move $16, $29 # Save the old stack pointer to s0 ($16)\n\
252 addu $4, $29, 32\n\
253 jal __init\n\
254 # Restore saved registers from the old stack.\n\
255 lw $28, 24($16)\n\
256 lw $31, 20($16)\n\
257 lw $16, 16($16)\n\
258 move $29, $2 # set new sp to SP\n\
259 call_init1:\n\
260 lw $4, 0($29)\n\
261 lw $5, 4($29)\n\
262 lw $6, 8($29)\n\
263 lw $7, 12($29)\n\
264 la $25, init1\n\
265 jr $25\n\
266 .end _init\n\
267 .text\n\
269 #endif
271 static void
272 preinit (void)
274 /* Initialize data structures so we can do RPCs. */
275 __mach_init ();
277 RUN_HOOK (_hurd_preinit_hook, ());
279 (void) &preinit;
282 void __libc_init_first (int argc, ...)
285 #endif
287 #ifndef SHARED
288 /* An assembler code wrapping c function __init. */
289 #ifdef __mips64
290 asm ("\
291 .text\n\
292 .align 3\n\
293 init:\n\
294 dsubu $29, 8*8\n\
295 sd $16, 4*8($29)\n\
296 sd $31, 5*8($29)\n\
297 move $16, $29\n\
298 jal __init\n\
299 ld $31, 5*8($16)\n\
300 ld $16, 4*8($16)\n\
301 move $29, $2 # set new sp to SP\n\
302 call_init1:\n\
303 ld $4, 0($29)\n\
304 ld $5, 1*8($29)\n\
305 ld $6, 2*8($29)\n\
306 ld $7, 3*8($29)\n\
307 dla $25, init1\n\
308 jr $25\n\
310 #else
311 asm ("\
312 .text\n\
313 .align 2\n\
314 init:\n\
315 subu $29, 32\n\
316 sw $16, 16($29)\n\
317 sw $31, 20($29)\n\
318 move $16, $29\n\
319 jal __init\n\
320 lw $31, 20($16)\n\
321 lw $16, 16($16)\n\
322 move $29, $2 # set new sp to SP\n\
323 call_init1:\n\
324 lw $4, 0($29)\n\
325 lw $5, 4($29)\n\
326 lw $6, 8($29)\n\
327 lw $7, 12($29)\n\
328 la $25, init1\n\
329 jr $25\n\
331 #endif
333 /* An assembler code wrapping c function ___libc_init_first.
334 ___libc_init_first does an RPC call to flush cache to put doinit
335 function on the stack, so we should call __mach_init first in
336 this wrap. */
337 #ifdef __mips64
338 asm ("\
339 .text\n\
340 .align 3\n\
341 .globl __libc_init_first\n\
342 __libc_init_first:\n\
343 dsubu $29, 8\n\
344 sd $31, 0($29)\n\
345 jal __mach_init\n\
346 ld $4, 0($29)\n\
347 ld $5, 1*8($29)\n\
348 ld $6, 2*8($29)\n\
349 ld $7, 3*8($29)\n\
350 j ___libc_init_first\n\
352 #else
353 asm ("\
354 .text\n\
355 .align 2\n\
356 .globl __libc_init_first\n\
357 __libc_init_first:\n\
358 subu $29, 4\n\
359 sw $31, 0($29)\n\
360 jal __mach_init\n\
361 lw $4, 0($29)\n\
362 lw $5, 4($29)\n\
363 lw $6, 8($29)\n\
364 lw $7, 12($29)\n\
365 j ___libc_init_first\n\
367 #endif
369 static void
370 ___libc_init_first (int return_addr, int argc, ...)
372 void doinit (int *data)
374 #if 0
375 /* This function gets called with the argument data at TOS. */
376 void doinit1 (int argc, ...)
378 init (&argc);
380 #endif
381 extern void init (int *data);
383 /* Push the user return address after the argument data, and then
384 jump to `doinit1' (above), so it is as if __libc_init_first's
385 caller had called `init' with the argument data already on the
386 stack. */
387 *--data = return_addr;
389 #ifdef __mips64
390 asm volatile ("ld $31, 0(%0)\n" /* Load the original return address. */
391 "daddu $29, %0, 8\n" /* Switch to new outermost stack. */
392 "move $4, $29\n"
393 "jr %1" : : "r" (data), "r" (&init));
394 #else
395 asm volatile ("lw $31, 0(%0)\n" /* Load the original return address. */
396 "addu $29, %0, 4\n" /* Switch to new outermost stack. */
397 "move $4, $29\n"
398 "jr %1" : : "r" (data), "r" (&init));
399 #endif
400 /* NOTREACHED */
403 #if 0
404 /* Initialize data structures so we can do RPCs. */
405 __mach_init ();
406 #endif
408 RUN_HOOK (_hurd_preinit_hook, ());
410 _hurd_startup ((void **) &argc, &doinit);
412 (void) &___libc_init_first;
414 #endif