Fix Hurd glibc build with GCC 8.
[glibc.git] / sysdeps / mach / hurd / dl-sysdep.c
blob547108805e5213ef734bca549822bce92c97066a
1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995-2018 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, see
17 <http://www.gnu.org/licenses/>. */
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
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 <mach/mig_support.h>
34 #include <mach/machine/vm_param.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>
44 #include <entry.h>
45 #include <dl-machine.h>
46 #include <dl-procinfo.h>
48 #include <dl-tunables.h>
49 #include <not-errno.h>
51 extern void __mach_init (void);
53 extern int _dl_argc;
54 extern char **_dl_argv;
55 extern char **_environ;
57 int __libc_enable_secure = 0;
58 rtld_hidden_data_def (__libc_enable_secure)
59 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
60 of init-first. */
61 /* This variable contains the lowest stack address ever used. */
62 void *__libc_stack_end = NULL;
63 rtld_hidden_data_def(__libc_stack_end)
65 #if HP_TIMING_AVAIL
66 hp_timing_t _dl_cpuclock_offset;
67 #endif
69 /* TODO: Initialize. */
70 void *_dl_random attribute_relro = NULL;
72 struct hurd_startup_data *_dl_hurd_data;
74 #define FMH defined(__i386__)
75 #if ! FMH
76 # define fmh() ((void)0)
77 # define unfmh() ((void)0)
78 #else
79 /* XXX loser kludge for vm_map kernel bug */
80 #undef ELF_MACHINE_USER_ADDRESS_MASK
81 #define ELF_MACHINE_USER_ADDRESS_MASK 0
82 static vm_address_t fmha;
83 static vm_size_t fmhs;
84 static void unfmh(void){
85 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
86 static void fmh(void) {
87 error_t err;int x;vm_offset_t o;mach_port_t p;
88 vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
89 while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&o))){
90 __mach_port_deallocate(__mach_task_self(),p);
91 if (a+fmhs>=0x80000000U){
92 max=a; break;}
93 fmha=a+=fmhs;}
94 if (err) assert(err==KERN_NO_SPACE);
95 if (!fmha)fmhs=0;else{
96 fmhs=max-fmha;
97 err = __vm_map (__mach_task_self (),
98 &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
99 VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
100 assert_perror(err);}
102 /* XXX loser kludge for vm_map kernel bug */
103 #endif
106 ElfW(Addr)
107 _dl_sysdep_start (void **start_argptr,
108 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
109 ElfW(Addr) *user_entry,
110 ElfW(auxv_t) *auxv))
112 void go (intptr_t *argdata)
114 char **p;
116 /* Cache the information in various global variables. */
117 _dl_argc = *argdata;
118 _dl_argv = 1 + (char **) argdata;
119 _environ = &_dl_argv[_dl_argc + 1];
120 for (p = _environ; *p++;); /* Skip environ pointers and terminator. */
122 if ((void *) p == _dl_argv[0])
124 static struct hurd_startup_data nodata;
125 _dl_hurd_data = &nodata;
126 nodata.user_entry = (vm_address_t) ENTRY_POINT;
128 else
129 _dl_hurd_data = (void *) p;
131 __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE;
133 __tunables_init (_environ);
135 if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
136 _dl_hurd_data->user_entry == 0)
137 _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
139 unfmh(); /* XXX */
141 #if 0 /* XXX make this work for real someday... */
142 if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
143 /* We were invoked as a command, not as the program interpreter.
144 The generic ld.so code supports this: it will parse the args
145 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
146 support an additional special syntax:
147 ld.so [-LIBS...] PROGRAM [ARGS...]
148 Each LIBS word consists of "FILENAME=MEMOBJ";
149 for example "-/lib/libc.so=123" says that the contents of
150 /lib/libc.so are found in a memory object whose port name
151 in our task is 123. */
152 while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
154 char *lastslash, *memobjname, *p;
155 struct link_map *l;
156 mach_port_t memobj;
157 error_t err;
159 ++_dl_skip_args;
160 --_dl_argc;
161 p = _dl_argv++[1] + 1;
163 memobjname = strchr (p, '=');
164 if (! memobjname)
165 _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
166 *memobjname++ = '\0';
167 memobj = 0;
168 while (*memobjname != '\0')
169 memobj = (memobj * 10) + (*memobjname++ - '0');
171 /* Add a user reference on the memory object port, so we will
172 still have one after _dl_map_object_from_fd calls our
173 `close'. */
174 err = __mach_port_mod_refs (__mach_task_self (), memobj,
175 MACH_PORT_RIGHT_SEND, +1);
176 assert_perror (err);
178 lastslash = strrchr (p, '/');
179 l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p, NULL,
180 memobj, strdup (p), 0);
182 /* Squirrel away the memory object port where it
183 can be retrieved by the program later. */
184 l->l_info[DT_NULL] = (void *) memobj;
186 #endif
188 /* Call elf/rtld.c's main program. It will set everything
189 up and leave us to transfer control to USER_ENTRY. */
190 (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
191 _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
192 (ElfW(Addr) *) &_dl_hurd_data->user_entry, NULL);
194 /* The call above might screw a few things up.
196 First of all, if _dl_skip_args is nonzero, we are ignoring
197 the first few arguments. However, if we have no Hurd startup
198 data, it is the magical convention that ARGV[0] == P. The
199 startup code in init-first.c will get confused if this is not
200 the case, so we must rearrange things to make it so. We'll
201 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
203 Secondly, if we need to be secure, it removes some dangerous
204 environment variables. If we have no Hurd startup date this
205 changes P (since that's the location after the terminating
206 NULL in the list of environment variables). We do the same
207 thing as in the first case but make sure we recalculate P.
208 If we do have Hurd startup data, we have to move the data
209 such that it starts just after the terminating NULL in the
210 environment list.
212 We use memmove, since the locations might overlap. */
213 if (__libc_enable_secure || _dl_skip_args)
215 char **newp;
217 for (newp = _environ; *newp++;);
219 if (_dl_argv[-_dl_skip_args] == (char *) p)
221 if ((char *) newp != _dl_argv[0])
223 assert ((char *) newp < _dl_argv[0]);
224 _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
225 strlen (_dl_argv[0]) + 1);
228 else
230 if ((void *) newp != _dl_hurd_data)
231 memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
236 extern void _dl_start_user (void);
237 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
238 to the RTLD_START code which will run the user's entry point. */
239 RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
243 /* Set up so we can do RPCs. */
244 __mach_init ();
246 /* Initialize frequently used global variable. */
247 GLRO(dl_pagesize) = __getpagesize ();
249 #if HP_TIMING_AVAIL
250 HP_TIMING_NOW (_dl_cpuclock_offset);
251 #endif
253 fmh(); /* XXX */
255 /* See hurd/hurdstartup.c; this deals with getting information
256 from the exec server and slicing up the arguments.
257 Then it will call `go', above. */
258 _hurd_startup (start_argptr, &go);
260 LOSE;
261 abort ();
264 void
265 _dl_sysdep_start_cleanup (void)
267 /* Deallocate the reply port and task port rights acquired by
268 __mach_init. We are done with them now, and the user will
269 reacquire them for himself when he wants them. */
270 __mig_dealloc_reply_port (MACH_PORT_NULL);
271 __mach_port_deallocate (__mach_task_self (), __mach_host_self_);
272 __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
275 /* Minimal open/close/mmap implementation sufficient for initial loading of
276 shared libraries. These are weak definitions so that when the
277 dynamic linker re-relocates itself to be user-visible (for -ldl),
278 it will get the user's definition (i.e. usually libc's). */
280 /* This macro checks that the function does not get renamed to be hidden: we do
281 need these to be overridable by libc's. */
282 #define check_no_hidden(name) \
283 static __typeof (name) __check_##name##_no_hidden \
284 __attribute__ ((alias (#name)));
286 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
287 error. If STAT is non-zero, stat the file into that stat buffer. */
288 static error_t
289 open_file (const char *file_name, int flags,
290 mach_port_t *port, struct stat64 *stat)
292 enum retry_type doretry;
293 char retryname[1024]; /* XXX string_t LOSES! */
294 file_t startdir;
295 error_t err;
297 error_t use_init_port (int which, error_t (*operate) (file_t))
299 return (which < _dl_hurd_data->portarraysize
300 ? ((*operate) (_dl_hurd_data->portarray[which]))
301 : EGRATUITOUS);
303 file_t get_dtable_port (int fd)
305 if ((unsigned int) fd < _dl_hurd_data->dtablesize
306 && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
308 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
309 MACH_PORT_RIGHT_SEND, +1);
310 return _dl_hurd_data->dtable[fd];
312 errno = EBADF;
313 return MACH_PORT_NULL;
316 assert (!(flags & ~(O_READ | O_CLOEXEC)));
318 startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
319 INIT_PORT_CRDIR : INIT_PORT_CWDIR];
321 while (file_name[0] == '/')
322 file_name++;
324 err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
325 &doretry, retryname, port);
327 if (!err)
328 err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
329 __dir_lookup, doretry, retryname,
330 O_RDONLY, 0, port);
331 if (!err && stat)
333 err = __io_stat (*port, stat);
334 if (err)
335 __mach_port_deallocate (__mach_task_self (), *port);
338 return err;
341 check_no_hidden(__open);
342 int weak_function
343 __open (const char *file_name, int mode, ...)
345 mach_port_t port;
346 error_t err = open_file (file_name, mode, &port, 0);
347 if (err)
348 return __hurd_fail (err);
349 else
350 return (int)port;
353 check_no_hidden(__close);
354 int weak_function
355 __close (int fd)
357 if (fd != (int) MACH_PORT_NULL)
358 __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
359 return 0;
362 check_no_hidden(__libc_read);
363 __ssize_t weak_function
364 __libc_read (int fd, void *buf, size_t nbytes)
366 error_t err;
367 char *data;
368 mach_msg_type_number_t nread;
370 data = buf;
371 nread = nbytes;
372 err = __io_read ((mach_port_t) fd, &data, &nread, -1, nbytes);
373 if (err)
374 return __hurd_fail (err);
376 if (data != buf)
378 memcpy (buf, data, nread);
379 __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
382 return nread;
384 libc_hidden_weak (__libc_read)
386 check_no_hidden(__libc_write);
387 __ssize_t weak_function
388 __libc_write (int fd, const void *buf, size_t nbytes)
390 error_t err;
391 mach_msg_type_number_t nwrote;
393 assert (fd < _hurd_init_dtablesize);
395 err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
396 if (err)
397 return __hurd_fail (err);
399 return nwrote;
401 libc_hidden_weak (__libc_write)
403 /* This is only used for printing messages (see dl-misc.c). */
404 check_no_hidden(__writev);
405 __ssize_t weak_function
406 __writev (int fd, const struct iovec *iov, int niov)
408 if (fd >= _hurd_init_dtablesize)
410 errno = EBADF;
411 return -1;
414 int i;
415 size_t total = 0;
416 for (i = 0; i < niov; ++i)
417 total += iov[i].iov_len;
419 if (total != 0)
421 char buf[total], *bufp = buf;
422 error_t err;
423 mach_msg_type_number_t nwrote;
425 for (i = 0; i < niov; ++i)
426 bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
427 + iov[i].iov_len);
429 err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
430 if (err)
431 return __hurd_fail (err);
433 return nwrote;
435 return 0;
438 check_no_hidden(__libc_lseek64);
439 off64_t weak_function
440 __libc_lseek64 (int fd, off64_t offset, int whence)
442 error_t err;
444 err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
445 if (err)
446 return __hurd_fail (err);
448 return offset;
451 check_no_hidden(__mmap);
452 void *weak_function
453 __mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
455 error_t err;
456 vm_prot_t vmprot;
457 vm_address_t mapaddr;
458 mach_port_t memobj_rd, memobj_wr;
460 vmprot = VM_PROT_NONE;
461 if (prot & PROT_READ)
462 vmprot |= VM_PROT_READ;
463 if (prot & PROT_WRITE)
464 vmprot |= VM_PROT_WRITE;
465 if (prot & PROT_EXEC)
466 vmprot |= VM_PROT_EXECUTE;
468 if (flags & MAP_ANON)
469 memobj_rd = MACH_PORT_NULL;
470 else
472 assert (!(flags & MAP_SHARED));
473 err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
474 if (err)
475 return __hurd_fail (err), MAP_FAILED;
476 if (memobj_wr != MACH_PORT_NULL)
477 __mach_port_deallocate (__mach_task_self (), memobj_wr);
480 mapaddr = (vm_address_t) addr;
481 err = __vm_map (__mach_task_self (),
482 &mapaddr, (vm_size_t) len, ELF_MACHINE_USER_ADDRESS_MASK,
483 !(flags & MAP_FIXED),
484 memobj_rd,
485 (vm_offset_t) offset,
486 flags & (MAP_COPY|MAP_PRIVATE),
487 vmprot, VM_PROT_ALL,
488 (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
489 if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
491 /* XXX this is not atomic as it is in unix! */
492 /* The region is already allocated; deallocate it first. */
493 err = __vm_deallocate (__mach_task_self (), mapaddr, len);
494 if (! err)
495 err = __vm_map (__mach_task_self (),
496 &mapaddr, (vm_size_t) len,
497 ELF_MACHINE_USER_ADDRESS_MASK,
498 !(flags & MAP_FIXED),
499 memobj_rd, (vm_offset_t) offset,
500 flags & (MAP_COPY|MAP_PRIVATE),
501 vmprot, VM_PROT_ALL,
502 (flags & MAP_SHARED)
503 ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
506 if ((flags & MAP_ANON) == 0)
507 __mach_port_deallocate (__mach_task_self (), memobj_rd);
509 if (err)
510 return __hurd_fail (err), MAP_FAILED;
511 return (void *) mapaddr;
514 check_no_hidden(__fxstat64);
515 int weak_function
516 __fxstat64 (int vers, int fd, struct stat64 *buf)
518 error_t err;
520 assert (vers == _STAT_VER);
522 err = __io_stat ((mach_port_t) fd, buf);
523 if (err)
524 return __hurd_fail (err);
526 return 0;
528 libc_hidden_def (__fxstat64)
530 check_no_hidden(__xstat64);
531 int weak_function
532 __xstat64 (int vers, const char *file, struct stat64 *buf)
534 error_t err;
535 mach_port_t port;
537 assert (vers == _STAT_VER);
539 err = open_file (file, 0, &port, buf);
540 if (err)
541 return __hurd_fail (err);
543 __mach_port_deallocate (__mach_task_self (), port);
545 return 0;
547 libc_hidden_def (__xstat64)
549 /* This function is called by the dynamic linker (rtld.c) to check
550 whether debugging malloc is allowed even for SUID binaries. This
551 stub will always fail, which means that malloc-debugging is always
552 disabled for SUID binaries. */
553 check_no_hidden(__access);
554 int weak_function
555 __access (const char *file, int type)
557 errno = ENOSYS;
558 return -1;
560 check_no_hidden(__access_noerrno);
561 int weak_function
562 __access_noerrno (const char *file, int type)
564 return -1;
567 check_no_hidden(__getpid);
568 pid_t weak_function
569 __getpid (void)
571 pid_t pid, ppid;
572 int orphaned;
574 if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
575 &pid, &ppid, &orphaned))
576 return -1;
578 return pid;
581 /* We need this alias to satisfy references from libc_pic.a objects
582 that were affected by the libc_hidden_proto declaration for __getpid. */
583 strong_alias (__getpid, __GI___getpid)
585 /* This is called only in some strange cases trying to guess a value
586 for $ORIGIN for the executable. The dynamic linker copes with
587 getcwd failing (dl-object.c), and it's too much hassle to include
588 the functionality here. (We could, it just requires duplicating or
589 reusing getcwd.c's code but using our special lookup function as in
590 `open', above.) */
591 check_no_hidden(__getcwd);
592 char *weak_function
593 __getcwd (char *buf, size_t size)
595 errno = ENOSYS;
596 return NULL;
599 /* This is used by dl-tunables.c to strdup strings. We can just make this a
600 mere allocation. */
601 check_no_hidden(__sbrk);
602 void *weak_function
603 __sbrk (intptr_t increment)
605 vm_address_t addr;
606 __vm_allocate (__mach_task_self (), &addr, increment, 1);
607 return (void *) addr;
610 check_no_hidden(__strtoul_internal);
611 unsigned long int weak_function
612 __strtoul_internal (const char *nptr, char **endptr, int base, int group)
614 assert (base == 0 || base == 10);
615 assert (group == 0);
616 return _dl_strtoul (nptr, endptr);
619 /* We need this alias to satisfy references from libc_pic.a objects
620 that were affected by the libc_hidden_proto declaration for __strtoul_internal. */
621 strong_alias (__strtoul_internal, __GI___strtoul_internal)
622 strong_alias (__strtoul_internal, __GI_____strtoul_internal)
624 check_no_hidden(_exit);
625 void weak_function attribute_hidden
626 _exit (int status)
628 __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
629 W_EXITCODE (status, 0), 0);
630 while (__task_terminate (__mach_task_self ()))
631 __mach_task_self_ = (__mach_task_self) ();
633 LOSE;
634 abort ();
636 /* We need this alias to satisfy references from libc_pic.a objects
637 that were affected by the libc_hidden_proto declaration for _exit. */
638 strong_alias (_exit, __GI__exit)
640 /* Try to get a machine dependent instruction which will make the
641 program crash. This is used in case everything else fails. */
642 #include <abort-instr.h>
643 #ifndef ABORT_INSTRUCTION
644 /* No such instruction is available. */
645 # define ABORT_INSTRUCTION
646 #endif
648 check_no_hidden(abort);
649 void weak_function
650 abort (void)
652 /* Try to abort using the system specific command. */
653 ABORT_INSTRUCTION;
655 /* If the abort instruction failed, exit. */
656 _exit (127);
658 /* If even this fails, make sure we never return. */
659 while (1)
660 /* Try for ever and ever. */
661 ABORT_INSTRUCTION;
664 /* We need this alias to satisfy references from libc_pic.a objects
665 that were affected by the libc_hidden_proto declaration for abort. */
666 strong_alias (abort, __GI_abort)
667 strong_alias (abort, __GI___chk_fail)
668 strong_alias (abort, __GI___fortify_fail)
669 strong_alias (abort, __GI___assert_fail)
670 strong_alias (abort, __GI___assert_perror_fail)
672 /* This function is called by interruptible RPC stubs. For initial
673 dynamic linking, just use the normal mach_msg. Since this defn is
674 weak, the real defn in libc.so will override it if we are linked into
675 the user program (-ldl). */
677 error_t weak_function
678 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
679 mach_msg_option_t option,
680 mach_msg_size_t send_size,
681 mach_msg_size_t rcv_size,
682 mach_port_t rcv_name,
683 mach_msg_timeout_t timeout,
684 mach_port_t notify)
686 return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
687 timeout, notify);
691 void
692 _dl_show_auxv (void)
694 /* There is nothing to print. Hurd has no auxiliary vector. */
698 void weak_function
699 _dl_init_first (int argc, ...)
701 /* This no-op definition only gets used if libc is not linked in. */
704 #endif /* SHARED */