Handle platforms without aux vector
[glibc.git] / sysdeps / mach / hurd / dl-sysdep.c
blobf87b6e07dc5cd11b8074aef059fb8e3607524204
1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2010
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <hurd.h>
22 #include <link.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <sys/mman.h>
27 #include <ldsodefs.h>
28 #include <sys/wait.h>
29 #include <assert.h>
30 #include <sysdep.h>
31 #include <mach/mig_support.h>
32 #include "hurdstartup.h"
33 #include <hurd/lookup.h>
34 #include <hurd/auth.h>
35 #include <hurd/term.h>
36 #include <stdarg.h>
37 #include <ctype.h>
38 #include <sys/stat.h>
39 #include <sys/uio.h>
41 #include <entry.h>
42 #include <dl-machine.h>
43 #include <dl-procinfo.h>
45 extern void __mach_init (void);
47 extern int _dl_argc;
48 extern char **_dl_argv;
49 extern char **_environ;
51 int __libc_enable_secure = 0;
52 INTVARDEF(__libc_enable_secure)
53 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
54 of init-first. */
55 /* This variable containts the lowest stack address ever used. */
56 void *__libc_stack_end;
58 #if HP_TIMING_AVAIL
59 hp_timing_t _dl_cpuclock_offset;
60 #endif
63 struct hurd_startup_data *_dl_hurd_data;
65 /* This is used only within ld.so, via dl-minimal.c's __errno_location. */
66 #undef errno
67 int errno attribute_hidden;
69 /* Defining these variables here avoids the inclusion of hurdsig.c. */
70 unsigned long int __hurd_sigthread_stack_base;
71 unsigned long int __hurd_sigthread_stack_end;
72 unsigned long int *__hurd_sigthread_variables;
74 /* Defining these variables here avoids the inclusion of init-first.c.
75 We need to provide temporary storage for the per-thread variables
76 of the main user thread here, since it is used for storing the
77 `errno' variable. Note that this information is lost once we
78 relocate the dynamic linker. */
79 static unsigned long int threadvars[_HURD_THREADVAR_MAX];
80 unsigned long int __hurd_threadvar_stack_offset
81 = (unsigned long int) &threadvars;
82 unsigned long int __hurd_threadvar_stack_mask;
84 #define FMH defined(__i386__)
85 #if ! FMH
86 # define fmh() ((void)0)
87 # define unfmh() ((void)0)
88 #else
89 /* XXX loser kludge for vm_map kernel bug */
90 #undef ELF_MACHINE_USER_ADDRESS_MASK
91 #define ELF_MACHINE_USER_ADDRESS_MASK 0
92 static vm_address_t fmha;
93 static vm_size_t fmhs;
94 static void unfmh(void){
95 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
96 static void fmh(void) {
97 error_t err;int x;mach_port_t p;
98 vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
99 while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){
100 __mach_port_deallocate(__mach_task_self(),p);
101 if (a+fmhs>=0x80000000U){
102 max=a; break;}
103 fmha=a+=fmhs;}
104 if (err) assert(err==KERN_NO_SPACE);
105 if (!fmha)fmhs=0;else{
106 fmhs=max-fmha;
107 err = __vm_map (__mach_task_self (),
108 &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
109 VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
110 assert_perror(err);}
112 /* XXX loser kludge for vm_map kernel bug */
113 #endif
116 ElfW(Addr)
117 _dl_sysdep_start (void **start_argptr,
118 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
119 ElfW(Addr) *user_entry,
120 ElfW(auxv_t) *auxv)))
122 void go (intptr_t *argdata)
124 extern unsigned int _dl_skip_args; /* rtld.c */
125 char **p;
127 /* Cache the information in various global variables. */
128 _dl_argc = *argdata;
129 _dl_argv = 1 + (char **) argdata;
130 _environ = &_dl_argv[_dl_argc + 1];
131 for (p = _environ; *p++;); /* Skip environ pointers and terminator. */
133 if ((void *) p == _dl_argv[0])
135 static struct hurd_startup_data nodata;
136 _dl_hurd_data = &nodata;
137 nodata.user_entry = (vm_address_t) ENTRY_POINT;
139 else
140 _dl_hurd_data = (void *) p;
142 INTUSE(__libc_enable_secure) = _dl_hurd_data->flags & EXEC_SECURE;
144 if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
145 _dl_hurd_data->user_entry == 0)
146 _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
148 unfmh(); /* XXX */
150 #if 0 /* XXX make this work for real someday... */
151 if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
152 /* We were invoked as a command, not as the program interpreter.
153 The generic ld.so code supports this: it will parse the args
154 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
155 support an additional special syntax:
156 ld.so [-LIBS...] PROGRAM [ARGS...]
157 Each LIBS word consists of "FILENAME=MEMOBJ";
158 for example "-/lib/libc.so=123" says that the contents of
159 /lib/libc.so are found in a memory object whose port name
160 in our task is 123. */
161 while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
163 char *lastslash, *memobjname, *p;
164 struct link_map *l;
165 mach_port_t memobj;
166 error_t err;
168 ++_dl_skip_args;
169 --_dl_argc;
170 p = _dl_argv++[1] + 1;
172 memobjname = strchr (p, '=');
173 if (! memobjname)
174 _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
175 *memobjname++ = '\0';
176 memobj = 0;
177 while (*memobjname != '\0')
178 memobj = (memobj * 10) + (*memobjname++ - '0');
180 /* Add a user reference on the memory object port, so we will
181 still have one after _dl_map_object_from_fd calls our
182 `close'. */
183 err = __mach_port_mod_refs (__mach_task_self (), memobj,
184 MACH_PORT_RIGHT_SEND, +1);
185 assert_perror (err);
187 lastslash = strrchr (p, '/');
188 l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p,
189 memobj, strdup (p), 0);
191 /* Squirrel away the memory object port where it
192 can be retrieved by the program later. */
193 l->l_info[DT_NULL] = (void *) memobj;
195 #endif
197 /* Call elf/rtld.c's main program. It will set everything
198 up and leave us to transfer control to USER_ENTRY. */
199 (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
200 _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
201 &_dl_hurd_data->user_entry, NULLy);
203 /* The call above might screw a few things up.
205 First of all, if _dl_skip_args is nonzero, we are ignoring
206 the first few arguments. However, if we have no Hurd startup
207 data, it is the magical convention that ARGV[0] == P. The
208 startup code in init-first.c will get confused if this is not
209 the case, so we must rearrange things to make it so. We'll
210 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
212 Secondly, if we need to be secure, it removes some dangerous
213 environment variables. If we have no Hurd startup date this
214 changes P (since that's the location after the terminating
215 NULL in the list of environment variables). We do the same
216 thing as in the first case but make sure we recalculate P.
217 If we do have Hurd startup data, we have to move the data
218 such that it starts just after the terminating NULL in the
219 environment list.
221 We use memmove, since the locations might overlap. */
222 if (INTUSE(__libc_enable_secure) || _dl_skip_args)
224 char **newp;
226 for (newp = _environ; *newp++;);
228 if (_dl_argv[-_dl_skip_args] == (char *) p)
230 if ((char *) newp != _dl_argv[0])
232 assert ((char *) newp < _dl_argv[0]);
233 _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
234 strlen (_dl_argv[0]) + 1);
237 else
239 if ((void *) newp != _dl_hurd_data)
240 memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
245 extern void _dl_start_user (void);
246 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
247 to the RTLD_START code which will run the user's entry point. */
248 RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
252 /* Set up so we can do RPCs. */
253 __mach_init ();
255 /* Initialize frequently used global variable. */
256 GLRO(dl_pagesize) = __getpagesize ();
258 #if HP_TIMING_AVAIL
259 HP_TIMING_NOW (_dl_cpuclock_offset);
260 #endif
262 fmh(); /* XXX */
264 /* See hurd/hurdstartup.c; this deals with getting information
265 from the exec server and slicing up the arguments.
266 Then it will call `go', above. */
267 _hurd_startup (start_argptr, &go);
269 LOSE;
270 abort ();
273 void
274 internal_function
275 _dl_sysdep_start_cleanup (void)
277 /* Deallocate the reply port and task port rights acquired by
278 __mach_init. We are done with them now, and the user will
279 reacquire them for himself when he wants them. */
280 __mig_dealloc_reply_port (MACH_PORT_NULL);
281 __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
284 /* Minimal open/close/mmap implementation sufficient for initial loading of
285 shared libraries. These are weak definitions so that when the
286 dynamic linker re-relocates itself to be user-visible (for -ldl),
287 it will get the user's definition (i.e. usually libc's). */
289 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
290 error. If STAT is non-zero, stat the file into that stat buffer. */
291 static error_t
292 open_file (const char *file_name, int flags,
293 mach_port_t *port, struct stat64 *stat)
295 enum retry_type doretry;
296 char retryname[1024]; /* XXX string_t LOSES! */
297 file_t startdir;
298 error_t err;
300 error_t use_init_port (int which, error_t (*operate) (file_t))
302 return (which < _dl_hurd_data->portarraysize
303 ? ((*operate) (_dl_hurd_data->portarray[which]))
304 : EGRATUITOUS);
306 file_t get_dtable_port (int fd)
308 if ((unsigned int) fd < _dl_hurd_data->dtablesize
309 && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
311 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
312 MACH_PORT_RIGHT_SEND, +1);
313 return _dl_hurd_data->dtable[fd];
315 errno = EBADF;
316 return MACH_PORT_NULL;
319 assert (!(flags & ~O_READ));
321 startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
322 INIT_PORT_CRDIR : INIT_PORT_CWDIR];
324 while (file_name[0] == '/')
325 file_name++;
327 err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
328 &doretry, retryname, port);
330 if (!err)
331 err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
332 __dir_lookup, doretry, retryname,
333 O_RDONLY, 0, port);
334 if (!err && stat)
336 err = __io_stat (*port, stat);
337 if (err)
338 __mach_port_deallocate (__mach_task_self (), *port);
341 return err;
344 int weak_function
345 __open (const char *file_name, int mode, ...)
347 mach_port_t port;
348 error_t err = open_file (file_name, mode, &port, 0);
349 if (err)
350 return __hurd_fail (err);
351 else
352 return (int)port;
355 int weak_function
356 __close (int fd)
358 if (fd != (int) MACH_PORT_NULL)
359 __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
360 return 0;
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 __ssize_t weak_function
387 __libc_write (int fd, const void *buf, size_t nbytes)
389 error_t err;
390 mach_msg_type_number_t nwrote;
392 assert (fd < _hurd_init_dtablesize);
394 err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
395 if (err)
396 return __hurd_fail (err);
398 return nwrote;
400 libc_hidden_weak (__libc_write)
402 /* This is only used for printing messages (see dl-misc.c). */
403 __ssize_t weak_function
404 __writev (int fd, const struct iovec *iov, int niov)
406 if (fd >= _hurd_init_dtablesize)
408 errno = EBADF;
409 return -1;
412 int i;
413 size_t total = 0;
414 for (i = 0; i < niov; ++i)
415 total += iov[i].iov_len;
417 if (total != 0)
419 char buf[total], *bufp = buf;
420 error_t err;
421 mach_msg_type_number_t nwrote;
423 for (i = 0; i < niov; ++i)
424 bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
425 + iov[i].iov_len);
427 err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
428 if (err)
429 return __hurd_fail (err);
431 return nwrote;
433 return 0;
437 off64_t weak_function
438 __libc_lseek64 (int fd, off64_t offset, int whence)
440 error_t err;
442 err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
443 if (err)
444 return __hurd_fail (err);
446 return offset;
449 __ptr_t weak_function
450 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
452 error_t err;
453 vm_prot_t vmprot;
454 vm_address_t mapaddr;
455 mach_port_t memobj_rd, memobj_wr;
457 vmprot = VM_PROT_NONE;
458 if (prot & PROT_READ)
459 vmprot |= VM_PROT_READ;
460 if (prot & PROT_WRITE)
461 vmprot |= VM_PROT_WRITE;
462 if (prot & PROT_EXEC)
463 vmprot |= VM_PROT_EXECUTE;
465 if (flags & MAP_ANON)
466 memobj_rd = MACH_PORT_NULL;
467 else
469 assert (!(flags & MAP_SHARED));
470 err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
471 if (err)
472 return __hurd_fail (err), MAP_FAILED;
473 __mach_port_deallocate (__mach_task_self (), memobj_wr);
476 mapaddr = (vm_address_t) addr;
477 err = __vm_map (__mach_task_self (),
478 &mapaddr, (vm_size_t) len, ELF_MACHINE_USER_ADDRESS_MASK,
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))
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 ELF_MACHINE_USER_ADDRESS_MASK,
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);
502 if ((flags & MAP_ANON) == 0)
503 __mach_port_deallocate (__mach_task_self (), memobj_rd);
505 if (err)
506 return __hurd_fail (err), MAP_FAILED;
507 return (__ptr_t) mapaddr;
510 int weak_function
511 __fxstat64 (int vers, int fd, struct stat64 *buf)
513 error_t err;
515 assert (vers == _STAT_VER);
517 err = __io_stat ((mach_port_t) fd, buf);
518 if (err)
519 return __hurd_fail (err);
521 return 0;
523 libc_hidden_def (__fxstat64)
525 int weak_function
526 __xstat64 (int vers, const char *file, struct stat64 *buf)
528 error_t err;
529 mach_port_t port;
531 assert (vers == _STAT_VER);
533 err = open_file (file, 0, &port, buf);
534 if (err)
535 return __hurd_fail (err);
537 __mach_port_deallocate (__mach_task_self (), port);
539 return 0;
541 libc_hidden_def (__xstat64)
543 /* This function is called by the dynamic linker (rtld.c) to check
544 whether debugging malloc is allowed even for SUID binaries. This
545 stub will always fail, which means that malloc-debugging is always
546 disabled for SUID binaries. */
547 int weak_function
548 __access (const char *file, int type)
550 errno = ENOSYS;
551 return -1;
554 pid_t weak_function
555 __getpid ()
557 pid_t pid, ppid;
558 int orphaned;
560 if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
561 &pid, &ppid, &orphaned))
562 return -1;
564 return pid;
567 /* This is called only in some strange cases trying to guess a value
568 for $ORIGIN for the executable. The dynamic linker copes with
569 getcwd failing (dl-object.c), and it's too much hassle to include
570 the functionality here. (We could, it just requires duplicating or
571 reusing getcwd.c's code but using our special lookup function as in
572 `open', above.) */
573 char *
574 weak_function
575 __getcwd (char *buf, size_t size)
577 errno = ENOSYS;
578 return NULL;
581 void weak_function attribute_hidden
582 _exit (int status)
584 __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
585 W_EXITCODE (status, 0), 0);
586 while (__task_terminate (__mach_task_self ()))
587 __mach_task_self_ = (__mach_task_self) ();
589 /* We need this alias to satisfy references from libc_pic.a objects
590 that were affected by the libc_hidden_proto declaration for _exit. */
591 strong_alias (_exit, __GI__exit)
593 /* Try to get a machine dependent instruction which will make the
594 program crash. This is used in case everything else fails. */
595 #include <abort-instr.h>
596 #ifndef ABORT_INSTRUCTION
597 /* No such instruction is available. */
598 # define ABORT_INSTRUCTION
599 #endif
601 void weak_function
602 abort (void)
604 /* Try to abort using the system specific command. */
605 ABORT_INSTRUCTION;
607 /* If the abort instruction failed, exit. */
608 _exit (127);
610 /* If even this fails, make sure we never return. */
611 while (1)
612 /* Try for ever and ever. */
613 ABORT_INSTRUCTION;
616 /* We need this alias to satisfy references from libc_pic.a objects
617 that were affected by the libc_hidden_proto declaration for abort. */
618 strong_alias (abort, __GI_abort)
620 /* This function is called by interruptible RPC stubs. For initial
621 dynamic linking, just use the normal mach_msg. Since this defn is
622 weak, the real defn in libc.so will override it if we are linked into
623 the user program (-ldl). */
625 error_t weak_function
626 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
627 mach_msg_option_t option,
628 mach_msg_size_t send_size,
629 mach_msg_size_t rcv_size,
630 mach_port_t rcv_name,
631 mach_msg_timeout_t timeout,
632 mach_port_t notify)
634 return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
635 timeout, notify);
639 void
640 internal_function
641 _dl_show_auxv (void)
643 /* There is nothing to print. Hurd has no auxiliary vector. */
647 /* Return an array of useful/necessary hardware capability names. */
648 const struct r_strlenpair *
649 internal_function
650 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
651 size_t *max_capstrlen)
653 struct r_strlenpair *result;
655 /* Return an empty array. Hurd has no hardware capabilities. */
656 result = (struct r_strlenpair *) malloc (sizeof (*result));
657 if (result == NULL)
658 _dl_signal_error (ENOMEM, NULL, NULL, "cannot create capability list");
660 result[0].str = (char *) result; /* Does not really matter. */
661 result[0].len = 0;
663 *sz = 1;
664 return result;
667 void weak_function
668 _dl_init_first (int argc, ...)
670 /* This no-op definition only gets used if libc is not linked in. */