1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995,96,97,98,99,2000,2001,2002 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30 #include <mach/mig_support.h>
31 #include "hurdstartup.h"
32 #include <hurd/lookup.h>
33 #include <hurd/auth.h>
34 #include <hurd/term.h>
41 #include <dl-machine.h>
42 #include <dl-procinfo.h>
44 extern void __mach_init (void);
47 extern char **_dl_argv;
48 extern char **_environ;
50 int __libc_enable_secure = 0;
51 INTVARDEF(__libc_enable_secure)
52 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
54 /* This variable containts the lowest stack address ever used. */
55 void *__libc_stack_end;
58 struct hurd_startup_data *_dl_hurd_data;
60 /* This is used only within ld.so, via dl-minimal.c's __errno_location. */
62 int errno attribute_hidden;
64 /* Defining these variables here avoids the inclusion of hurdsig.c. */
65 unsigned long int __hurd_sigthread_stack_base;
66 unsigned long int __hurd_sigthread_stack_end;
67 unsigned long int *__hurd_sigthread_variables;
69 /* Defining these variables here avoids the inclusion of init-first.c.
70 We need to provide temporary storage for the per-thread variables
71 of the main user thread here, since it is used for storing the
72 `errno' variable. Note that this information is lost once we
73 relocate the dynamic linker. */
74 static unsigned long int threadvars[_HURD_THREADVAR_MAX];
75 unsigned long int __hurd_threadvar_stack_offset
76 = (unsigned long int) &threadvars;
77 unsigned long int __hurd_threadvar_stack_mask;
79 #define FMH defined(__i386__)
81 # define fmh() ((void)0)
82 # define unfmh() ((void)0)
84 /* XXX loser kludge for vm_map kernel bug */
85 #undef ELF_MACHINE_USER_ADDRESS_MASK
86 #define ELF_MACHINE_USER_ADDRESS_MASK 0
87 static vm_address_t fmha;
88 static vm_size_t fmhs;
89 static void unfmh(void){
90 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
91 static void fmh(void) {
92 error_t err;int x;mach_port_t p;
93 vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
94 while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){
95 __mach_port_deallocate(__mach_task_self(),p);
96 if (a+fmhs>=0x80000000U){
99 if (err) assert(err==KERN_NO_SPACE);
100 if (!fmha)fmhs=0;else{
102 err = __vm_map (__mach_task_self (),
103 &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
104 VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
107 /* XXX loser kludge for vm_map kernel bug */
112 _dl_sysdep_start (void **start_argptr,
113 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
114 ElfW(Addr) *user_entry))
116 void go (int *argdata)
118 extern unsigned int _dl_skip_args; /* rtld.c */
121 /* Cache the information in various global variables. */
123 _dl_argv = 1 + (char **) argdata;
124 _environ = &_dl_argv[_dl_argc + 1];
125 for (p = _environ; *p++;); /* Skip environ pointers and terminator. */
127 if ((void *) p == _dl_argv[0])
129 static struct hurd_startup_data nodata;
130 _dl_hurd_data = &nodata;
131 nodata.user_entry = (vm_address_t) ENTRY_POINT;
134 _dl_hurd_data = (void *) p;
136 INTUSE(__libc_enable_secure) = _dl_hurd_data->flags & EXEC_SECURE;
138 if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
139 _dl_hurd_data->user_entry == 0)
140 _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
144 #if 0 /* XXX make this work for real someday... */
145 if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
146 /* We were invoked as a command, not as the program interpreter.
147 The generic ld.so code supports this: it will parse the args
148 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
149 support an additional special syntax:
150 ld.so [-LIBS...] PROGRAM [ARGS...]
151 Each LIBS word consists of "FILENAME=MEMOBJ";
152 for example "-/lib/libc.so=123" says that the contents of
153 /lib/libc.so are found in a memory object whose port name
154 in our task is 123. */
155 while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
157 char *lastslash, *memobjname, *p;
164 p = _dl_argv++[1] + 1;
166 memobjname = strchr (p, '=');
168 _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
169 *memobjname++ = '\0';
171 while (*memobjname != '\0')
172 memobj = (memobj * 10) + (*memobjname++ - '0');
174 /* Add a user reference on the memory object port, so we will
175 still have one after _dl_map_object_from_fd calls our
177 err = __mach_port_mod_refs (__mach_task_self (), memobj,
178 MACH_PORT_RIGHT_SEND, +1);
181 lastslash = strrchr (p, '/');
182 l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p,
183 memobj, strdup (p), 0);
185 /* Squirrel away the memory object port where it
186 can be retrieved by the program later. */
187 l->l_info[DT_NULL] = (void *) memobj;
191 /* Call elf/rtld.c's main program. It will set everything
192 up and leave us to transfer control to USER_ENTRY. */
193 (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
194 _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
195 &_dl_hurd_data->user_entry);
197 /* The call above might screw a few things up.
199 First of all, if _dl_skip_args is nonzero, we are ignoring
200 the first few arguments. However, if we have no Hurd startup
201 data, it is the magical convention that ARGV[0] == P. The
202 startup code in init-first.c will get confused if this is not
203 the case, so we must rearrange things to make it so. We'll
204 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
206 Secondly, if we need to be secure, it removes some dangerous
207 environment variables. If we have no Hurd startup date this
208 changes P (since that's the location after the terminating
209 NULL in the list of environment variables). We do the same
210 thing as in the first case but make sure we recalculate P.
211 If we do have Hurd startup data, we have to move the data
212 such that it starts just after the terminating NULL in the
215 We use memmove, since the locations might overlap. */
216 if (INTUSE(__libc_enable_secure) || _dl_skip_args)
220 for (newp = _environ; *newp++;);
222 if (_dl_argv[-_dl_skip_args] == (char *) p)
224 if ((char *) newp != _dl_argv[0])
226 assert ((char *) newp < _dl_argv[0]);
227 _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
228 strlen (_dl_argv[0]) + 1);
233 if ((void *) newp != _dl_hurd_data)
234 memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
239 extern void _dl_start_user (void);
240 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
241 to the RTLD_START code which will run the user's entry point. */
242 RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
246 /* Set up so we can do RPCs. */
249 /* Initialize frequently used global variable. */
250 GL(dl_pagesize) = __getpagesize ();
254 /* See hurd/hurdstartup.c; this deals with getting information
255 from the exec server and slicing up the arguments.
256 Then it will call `go', above. */
257 _hurd_startup (start_argptr, &go);
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_task_self_);
274 /* Minimal open/close/mmap implementation sufficient for initial loading of
275 shared libraries. These are weak definitions so that when the
276 dynamic linker re-relocates itself to be user-visible (for -ldl),
277 it will get the user's definition (i.e. usually libc's). */
279 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
280 error. If STAT is non-zero, stat the file into that stat buffer. */
282 open_file (const char *file_name, int flags,
283 mach_port_t *port, struct stat *stat)
285 enum retry_type doretry;
286 char retryname[1024]; /* XXX string_t LOSES! */
290 error_t use_init_port (int which, error_t (*operate) (file_t))
292 return (which < _dl_hurd_data->portarraysize
293 ? ((*operate) (_dl_hurd_data->portarray[which]))
296 file_t get_dtable_port (int fd)
298 if ((unsigned int) fd < _dl_hurd_data->dtablesize
299 && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
301 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
302 MACH_PORT_RIGHT_SEND, +1);
303 return _dl_hurd_data->dtable[fd];
306 return MACH_PORT_NULL;
309 assert (!(flags & ~O_READ));
311 startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
312 INIT_PORT_CRDIR : INIT_PORT_CWDIR];
314 while (file_name[0] == '/')
317 err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
318 &doretry, retryname, port);
321 err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
322 __dir_lookup, doretry, retryname,
326 err = __io_stat (*port, stat);
328 __mach_port_deallocate (__mach_task_self (), *port);
335 __open (const char *file_name, int mode, ...)
338 error_t err = open_file (file_name, mode, &port, 0);
340 return __hurd_fail (err);
348 if (fd != (int) MACH_PORT_NULL)
349 __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
353 __ssize_t weak_function
354 __libc_read (int fd, void *buf, size_t nbytes)
358 mach_msg_type_number_t nread;
361 err = __io_read ((mach_port_t) fd, &data, &nread, -1, nbytes);
363 return __hurd_fail (err);
367 memcpy (buf, data, nread);
368 __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
374 __ssize_t weak_function
375 __libc_write (int fd, const void *buf, size_t nbytes)
378 mach_msg_type_number_t nwrote;
380 assert (fd < _hurd_init_dtablesize);
382 err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
384 return __hurd_fail (err);
389 /* This is only used for printing messages (see dl-misc.c). */
390 __ssize_t weak_function
391 __writev (int fd, const struct iovec *iov, int niov)
395 for (i = 0; i < niov; ++i)
396 total += iov[i].iov_len;
398 assert (fd < _hurd_init_dtablesize);
402 char buf[total], *bufp = buf;
404 mach_msg_type_number_t nwrote;
406 for (i = 0; i < niov; ++i)
407 bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
410 err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
412 return __hurd_fail (err);
421 __lseek (int fd, off_t offset, int whence)
425 err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
427 return __hurd_fail (err);
432 __ptr_t weak_function
433 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
437 vm_address_t mapaddr;
438 mach_port_t memobj_rd, memobj_wr;
440 vmprot = VM_PROT_NONE;
441 if (prot & PROT_READ)
442 vmprot |= VM_PROT_READ;
443 if (prot & PROT_WRITE)
444 vmprot |= VM_PROT_WRITE;
445 if (prot & PROT_EXEC)
446 vmprot |= VM_PROT_EXECUTE;
448 if (flags & MAP_ANON)
449 memobj_rd = MACH_PORT_NULL;
452 assert (!(flags & MAP_SHARED));
453 err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
455 return __hurd_fail (err), MAP_FAILED;
456 __mach_port_deallocate (__mach_task_self (), memobj_wr);
459 mapaddr = (vm_address_t) addr;
460 err = __vm_map (__mach_task_self (),
461 &mapaddr, (vm_size_t) len, ELF_MACHINE_USER_ADDRESS_MASK,
462 !(flags & MAP_FIXED),
464 (vm_offset_t) offset,
465 flags & (MAP_COPY|MAP_PRIVATE),
467 (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
468 if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
470 /* XXX this is not atomic as it is in unix! */
471 /* The region is already allocated; deallocate it first. */
472 err = __vm_deallocate (__mach_task_self (), mapaddr, len);
474 err = __vm_map (__mach_task_self (),
475 &mapaddr, (vm_size_t) len,
476 ELF_MACHINE_USER_ADDRESS_MASK,
477 !(flags & MAP_FIXED),
478 memobj_rd, (vm_offset_t) offset,
479 flags & (MAP_COPY|MAP_PRIVATE),
482 ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
485 if ((flags & MAP_ANON) == 0)
486 __mach_port_deallocate (__mach_task_self (), memobj_rd);
489 return __hurd_fail (err), MAP_FAILED;
490 return (__ptr_t) mapaddr;
494 __fxstat (int vers, int fd, struct stat *buf)
498 assert (vers == _STAT_VER);
500 err = __io_stat ((mach_port_t) fd, buf);
502 return __hurd_fail (err);
508 __xstat (int vers, const char *file, struct stat *buf)
513 assert (vers == _STAT_VER);
515 err = open_file (file, 0, &port, buf);
517 return __hurd_fail (err);
519 __mach_port_deallocate (__mach_task_self (), port);
524 /* This function is called by the dynamic linker (rtld.c) to check
525 whether debugging malloc is allowed even for SUID binaries. This
526 stub will always fail, which means that malloc-debugging is always
527 disabled for SUID binaries. */
529 __access (const char *file, int type)
541 if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
542 &pid, &ppid, &orphaned))
548 /* This is called only in some strange cases trying to guess a value
549 for $ORIGIN for the executable. The dynamic linker copes with
550 getcwd failing (dl-object.c), and it's too much hassle to include
551 the functionality here. (We could, it just requires duplicating or
552 reusing getcwd.c's code but using our special lookup function as in
556 __getcwd (char *buf, size_t size)
565 __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
566 W_EXITCODE (status, 0), 0);
567 while (__task_terminate (__mach_task_self ()))
568 __mach_task_self_ = (__mach_task_self) ();
571 /* Try to get a machine dependent instruction which will make the
572 program crash. This is used in case everything else fails. */
573 #include <abort-instr.h>
574 #ifndef ABORT_INSTRUCTION
575 /* No such instruction is available. */
576 # define ABORT_INSTRUCTION
582 /* Try to abort using the system specific command. */
585 /* If the abort instruction failed, exit. */
588 /* If even this fails, make sure we never return. */
590 /* Try for ever and ever. */
594 /* This function is called by interruptible RPC stubs. For initial
595 dynamic linking, just use the normal mach_msg. Since this defn is
596 weak, the real defn in libc.so will override it if we are linked into
597 the user program (-ldl). */
599 error_t weak_function
600 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
601 mach_msg_option_t option,
602 mach_msg_size_t send_size,
603 mach_msg_size_t rcv_size,
604 mach_port_t rcv_name,
605 mach_msg_timeout_t timeout,
608 return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
617 /* There is nothing to print. Hurd has no auxiliary vector. */
621 /* Return an array of useful/necessary hardware capability names. */
622 const struct r_strlenpair *
624 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
625 size_t *max_capstrlen)
627 struct r_strlenpair *result;
629 /* Return an empty array. Hurd has no hardware capabilities. */
630 result = (struct r_strlenpair *) malloc (sizeof (*result));
632 _dl_signal_error (ENOMEM, NULL, NULL, "cannot create capability list");
634 result[0].str = (char *) result; /* Does not really matter. */
642 _dl_init_first (int argc, ...)
644 /* This no-op definition only gets used if libc is not linked in. */