Update copyright dates with scripts/update-copyrights.
[glibc.git] / sysdeps / mach / hurd / dl-sysdep.c
blob084624a7efa40c12c92809e8d49b042ca871267e
1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995-2015 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 "hurdstartup.h"
35 #include <hurd/lookup.h>
36 #include <hurd/auth.h>
37 #include <hurd/term.h>
38 #include <stdarg.h>
39 #include <ctype.h>
40 #include <sys/stat.h>
41 #include <sys/uio.h>
43 #include <entry.h>
44 #include <dl-machine.h>
45 #include <dl-procinfo.h>
47 extern void __mach_init (void);
49 extern int _dl_argc;
50 extern char **_dl_argv;
51 extern char **_environ;
53 int __libc_enable_secure = 0;
54 rtld_hidden_data_def (__libc_enable_secure)
55 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
56 of init-first. */
57 /* This variable contains the lowest stack address ever used. */
58 void *__libc_stack_end;
60 #if HP_TIMING_AVAIL
61 hp_timing_t _dl_cpuclock_offset;
62 #endif
65 struct hurd_startup_data *_dl_hurd_data;
67 /* This is used only within ld.so, via dl-minimal.c's __errno_location. */
68 #undef errno
69 int errno attribute_hidden;
71 /* Defining these variables here avoids the inclusion of hurdsig.c. */
72 unsigned long int __hurd_sigthread_stack_base;
73 unsigned long int __hurd_sigthread_stack_end;
74 unsigned long int *__hurd_sigthread_variables;
76 /* Defining these variables here avoids the inclusion of init-first.c.
77 We need to provide temporary storage for the per-thread variables
78 of the main user thread here, since it is used for storing the
79 `errno' variable. Note that this information is lost once we
80 relocate the dynamic linker. */
81 static unsigned long int threadvars[_HURD_THREADVAR_MAX];
82 unsigned long int __hurd_threadvar_stack_offset
83 = (unsigned long int) &threadvars;
84 unsigned long int __hurd_threadvar_stack_mask;
86 #define FMH defined(__i386__)
87 #if ! FMH
88 # define fmh() ((void)0)
89 # define unfmh() ((void)0)
90 #else
91 /* XXX loser kludge for vm_map kernel bug */
92 #undef ELF_MACHINE_USER_ADDRESS_MASK
93 #define ELF_MACHINE_USER_ADDRESS_MASK 0
94 static vm_address_t fmha;
95 static vm_size_t fmhs;
96 static void unfmh(void){
97 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
98 static void fmh(void) {
99 error_t err;int x;mach_port_t p;
100 vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
101 while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){
102 __mach_port_deallocate(__mach_task_self(),p);
103 if (a+fmhs>=0x80000000U){
104 max=a; break;}
105 fmha=a+=fmhs;}
106 if (err) assert(err==KERN_NO_SPACE);
107 if (!fmha)fmhs=0;else{
108 fmhs=max-fmha;
109 err = __vm_map (__mach_task_self (),
110 &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
111 VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
112 assert_perror(err);}
114 /* XXX loser kludge for vm_map kernel bug */
115 #endif
118 ElfW(Addr)
119 _dl_sysdep_start (void **start_argptr,
120 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
121 ElfW(Addr) *user_entry,
122 ElfW(auxv_t) *auxv))
124 void go (intptr_t *argdata)
126 char **p;
128 /* Cache the information in various global variables. */
129 _dl_argc = *argdata;
130 _dl_argv = 1 + (char **) argdata;
131 _environ = &_dl_argv[_dl_argc + 1];
132 for (p = _environ; *p++;); /* Skip environ pointers and terminator. */
134 if ((void *) p == _dl_argv[0])
136 static struct hurd_startup_data nodata;
137 _dl_hurd_data = &nodata;
138 nodata.user_entry = (vm_address_t) ENTRY_POINT;
140 else
141 _dl_hurd_data = (void *) p;
143 __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE;
145 if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
146 _dl_hurd_data->user_entry == 0)
147 _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
149 unfmh(); /* XXX */
151 #if 0 /* XXX make this work for real someday... */
152 if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
153 /* We were invoked as a command, not as the program interpreter.
154 The generic ld.so code supports this: it will parse the args
155 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
156 support an additional special syntax:
157 ld.so [-LIBS...] PROGRAM [ARGS...]
158 Each LIBS word consists of "FILENAME=MEMOBJ";
159 for example "-/lib/libc.so=123" says that the contents of
160 /lib/libc.so are found in a memory object whose port name
161 in our task is 123. */
162 while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
164 char *lastslash, *memobjname, *p;
165 struct link_map *l;
166 mach_port_t memobj;
167 error_t err;
169 ++_dl_skip_args;
170 --_dl_argc;
171 p = _dl_argv++[1] + 1;
173 memobjname = strchr (p, '=');
174 if (! memobjname)
175 _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
176 *memobjname++ = '\0';
177 memobj = 0;
178 while (*memobjname != '\0')
179 memobj = (memobj * 10) + (*memobjname++ - '0');
181 /* Add a user reference on the memory object port, so we will
182 still have one after _dl_map_object_from_fd calls our
183 `close'. */
184 err = __mach_port_mod_refs (__mach_task_self (), memobj,
185 MACH_PORT_RIGHT_SEND, +1);
186 assert_perror (err);
188 lastslash = strrchr (p, '/');
189 l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p,
190 memobj, strdup (p), 0);
192 /* Squirrel away the memory object port where it
193 can be retrieved by the program later. */
194 l->l_info[DT_NULL] = (void *) memobj;
196 #endif
198 /* Call elf/rtld.c's main program. It will set everything
199 up and leave us to transfer control to USER_ENTRY. */
200 (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
201 _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
202 &_dl_hurd_data->user_entry, NULL);
204 /* The call above might screw a few things up.
206 First of all, if _dl_skip_args is nonzero, we are ignoring
207 the first few arguments. However, if we have no Hurd startup
208 data, it is the magical convention that ARGV[0] == P. The
209 startup code in init-first.c will get confused if this is not
210 the case, so we must rearrange things to make it so. We'll
211 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
213 Secondly, if we need to be secure, it removes some dangerous
214 environment variables. If we have no Hurd startup date this
215 changes P (since that's the location after the terminating
216 NULL in the list of environment variables). We do the same
217 thing as in the first case but make sure we recalculate P.
218 If we do have Hurd startup data, we have to move the data
219 such that it starts just after the terminating NULL in the
220 environment list.
222 We use memmove, since the locations might overlap. */
223 if (__libc_enable_secure || _dl_skip_args)
225 char **newp;
227 for (newp = _environ; *newp++;);
229 if (_dl_argv[-_dl_skip_args] == (char *) p)
231 if ((char *) newp != _dl_argv[0])
233 assert ((char *) newp < _dl_argv[0]);
234 _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
235 strlen (_dl_argv[0]) + 1);
238 else
240 if ((void *) newp != _dl_hurd_data)
241 memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
246 extern void _dl_start_user (void);
247 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
248 to the RTLD_START code which will run the user's entry point. */
249 RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
253 /* Set up so we can do RPCs. */
254 __mach_init ();
256 /* Initialize frequently used global variable. */
257 GLRO(dl_pagesize) = __getpagesize ();
259 #if HP_TIMING_AVAIL
260 HP_TIMING_NOW (_dl_cpuclock_offset);
261 #endif
263 fmh(); /* XXX */
265 /* See hurd/hurdstartup.c; this deals with getting information
266 from the exec server and slicing up the arguments.
267 Then it will call `go', above. */
268 _hurd_startup (start_argptr, &go);
270 LOSE;
271 abort ();
274 void
275 internal_function
276 _dl_sysdep_start_cleanup (void)
278 /* Deallocate the reply port and task port rights acquired by
279 __mach_init. We are done with them now, and the user will
280 reacquire them for himself when he wants them. */
281 __mig_dealloc_reply_port (MACH_PORT_NULL);
282 __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
285 /* Minimal open/close/mmap implementation sufficient for initial loading of
286 shared libraries. These are weak definitions so that when the
287 dynamic linker re-relocates itself to be user-visible (for -ldl),
288 it will get the user's definition (i.e. usually libc's). */
290 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
291 error. If STAT is non-zero, stat the file into that stat buffer. */
292 static error_t
293 open_file (const char *file_name, int flags,
294 mach_port_t *port, struct stat64 *stat)
296 enum retry_type doretry;
297 char retryname[1024]; /* XXX string_t LOSES! */
298 file_t startdir;
299 error_t err;
301 error_t use_init_port (int which, error_t (*operate) (file_t))
303 return (which < _dl_hurd_data->portarraysize
304 ? ((*operate) (_dl_hurd_data->portarray[which]))
305 : EGRATUITOUS);
307 file_t get_dtable_port (int fd)
309 if ((unsigned int) fd < _dl_hurd_data->dtablesize
310 && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
312 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
313 MACH_PORT_RIGHT_SEND, +1);
314 return _dl_hurd_data->dtable[fd];
316 errno = EBADF;
317 return MACH_PORT_NULL;
320 assert (!(flags & ~(O_READ | O_CLOEXEC)));
322 startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
323 INIT_PORT_CRDIR : INIT_PORT_CWDIR];
325 while (file_name[0] == '/')
326 file_name++;
328 err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
329 &doretry, retryname, port);
331 if (!err)
332 err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
333 __dir_lookup, doretry, retryname,
334 O_RDONLY, 0, port);
335 if (!err && stat)
337 err = __io_stat (*port, stat);
338 if (err)
339 __mach_port_deallocate (__mach_task_self (), *port);
342 return err;
345 int weak_function
346 __open (const char *file_name, int mode, ...)
348 mach_port_t port;
349 error_t err = open_file (file_name, mode, &port, 0);
350 if (err)
351 return __hurd_fail (err);
352 else
353 return (int)port;
356 int weak_function
357 __close (int fd)
359 if (fd != (int) MACH_PORT_NULL)
360 __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
361 return 0;
364 __ssize_t weak_function
365 __libc_read (int fd, void *buf, size_t nbytes)
367 error_t err;
368 char *data;
369 mach_msg_type_number_t nread;
371 data = buf;
372 nread = nbytes;
373 err = __io_read ((mach_port_t) fd, &data, &nread, -1, nbytes);
374 if (err)
375 return __hurd_fail (err);
377 if (data != buf)
379 memcpy (buf, data, nread);
380 __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
383 return nread;
385 libc_hidden_weak (__libc_read)
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 __ssize_t weak_function
405 __writev (int fd, const struct iovec *iov, int niov)
407 if (fd >= _hurd_init_dtablesize)
409 errno = EBADF;
410 return -1;
413 int i;
414 size_t total = 0;
415 for (i = 0; i < niov; ++i)
416 total += iov[i].iov_len;
418 if (total != 0)
420 char buf[total], *bufp = buf;
421 error_t err;
422 mach_msg_type_number_t nwrote;
424 for (i = 0; i < niov; ++i)
425 bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
426 + iov[i].iov_len);
428 err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
429 if (err)
430 return __hurd_fail (err);
432 return nwrote;
434 return 0;
438 off64_t weak_function
439 __libc_lseek64 (int fd, off64_t offset, int whence)
441 error_t err;
443 err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
444 if (err)
445 return __hurd_fail (err);
447 return offset;
450 __ptr_t weak_function
451 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
453 error_t err;
454 vm_prot_t vmprot;
455 vm_address_t mapaddr;
456 mach_port_t memobj_rd, memobj_wr;
458 vmprot = VM_PROT_NONE;
459 if (prot & PROT_READ)
460 vmprot |= VM_PROT_READ;
461 if (prot & PROT_WRITE)
462 vmprot |= VM_PROT_WRITE;
463 if (prot & PROT_EXEC)
464 vmprot |= VM_PROT_EXECUTE;
466 if (flags & MAP_ANON)
467 memobj_rd = MACH_PORT_NULL;
468 else
470 assert (!(flags & MAP_SHARED));
471 err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
472 if (err)
473 return __hurd_fail (err), MAP_FAILED;
474 __mach_port_deallocate (__mach_task_self (), memobj_wr);
477 mapaddr = (vm_address_t) addr;
478 err = __vm_map (__mach_task_self (),
479 &mapaddr, (vm_size_t) len, ELF_MACHINE_USER_ADDRESS_MASK,
480 !(flags & MAP_FIXED),
481 memobj_rd,
482 (vm_offset_t) offset,
483 flags & (MAP_COPY|MAP_PRIVATE),
484 vmprot, VM_PROT_ALL,
485 (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
486 if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
488 /* XXX this is not atomic as it is in unix! */
489 /* The region is already allocated; deallocate it first. */
490 err = __vm_deallocate (__mach_task_self (), mapaddr, len);
491 if (! err)
492 err = __vm_map (__mach_task_self (),
493 &mapaddr, (vm_size_t) len,
494 ELF_MACHINE_USER_ADDRESS_MASK,
495 !(flags & MAP_FIXED),
496 memobj_rd, (vm_offset_t) offset,
497 flags & (MAP_COPY|MAP_PRIVATE),
498 vmprot, VM_PROT_ALL,
499 (flags & MAP_SHARED)
500 ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
503 if ((flags & MAP_ANON) == 0)
504 __mach_port_deallocate (__mach_task_self (), memobj_rd);
506 if (err)
507 return __hurd_fail (err), MAP_FAILED;
508 return (__ptr_t) mapaddr;
511 int weak_function
512 __fxstat64 (int vers, int fd, struct stat64 *buf)
514 error_t err;
516 assert (vers == _STAT_VER);
518 err = __io_stat ((mach_port_t) fd, buf);
519 if (err)
520 return __hurd_fail (err);
522 return 0;
524 libc_hidden_def (__fxstat64)
526 int weak_function
527 __xstat64 (int vers, const char *file, struct stat64 *buf)
529 error_t err;
530 mach_port_t port;
532 assert (vers == _STAT_VER);
534 err = open_file (file, 0, &port, buf);
535 if (err)
536 return __hurd_fail (err);
538 __mach_port_deallocate (__mach_task_self (), port);
540 return 0;
542 libc_hidden_def (__xstat64)
544 /* This function is called by the dynamic linker (rtld.c) to check
545 whether debugging malloc is allowed even for SUID binaries. This
546 stub will always fail, which means that malloc-debugging is always
547 disabled for SUID binaries. */
548 int weak_function
549 __access (const char *file, int type)
551 errno = ENOSYS;
552 return -1;
555 pid_t weak_function
556 __getpid (void)
558 pid_t pid, ppid;
559 int orphaned;
561 if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
562 &pid, &ppid, &orphaned))
563 return -1;
565 return pid;
568 /* This is called only in some strange cases trying to guess a value
569 for $ORIGIN for the executable. The dynamic linker copes with
570 getcwd failing (dl-object.c), and it's too much hassle to include
571 the functionality here. (We could, it just requires duplicating or
572 reusing getcwd.c's code but using our special lookup function as in
573 `open', above.) */
574 char *
575 weak_function
576 __getcwd (char *buf, size_t size)
578 errno = ENOSYS;
579 return NULL;
582 void weak_function attribute_hidden
583 _exit (int status)
585 __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
586 W_EXITCODE (status, 0), 0);
587 while (__task_terminate (__mach_task_self ()))
588 __mach_task_self_ = (__mach_task_self) ();
590 /* We need this alias to satisfy references from libc_pic.a objects
591 that were affected by the libc_hidden_proto declaration for _exit. */
592 strong_alias (_exit, __GI__exit)
594 /* Try to get a machine dependent instruction which will make the
595 program crash. This is used in case everything else fails. */
596 #include <abort-instr.h>
597 #ifndef ABORT_INSTRUCTION
598 /* No such instruction is available. */
599 # define ABORT_INSTRUCTION
600 #endif
602 void weak_function
603 abort (void)
605 /* Try to abort using the system specific command. */
606 ABORT_INSTRUCTION;
608 /* If the abort instruction failed, exit. */
609 _exit (127);
611 /* If even this fails, make sure we never return. */
612 while (1)
613 /* Try for ever and ever. */
614 ABORT_INSTRUCTION;
617 /* We need this alias to satisfy references from libc_pic.a objects
618 that were affected by the libc_hidden_proto declaration for abort. */
619 strong_alias (abort, __GI_abort)
621 /* This function is called by interruptible RPC stubs. For initial
622 dynamic linking, just use the normal mach_msg. Since this defn is
623 weak, the real defn in libc.so will override it if we are linked into
624 the user program (-ldl). */
626 error_t weak_function
627 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
628 mach_msg_option_t option,
629 mach_msg_size_t send_size,
630 mach_msg_size_t rcv_size,
631 mach_port_t rcv_name,
632 mach_msg_timeout_t timeout,
633 mach_port_t notify)
635 return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
636 timeout, notify);
640 void
641 internal_function
642 _dl_show_auxv (void)
644 /* There is nothing to print. Hurd has no auxiliary vector. */
648 void weak_function
649 _dl_init_first (int argc, ...)
651 /* This no-op definition only gets used if libc is not linked in. */
654 #endif /* SHARED */