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 | |
34 | extern void __mach_init (void); |
35 | extern void __init_misc (int, char **, char **); |
36 | |
37 | extern int __libc_argc attribute_hidden; |
38 | extern char **__libc_argv attribute_hidden; |
39 | extern 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 |
51 | static 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. */ |
56 | DEFINE_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. */ |
61 | static void |
62 | posixland_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 | |
94 | static void |
95 | init (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. */ |
159 | static inline void |
160 | first_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 | |
181 | void |
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!! */ |
194 | strong_alias (posixland_init, _init); |
195 | |
196 | void |
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 | |
204 | strong_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. */ |
209 | void |
210 | inhibit_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 | |
260 | void |
261 | _dl_start (void) |
262 | { |
263 | abort (); |
264 | } |
265 | |