1 | /* Operating system support for run-time dynamic linker. Hurd version. |
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 | /* In the static library, this is all handled by dl-support.c |
20 | or by the vanilla definitions in the rest of the C library. */ |
21 | #ifdef SHARED |
22 | |
23 | #include <hurd.h> |
24 | #include <link.h> |
25 | #include <unistd.h> |
26 | #include <fcntl.h> |
27 | #include <stdlib.h> |
28 | #include <sys/mman.h> |
29 | #include <ldsodefs.h> |
30 | #include <sys/wait.h> |
31 | #include <assert.h> |
32 | #include <sysdep.h> |
33 | #include <argz.h> |
34 | #include <mach/mig_support.h> |
35 | #include "hurdstartup.h" |
36 | #include <hurd/lookup.h> |
37 | #include <hurd/auth.h> |
38 | #include <hurd/term.h> |
39 | #include <stdarg.h> |
40 | #include <ctype.h> |
41 | #include <sys/stat.h> |
42 | #include <sys/uio.h> |
43 | |
44 | #include <entry.h> |
45 | #include <dl-machine.h> |
46 | #include <dl-procinfo.h> |
47 | |
48 | #include <dl-tunables.h> |
49 | #include <not-errno.h> |
50 | #include <not-cancel.h> |
51 | |
52 | extern void __mach_init (void); |
53 | |
54 | extern int _dl_argc; |
55 | extern char **_dl_argv; |
56 | extern char **_environ; |
57 | |
58 | int __libc_enable_secure = 0; |
59 | rtld_hidden_data_def (__libc_enable_secure) |
60 | /* This variable contains the lowest stack address ever used. */ |
61 | void *__libc_stack_end = NULL; |
62 | rtld_hidden_data_def(__libc_stack_end) |
63 | |
64 | /* TODO: Initialize. */ |
65 | void *_dl_random attribute_relro = NULL; |
66 | |
67 | struct hurd_startup_data *_dl_hurd_data; |
68 | |
69 | |
70 | ElfW(Addr) |
71 | _dl_sysdep_start (void **start_argptr, |
72 | void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent, |
73 | ElfW(Addr) *user_entry, |
74 | ElfW(auxv_t) *auxv)) |
75 | { |
76 | void go (intptr_t *argdata) |
77 | { |
78 | char *orig_argv0; |
79 | char **p; |
80 | |
81 | /* Cache the information in various global variables. */ |
82 | _dl_argc = *argdata; |
83 | _dl_argv = 1 + (char **) argdata; |
84 | _environ = &_dl_argv[_dl_argc + 1]; |
85 | for (p = _environ; *p++;); /* Skip environ pointers and terminator. */ |
86 | |
87 | orig_argv0 = _dl_argv[0]; |
88 | |
89 | if ((void *) p == _dl_argv[0]) |
90 | { |
91 | static struct hurd_startup_data nodata; |
92 | _dl_hurd_data = &nodata; |
93 | nodata.user_entry = (vm_address_t) ENTRY_POINT; |
94 | } |
95 | else |
96 | _dl_hurd_data = (void *) p; |
97 | |
98 | GLRO(dl_platform) = NULL; /* Default to nothing known about the platform. */ |
99 | |
100 | __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE; |
101 | |
102 | __tunables_init (_environ); |
103 | |
104 | /* Initialize DSO sorting algorithm after tunables. */ |
105 | _dl_sort_maps_init (); |
106 | |
107 | #ifdef DL_SYSDEP_INIT |
108 | DL_SYSDEP_INIT; |
109 | #endif |
110 | |
111 | #ifdef DL_PLATFORM_INIT |
112 | DL_PLATFORM_INIT; |
113 | #endif |
114 | |
115 | /* Determine the length of the platform name. */ |
116 | if (GLRO(dl_platform) != NULL) |
117 | GLRO(dl_platformlen) = strlen (GLRO(dl_platform)); |
118 | |
119 | if (_dl_hurd_data->flags & EXEC_STACK_ARGS |
120 | && _dl_hurd_data->user_entry == 0) |
121 | _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT; |
122 | |
123 | #if 0 /* XXX make this work for real someday... */ |
124 | if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT) |
125 | /* We were invoked as a command, not as the program interpreter. |
126 | The generic ld.so code supports this: it will parse the args |
127 | as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we |
128 | support an additional special syntax: |
129 | ld.so [-LIBS...] PROGRAM [ARGS...] |
130 | Each LIBS word consists of "FILENAME=MEMOBJ"; |
131 | for example "-/lib/libc.so=123" says that the contents of |
132 | /lib/libc.so are found in a memory object whose port name |
133 | in our task is 123. */ |
134 | while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-') |
135 | { |
136 | char *lastslash, *memobjname, *p; |
137 | struct link_map *l; |
138 | mach_port_t memobj; |
139 | error_t err; |
140 | |
141 | --_dl_argc; |
142 | p = _dl_argv++[1] + 1; |
143 | |
144 | memobjname = strchr (p, '='); |
145 | if (! memobjname) |
146 | _dl_sysdep_fatal ("Bogus library spec: " , p, "\n" , NULL); |
147 | *memobjname++ = '\0'; |
148 | memobj = 0; |
149 | while (*memobjname != '\0') |
150 | memobj = (memobj * 10) + (*memobjname++ - '0'); |
151 | |
152 | /* Add a user reference on the memory object port, so we will |
153 | still have one after _dl_map_object_from_fd calls our |
154 | `close'. */ |
155 | err = __mach_port_mod_refs (__mach_task_self (), memobj, |
156 | MACH_PORT_RIGHT_SEND, +1); |
157 | assert_perror (err); |
158 | |
159 | lastslash = strrchr (p, '/'); |
160 | l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p, NULL, |
161 | memobj, strdup (p), 0); |
162 | |
163 | /* Squirrel away the memory object port where it |
164 | can be retrieved by the program later. */ |
165 | l->l_info[DT_NULL] = (void *) memobj; |
166 | } |
167 | #endif |
168 | |
169 | /* Call elf/rtld.c's main program. It will set everything |
170 | up and leave us to transfer control to USER_ENTRY. */ |
171 | (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr, |
172 | _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)), |
173 | (ElfW(Addr) *) &_dl_hurd_data->user_entry, NULL); |
174 | |
175 | /* The call above might screw a few things up. |
176 | |
177 | P is the location after the terminating NULL of the list of |
178 | environment variables. It has to point to the Hurd startup |
179 | data or if that's missing then P == ARGV[0] must hold. The |
180 | startup code in init-first.c will get confused if this is not |
181 | the case, so we must rearrange things to make it so. We'll |
182 | recompute P and move the Hurd data or the new ARGV[0] there. |
183 | |
184 | Note: directly invoked ld.so can move arguments and env vars. |
185 | |
186 | We use memmove, since the locations might overlap. */ |
187 | |
188 | char **newp; |
189 | for (newp = _environ; *newp++;); |
190 | |
191 | if (newp != p || _dl_argv[0] != orig_argv0) |
192 | { |
193 | if (orig_argv0 == (char *) p) |
194 | { |
195 | if ((char *) newp != _dl_argv[0]) |
196 | { |
197 | assert ((char *) newp < _dl_argv[0]); |
198 | _dl_argv[0] = memmove ((char *) newp, _dl_argv[0], |
199 | strlen (_dl_argv[0]) + 1); |
200 | } |
201 | } |
202 | else |
203 | { |
204 | if ((void *) newp != _dl_hurd_data) |
205 | memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data)); |
206 | } |
207 | } |
208 | |
209 | _dl_init_first (argdata); |
210 | |
211 | { |
212 | extern void _dl_start_user (void); |
213 | /* Unwind the stack to ARGDATA and simulate a return from _dl_start |
214 | to the RTLD_START code which will run the user's entry point. */ |
215 | RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry); |
216 | } |
217 | } |
218 | |
219 | /* Set up so we can do RPCs. */ |
220 | __mach_init (); |
221 | |
222 | /* Initialize frequently used global variable. */ |
223 | GLRO(dl_pagesize) = __getpagesize (); |
224 | |
225 | /* See hurd/hurdstartup.c; this deals with getting information |
226 | from the exec server and slicing up the arguments. |
227 | Then it will call `go', above. */ |
228 | _hurd_startup (start_argptr, &go); |
229 | |
230 | LOSE; |
231 | abort (); |
232 | } |
233 | |
234 | void |
235 | _dl_sysdep_start_cleanup (void) |
236 | { |
237 | /* Deallocate the reply port and task port rights acquired by |
238 | __mach_init. We are done with them now, and the user will |
239 | reacquire them for himself when he wants them. */ |
240 | __mig_dealloc_reply_port (__mig_get_reply_port ()); |
241 | __mach_port_deallocate (__mach_task_self (), __mach_host_self_); |
242 | __mach_port_deallocate (__mach_task_self (), __mach_task_self_); |
243 | } |
244 | |
245 | /* Minimal open/close/mmap/etc. implementation sufficient for initial loading of |
246 | shared libraries. These are weak definitions so that when the |
247 | dynamic linker re-relocates itself to be user-visible (for -ldl), |
248 | it will get the user's definition (i.e. usually libc's). |
249 | |
250 | They also need to be set in the libc and ld section of |
251 | sysdeps/mach/hurd/Versions, to be overridable, and in libc.abilist and |
252 | ld.abilist to be checked. */ |
253 | |
254 | /* This macro checks that the function does not get renamed to be hidden: we do |
255 | need these to be overridable by libc's. */ |
256 | #define check_no_hidden(name) \ |
257 | __typeof (name) __check_##name##_no_hidden \ |
258 | __attribute__ ((alias (#name))) \ |
259 | __attribute_copy__ (name); |
260 | |
261 | /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an |
262 | error. If STAT is non-zero, stat the file into that stat buffer. */ |
263 | static error_t |
264 | open_file (const char *file_name, int flags, |
265 | mach_port_t *port, struct stat64 *stat) |
266 | { |
267 | enum retry_type doretry; |
268 | char retryname[1024]; /* XXX string_t LOSES! */ |
269 | file_t startdir; |
270 | error_t err; |
271 | |
272 | error_t use_init_port (int which, error_t (*operate) (file_t)) |
273 | { |
274 | return (which < _dl_hurd_data->portarraysize |
275 | ? ((*operate) (_dl_hurd_data->portarray[which])) |
276 | : EGRATUITOUS); |
277 | } |
278 | file_t get_dtable_port (int fd) |
279 | { |
280 | if ((unsigned int) fd < _dl_hurd_data->dtablesize |
281 | && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL) |
282 | { |
283 | __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd], |
284 | MACH_PORT_RIGHT_SEND, +1); |
285 | return _dl_hurd_data->dtable[fd]; |
286 | } |
287 | return __hurd_fail (EBADF), MACH_PORT_NULL; |
288 | } |
289 | |
290 | assert (!(flags & ~(O_READ | O_EXEC | O_CLOEXEC | O_IGNORE_CTTY))); |
291 | flags &= ~(O_CLOEXEC | O_IGNORE_CTTY); |
292 | |
293 | startdir = _dl_hurd_data->portarray[file_name[0] == '/' |
294 | ? INIT_PORT_CRDIR : INIT_PORT_CWDIR]; |
295 | |
296 | while (file_name[0] == '/') |
297 | file_name++; |
298 | |
299 | err = __dir_lookup (startdir, (char *)file_name, flags, 0, |
300 | &doretry, retryname, port); |
301 | |
302 | if (!err) |
303 | err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port, |
304 | __dir_lookup, doretry, retryname, |
305 | flags, 0, port); |
306 | if (!err && stat) |
307 | { |
308 | err = __io_stat (*port, stat); |
309 | if (err) |
310 | __mach_port_deallocate (__mach_task_self (), *port); |
311 | } |
312 | |
313 | return err; |
314 | } |
315 | |
316 | check_no_hidden(__open); |
317 | check_no_hidden (__open64); |
318 | check_no_hidden (__open_nocancel); |
319 | int weak_function |
320 | __open (const char *file_name, int mode, ...) |
321 | { |
322 | mach_port_t port; |
323 | error_t err = open_file (file_name, mode, &port, 0); |
324 | if (err) |
325 | return __hurd_fail (err); |
326 | else |
327 | return (int)port; |
328 | } |
329 | weak_alias (__open, __open64) |
330 | weak_alias (__open, __open_nocancel) |
331 | |
332 | check_no_hidden(__close); |
333 | check_no_hidden(__close_nocancel); |
334 | int weak_function |
335 | __close (int fd) |
336 | { |
337 | if (fd != (int) MACH_PORT_NULL) |
338 | __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd); |
339 | return 0; |
340 | } |
341 | weak_alias (__close, __close_nocancel) |
342 | |
343 | check_no_hidden(__pread64); |
344 | check_no_hidden(__pread64_nocancel); |
345 | __ssize_t weak_function |
346 | __pread64 (int fd, void *buf, size_t nbytes, off64_t offset) |
347 | { |
348 | error_t err; |
349 | char *data; |
350 | mach_msg_type_number_t nread; |
351 | |
352 | data = buf; |
353 | nread = nbytes; |
354 | err = __io_read ((mach_port_t) fd, &data, &nread, offset, nbytes); |
355 | if (err) |
356 | return __hurd_fail (err); |
357 | |
358 | if (data != buf) |
359 | { |
360 | memcpy (buf, data, nread); |
361 | __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread); |
362 | } |
363 | |
364 | return nread; |
365 | } |
366 | libc_hidden_weak (__pread64) |
367 | weak_alias (__pread64, __pread64_nocancel) |
368 | |
369 | check_no_hidden(__read); |
370 | check_no_hidden(__read_nocancel); |
371 | __ssize_t weak_function |
372 | __read (int fd, void *buf, size_t nbytes) |
373 | { |
374 | return __pread64 (fd, buf, nbytes, -1); |
375 | } |
376 | libc_hidden_weak (__read) |
377 | weak_alias (__read, __read_nocancel) |
378 | |
379 | check_no_hidden(__write); |
380 | check_no_hidden(__write_nocancel); |
381 | __ssize_t weak_function |
382 | __write (int fd, const void *buf, size_t nbytes) |
383 | { |
384 | error_t err; |
385 | vm_size_t nwrote; |
386 | |
387 | assert (fd < _hurd_init_dtablesize); |
388 | |
389 | err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote); |
390 | if (err) |
391 | return __hurd_fail (err); |
392 | |
393 | return nwrote; |
394 | } |
395 | libc_hidden_weak (__write) |
396 | weak_alias (__write, __write_nocancel) |
397 | |
398 | /* This is only used for printing messages (see dl-misc.c). */ |
399 | check_no_hidden(__writev); |
400 | __ssize_t weak_function |
401 | __writev (int fd, const struct iovec *iov, int niov) |
402 | { |
403 | if (fd >= _hurd_init_dtablesize) |
404 | return __hurd_fail (EBADF); |
405 | |
406 | int i; |
407 | size_t total = 0; |
408 | for (i = 0; i < niov; ++i) |
409 | total += iov[i].iov_len; |
410 | |
411 | if (total != 0) |
412 | { |
413 | char buf[total], *bufp = buf; |
414 | error_t err; |
415 | vm_size_t nwrote; |
416 | |
417 | for (i = 0; i < niov; ++i) |
418 | bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len) |
419 | + iov[i].iov_len); |
420 | |
421 | err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote); |
422 | if (err) |
423 | return __hurd_fail (err); |
424 | |
425 | return nwrote; |
426 | } |
427 | return 0; |
428 | } |
429 | |
430 | check_no_hidden(__libc_lseek64); |
431 | off64_t weak_function |
432 | __libc_lseek64 (int fd, off64_t offset, int whence) |
433 | { |
434 | error_t err; |
435 | |
436 | err = __io_seek ((mach_port_t) fd, offset, whence, &offset); |
437 | if (err) |
438 | return __hurd_fail (err); |
439 | |
440 | return offset; |
441 | } |
442 | |
443 | check_no_hidden(__mmap); |
444 | void *weak_function |
445 | __mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset) |
446 | { |
447 | error_t err; |
448 | vm_prot_t vmprot; |
449 | vm_address_t mapaddr, mask; |
450 | mach_port_t memobj_rd, memobj_wr; |
451 | |
452 | vmprot = VM_PROT_NONE; |
453 | if (prot & PROT_READ) |
454 | vmprot |= VM_PROT_READ; |
455 | if (prot & PROT_WRITE) |
456 | vmprot |= VM_PROT_WRITE; |
457 | if (prot & PROT_EXEC) |
458 | vmprot |= VM_PROT_EXECUTE; |
459 | |
460 | #ifdef __LP64__ |
461 | if ((addr == NULL) && (prot & PROT_EXEC) |
462 | && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC)) |
463 | flags |= MAP_32BIT; |
464 | #endif |
465 | mask = (flags & MAP_32BIT) ? ~(vm_address_t) 0x7FFFFFFF : 0; |
466 | |
467 | if (flags & MAP_ANON) |
468 | memobj_rd = MACH_PORT_NULL; |
469 | else |
470 | { |
471 | assert (!(flags & MAP_SHARED)); |
472 | err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr); |
473 | if (err) |
474 | return __hurd_fail (err), MAP_FAILED; |
475 | if (MACH_PORT_VALID (memobj_wr)) |
476 | __mach_port_deallocate (__mach_task_self (), memobj_wr); |
477 | } |
478 | |
479 | mapaddr = (vm_address_t) addr; |
480 | err = __vm_map (__mach_task_self (), |
481 | &mapaddr, (vm_size_t) len, mask, |
482 | !(flags & MAP_FIXED), |
483 | memobj_rd, |
484 | (vm_offset_t) offset, |
485 | flags & (MAP_COPY|MAP_PRIVATE), |
486 | vmprot, VM_PROT_ALL, |
487 | (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY); |
488 | if (err == KERN_NO_SPACE && (flags & MAP_FIXED)) |
489 | { |
490 | /* XXX this is not atomic as it is in unix! */ |
491 | /* The region is already allocated; deallocate it first. */ |
492 | err = __vm_deallocate (__mach_task_self (), mapaddr, len); |
493 | if (! err) |
494 | err = __vm_map (__mach_task_self (), |
495 | &mapaddr, (vm_size_t) len, |
496 | mask, |
497 | !(flags & MAP_FIXED), |
498 | memobj_rd, (vm_offset_t) offset, |
499 | flags & (MAP_COPY|MAP_PRIVATE), |
500 | vmprot, VM_PROT_ALL, |
501 | (flags & MAP_SHARED) |
502 | ? VM_INHERIT_SHARE : VM_INHERIT_COPY); |
503 | } |
504 | |
505 | if ((flags & MAP_ANON) == 0) |
506 | __mach_port_deallocate (__mach_task_self (), memobj_rd); |
507 | |
508 | if (err) |
509 | return __hurd_fail (err), MAP_FAILED; |
510 | return (void *) mapaddr; |
511 | } |
512 | |
513 | check_no_hidden(__fstat64); |
514 | int weak_function |
515 | __fstat64 (int fd, struct stat64 *buf) |
516 | { |
517 | error_t err; |
518 | |
519 | err = __io_stat ((mach_port_t) fd, buf); |
520 | if (err) |
521 | return __hurd_fail (err); |
522 | |
523 | return 0; |
524 | } |
525 | libc_hidden_def (__fstat64) |
526 | |
527 | check_no_hidden(__stat64); |
528 | int weak_function |
529 | __stat64 (const char *file, struct stat64 *buf) |
530 | { |
531 | error_t err; |
532 | mach_port_t port; |
533 | |
534 | err = open_file (file, 0, &port, buf); |
535 | if (err) |
536 | return __hurd_fail (err); |
537 | |
538 | __mach_port_deallocate (__mach_task_self (), port); |
539 | |
540 | return 0; |
541 | } |
542 | libc_hidden_def (__stat64) |
543 | |
544 | /* This function is called by the dynamic linker (rtld.c) to check for |
545 | existence of /etc/ld.so.preload. This stub will always fail, which |
546 | means that /etc/ld.so.preload is unsupported. */ |
547 | check_no_hidden(__access); |
548 | int weak_function |
549 | __access (const char *file, int type) |
550 | { |
551 | return __hurd_fail (ENOSYS); |
552 | } |
553 | |
554 | int |
555 | __rtld_execve (const char *file_name, char *const argv[], |
556 | char *const envp[]) |
557 | { |
558 | file_t file; |
559 | error_t err; |
560 | char *args, *env; |
561 | size_t argslen, envlen; |
562 | mach_port_t *ports = _dl_hurd_data->portarray; |
563 | unsigned int portarraysize = _dl_hurd_data->portarraysize; |
564 | file_t *dtable = _dl_hurd_data->dtable; |
565 | unsigned int dtablesize = _dl_hurd_data->dtablesize; |
566 | int *intarray = _dl_hurd_data->intarray; |
567 | unsigned int i, j; |
568 | mach_port_t *please_dealloc, *pdp; |
569 | mach_port_t *portnames = NULL; |
570 | mach_msg_type_number_t nportnames = 0; |
571 | mach_port_type_t *porttypes = NULL; |
572 | mach_msg_type_number_t nporttypes = 0; |
573 | int flags; |
574 | |
575 | err = open_file (file_name, O_EXEC, &file, NULL); |
576 | if (err) |
577 | goto out; |
578 | |
579 | if (argv == NULL) |
580 | args = NULL, argslen = 0; |
581 | else if (err = __argz_create (argv, &args, &argslen)) |
582 | goto outfile; |
583 | if (envp == NULL) |
584 | env = NULL, envlen = 0; |
585 | else if (err = __argz_create (envp, &env, &envlen)) |
586 | goto outargs; |
587 | |
588 | please_dealloc = __alloca ((portarraysize + dtablesize) |
589 | * sizeof (mach_port_t)); |
590 | pdp = please_dealloc; |
591 | |
592 | /* Get all ports that we may not know about and we should thus destroy. */ |
593 | err = __mach_port_names (__mach_task_self (), |
594 | &portnames, &nportnames, |
595 | &porttypes, &nporttypes); |
596 | if (err) |
597 | goto outenv; |
598 | if (nportnames != nporttypes) |
599 | { |
600 | err = EGRATUITOUS; |
601 | goto outenv; |
602 | } |
603 | |
604 | for (i = 0; i < portarraysize; ++i) |
605 | if (ports[i] != MACH_PORT_NULL) |
606 | { |
607 | *pdp++ = ports[i]; |
608 | for (j = 0; j < nportnames; j++) |
609 | if (portnames[j] == ports[i]) |
610 | portnames[j] = MACH_PORT_NULL; |
611 | } |
612 | for (i = 0; i < dtablesize; ++i) |
613 | if (dtable[i] != MACH_PORT_NULL) |
614 | { |
615 | *pdp++ = dtable[i]; |
616 | for (j = 0; j < nportnames; j++) |
617 | if (portnames[j] == dtable[i]) |
618 | portnames[j] = MACH_PORT_NULL; |
619 | } |
620 | |
621 | /* Pack ports to be destroyed together. */ |
622 | for (i = 0, j = 0; i < nportnames; i++) |
623 | { |
624 | if (portnames[i] == MACH_PORT_NULL) |
625 | continue; |
626 | if (j != i) |
627 | portnames[j] = portnames[i]; |
628 | j++; |
629 | } |
630 | nportnames = j; |
631 | |
632 | flags = 0; |
633 | #ifdef EXEC_SIGTRAP |
634 | if (__sigismember (&intarray[INIT_TRACEMASK], SIGKILL)) |
635 | flags |= EXEC_SIGTRAP; |
636 | #endif |
637 | |
638 | err = __file_exec_paths (file, __mach_task_self (), flags, |
639 | file_name, file_name[0] == '/' ? file_name : "" , |
640 | args, argslen, |
641 | env, envlen, |
642 | dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize, |
643 | ports, MACH_MSG_TYPE_COPY_SEND, portarraysize, |
644 | intarray, INIT_INT_MAX, |
645 | please_dealloc, pdp - please_dealloc, |
646 | portnames, nportnames); |
647 | |
648 | /* Oh well. Might as well be tidy. */ |
649 | outenv: |
650 | free (env); |
651 | outargs: |
652 | free (args); |
653 | outfile: |
654 | __mach_port_deallocate (__mach_task_self (), file); |
655 | out: |
656 | return err; |
657 | } |
658 | |
659 | check_no_hidden(__getpid); |
660 | pid_t weak_function |
661 | __getpid (void) |
662 | { |
663 | pid_t pid, ppid; |
664 | int orphaned; |
665 | |
666 | if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC], |
667 | &pid, &ppid, &orphaned)) |
668 | return -1; |
669 | |
670 | return pid; |
671 | } |
672 | |
673 | /* We need this alias to satisfy references from libc_pic.a objects |
674 | that were affected by the libc_hidden_proto declaration for __getpid. */ |
675 | strong_alias (__getpid, __GI___getpid) |
676 | |
677 | /* This is called only in some strange cases trying to guess a value |
678 | for $ORIGIN for the executable. The dynamic linker copes with |
679 | getcwd failing (dl-object.c), and it's too much hassle to include |
680 | the functionality here. (We could, it just requires duplicating or |
681 | reusing getcwd.c's code but using our special lookup function as in |
682 | `open', above.) */ |
683 | check_no_hidden(__getcwd); |
684 | char *weak_function |
685 | __getcwd (char *buf, size_t size) |
686 | { |
687 | return __hurd_fail (ENOSYS), NULL; |
688 | } |
689 | |
690 | /* This is used by dl-tunables.c to strdup strings. We can just make this a |
691 | mere allocation. */ |
692 | check_no_hidden(__sbrk); |
693 | void *weak_function |
694 | __sbrk (intptr_t increment) |
695 | { |
696 | vm_address_t addr; |
697 | if (__vm_allocate (__mach_task_self (), &addr, increment, 1)) |
698 | return NULL; |
699 | return (void *) addr; |
700 | } |
701 | |
702 | /* This is only used by hurdlookup for the /dev/fd/nnn magic. |
703 | * We avoid pulling the whole libc implementation, and we can keep this hidden. */ |
704 | unsigned long int weak_function |
705 | __strtoul_internal (const char *nptr, char **endptr, int base, int group) |
706 | { |
707 | assert (base == 0 || base == 10); |
708 | assert (group == 0); |
709 | return _dl_strtoul (nptr, endptr); |
710 | } |
711 | |
712 | /* We need this alias to satisfy references from libc_pic.a objects |
713 | that were affected by the libc_hidden_proto declaration for __strtoul_internal. */ |
714 | strong_alias (__strtoul_internal, __GI___strtoul_internal) |
715 | strong_alias (__strtoul_internal, __GI_____strtoul_internal) |
716 | |
717 | check_no_hidden(_exit); |
718 | void weak_function attribute_hidden |
719 | _exit (int status) |
720 | { |
721 | __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC], |
722 | W_EXITCODE (status, 0), 0); |
723 | while (__task_terminate (__mach_task_self ())) |
724 | __mach_task_self_ = (__mach_task_self) (); |
725 | |
726 | LOSE; |
727 | abort (); |
728 | } |
729 | /* We need this alias to satisfy references from libc_pic.a objects |
730 | that were affected by the libc_hidden_proto declaration for _exit. */ |
731 | strong_alias (_exit, __GI__exit) |
732 | |
733 | /* Try to get a machine dependent instruction which will make the |
734 | program crash. This is used in case everything else fails. */ |
735 | #include <abort-instr.h> |
736 | #ifndef ABORT_INSTRUCTION |
737 | /* No such instruction is available. */ |
738 | # define ABORT_INSTRUCTION |
739 | #endif |
740 | |
741 | check_no_hidden(abort); |
742 | void weak_function |
743 | abort (void) |
744 | { |
745 | /* Try to abort using the system specific command. */ |
746 | ABORT_INSTRUCTION; |
747 | |
748 | /* If the abort instruction failed, exit. */ |
749 | _exit (127); |
750 | |
751 | /* If even this fails, make sure we never return. */ |
752 | while (1) |
753 | /* Try for ever and ever. */ |
754 | ABORT_INSTRUCTION; |
755 | } |
756 | |
757 | /* We need this alias to satisfy references from libc_pic.a objects |
758 | that were affected by the libc_hidden_proto declaration for abort. */ |
759 | strong_alias (abort, __GI_abort) |
760 | strong_alias (abort, __GI___fortify_fail) |
761 | strong_alias (abort, __GI___assert_fail) |
762 | strong_alias (abort, __GI___assert_perror_fail) |
763 | |
764 | /* This function is called by interruptible RPC stubs. For initial |
765 | dynamic linking, just use the normal mach_msg. Since this defn is |
766 | weak, the real defn in libc.so will override it if we are linked into |
767 | the user program (-ldl). */ |
768 | |
769 | error_t weak_function |
770 | _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, |
771 | mach_msg_option_t option, |
772 | mach_msg_size_t send_size, |
773 | mach_msg_size_t rcv_size, |
774 | mach_port_t rcv_name, |
775 | mach_msg_timeout_t timeout, |
776 | mach_port_t notify) |
777 | { |
778 | return __mach_msg (msg, option, send_size, rcv_size, rcv_name, |
779 | timeout, notify); |
780 | } |
781 | |
782 | |
783 | void |
784 | _dl_show_auxv (void) |
785 | { |
786 | /* There is nothing to print. Hurd has no auxiliary vector. */ |
787 | } |
788 | |
789 | |
790 | void weak_function |
791 | _dl_init_first (void *p) |
792 | { |
793 | /* This no-op definition only gets used if libc is not linked in. */ |
794 | } |
795 | |
796 | #endif /* SHARED */ |
797 | |