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