1/* Initialization code run first thing by the ELF startup code. For Hurd.
2 Copyright (C) 1995-2024 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 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.
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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <assert.h>
20#include <hurd.h>
21#include <stdio.h>
22#include <unistd.h>
23#include <string.h>
24#include <sysdep.h>
25#include <dl-sysdep.h>
26#include <set-hooks.h>
27#include "hurdstartup.h"
28
29#include <ldsodefs.h>
30#include <fpu_control.h>
31#include <libc-diag.h>
32#include <libc-internal.h>
33
34extern void __mach_init (void);
35extern void __init_misc (int, char **, char **);
36
37extern int __libc_argc attribute_hidden;
38extern char **__libc_argv attribute_hidden;
39extern char **_dl_argv;
40
41#if !defined (SHARED) && (defined (THREAD_SET_STACK_GUARD) || defined (THREAD_SET_POINTER_GUARD))
42/* In the static case, we need to set up TLS early so that the stack
43 protection guard can be read at from TLS by the GCC-generated snippets,
44 on architectures that store the guard in TLS and not globally. */
45# define USE_INIT1_TCBHEAD 1
46#else
47# define USE_INIT1_TCBHEAD 0
48#endif
49
50#if USE_INIT1_TCBHEAD
51static tcbhead_t __init1_tcbhead;
52#endif
53
54/* Things that want to be run before _hurd_init or much anything else.
55 Importantly, these are called before anything tries to use malloc. */
56DEFINE_HOOK (_hurd_preinit_hook, (void));
57
58
59/* We call this once the Hurd magic is all set up and we are ready to be a
60 Posixoid program. This does the same things the generic version does. */
61static void
62posixland_init (int argc, char **argv, char **envp)
63{
64 /* Now we have relocations etc. we can start signals etc. */
65 _hurd_libc_proc_init (argv);
66
67#ifdef SHARED
68 /* Make sure we don't initialize twice. */
69 if (__libc_initial)
70 {
71 /* Set the FPU control word to the proper default value. */
72 __setfpucw (__fpu_control);
73 }
74 else
75 {
76 /* Initialize data structures so the additional libc can do RPCs. */
77 __mach_init ();
78 }
79#else /* !SHARED */
80 __setfpucw (__fpu_control);
81#endif
82
83 /* Save the command-line arguments. */
84 __libc_argc = argc;
85 __libc_argv = argv;
86 __environ = envp;
87
88#ifndef SHARED
89 _dl_non_dynamic_init ();
90#endif
91 __init_misc (argc, argv, envp);
92}
93
94static void
95init (void **data)
96{
97 int argc = (int) (uintptr_t) *data;
98 char **argv = (void *) (data + 1);
99 char **envp = &argv[argc + 1];
100 struct hurd_startup_data *d;
101
102 /* Since the cthreads initialization code uses malloc, and the
103 malloc initialization code needs to get at the environment, make
104 sure we can find it. We'll need to do this again later on since
105 switching stacks changes the location where the environment is
106 stored. */
107 __environ = envp;
108
109 while (*envp)
110 ++envp;
111 d = (void *) ++envp;
112
113#ifndef SHARED
114
115 /* If we are the bootstrap task started by the kernel,
116 then after the environment pointers there is no Hurd
117 data block; the argument strings start there. */
118 if ((void *) d == argv[0] || d->phdr == 0)
119 {
120 __libc_enable_secure = 0;
121 /* With a new enough linker (binutils-2.23 or better),
122 the magic __ehdr_start symbol will be available and
123 __libc_start_main will have done this that way already. */
124 if (_dl_phdr == NULL)
125 {
126 /* We may need to see our own phdrs, e.g. for TLS setup.
127 Try the usual kludge to find the headers without help from
128 the exec server. */
129 extern const void __executable_start;
130 const ElfW(Ehdr) *const ehdr = &__executable_start;
131 _dl_phdr = (const void *) ehdr + ehdr->e_phoff;
132 _dl_phnum = ehdr->e_phnum;
133 assert (ehdr->e_phentsize == sizeof (ElfW(Phdr)));
134 }
135 }
136 else
137 {
138 __libc_enable_secure = d->flags & EXEC_SECURE;
139 _dl_phdr = (ElfW(Phdr) *) d->phdr;
140 _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr));
141 assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0);
142 }
143#endif
144
145 if ((void *) d == argv[0])
146 return;
147
148 _hurd_init_dtable = d->dtable;
149 _hurd_init_dtablesize = d->dtablesize;
150
151 if (d->portarray || d->intarray)
152 /* Initialize library data structures, start signal processing, etc. */
153 _hurd_init (d->flags, argv,
154 d->portarray, d->portarraysize,
155 d->intarray, d->intarraysize);
156}
157
158/* Do the first essential initializations that must precede all else. */
159static inline void
160first_init (void)
161{
162 /* Initialize data structures so we can do RPCs. */
163 __mach_init ();
164
165#ifndef SHARED
166 GLRO(dl_pagesize) = __vm_page_size;
167#endif
168
169#if USE_INIT1_TCBHEAD
170 _hurd_tls_init (&__init1_tcbhead, 0);
171#endif
172
173 RUN_RELHOOK (_hurd_preinit_hook, ());
174}
175
176#ifdef SHARED
177/* This function is called specially by the dynamic linker to do early
178 initialization of the shared C library before normal initializers
179 expecting a Posixoid environment can run. */
180
181void
182_dl_init_first (void *data)
183{
184 first_init ();
185 init (data);
186}
187
188/* The regular posixland initialization is what goes into libc's
189 normal initializer. */
190/* NOTE! The linker notices the magical name `_init' and sets the DT_INIT
191 pointer in the dynamic section based solely on that. It is convention
192 for this function to be in the `.init' section, but the symbol name is
193 the only thing that really matters!! */
194strong_alias (posixland_init, _init);
195
196void
197__libc_init_first (int argc, char **argv, char **envp)
198{
199 /* Everything was done in the shared library initializer, _init. */
200}
201
202#else /* SHARED */
203
204strong_alias (posixland_init, __libc_init_first);
205
206/* XXX This is all a crock and I am not happy with it.
207 This poorly-named function is called by static-start.S,
208 which should not exist at all. */
209void
210inhibit_stack_protector
211_hurd_stack_setup (void **argptr)
212{
213 /* This is the very first C code that runs in a statically linked
214 executable -- calling this function is the first thing that _start in
215 static-start.S does. Once this function returns, the unusual way that it
216 does (see below), _start jumps to _start1, the regular start-up code.
217
218 _start1 expects the arguments, environment, and a Hurd data block to be
219 located at the top of the stack. The data may already be located there,
220 or we may need to receive it from the exec server. If the data is located
221 on the stack (just above our call frame), argptr points to it. Note that
222 this may not be a valid pointer in case we're supposed to receive the
223 arguments from the exec server, so we can not dereference it yet. */
224
225 void *caller = __builtin_extract_return_addr (__builtin_return_address (0));
226 /* Init the essential things. */
227 first_init ();
228
229 void doinit (intptr_t *data)
230 {
231 init ((void **) data);
232 RETURN_TO (data, caller, 0);
233 __builtin_unreachable ();
234 }
235
236 /* _hurd_startup () will attempt to receive the data block from the exec
237 server; or if that is not possible, will take the data from the pointer
238 we pass it here. The important point here is that the data
239 _hurd_startup () collects may be allocated in its stack frame (with
240 alloca), which is why _hurd_startup () does not return the normal way.
241 Instead, it invokes a callback (which is not expected to return normally
242 either).
243
244 Our callback not only passes the data pointer to init (), but also jumps
245 out of the call stack back to our caller (i.e. to _start1), while setting
246 the stack pointer to the data (which is somewhere on the current stack
247 anyway). This way, _start1 find the data on the top of the stack, just as
248 it expects to. */
249 _hurd_startup (argptr, &doinit);
250 __builtin_unreachable ();
251}
252#endif
253
254
255/* This function is defined here so that if this file ever gets into
256 ld.so we will get a link error. Having this file silently included
257 in ld.so causes disaster, because the _init definition above will
258 cause ld.so to gain an init function, which is not a cool thing. */
259
260void
261_dl_start (void)
262{
263 abort ();
264}
265

source code of glibc/sysdeps/mach/hurd/init-first.c