Update.
[glibc.git] / sysdeps / mach / hurd / dl-sysdep.c
bloba17e92aff354fd56edca748feae2d54a2a9b7e95
1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995,96,97,98,99,2000,2001 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
18 02111-1307 USA. */
20 #include <hurd.h>
21 #include <link.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <sys/mman.h>
26 #include <ldsodefs.h>
27 #include <sys/wait.h>
28 #include <assert.h>
29 #include <sysdep.h>
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>
35 #include <stdarg.h>
36 #include <ctype.h>
37 #include <sys/stat.h>
38 #include <sys/uio.h>
40 #include <entry.h>
41 #include <dl-machine.h>
42 #include <dl-procinfo.h>
44 extern void __mach_init (void);
46 extern int _dl_argc;
47 extern char **_dl_argv;
48 extern char **_environ;
50 int __libc_enable_secure;
51 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
52 of init-first. */
53 /* This variable containts the lowest stack address ever used. */
54 void *__libc_stack_end;
55 unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
58 struct hurd_startup_data *_dl_hurd_data;
60 /* Defining these variables here avoids the inclusion of hurdsig.c. */
61 unsigned long int __hurd_sigthread_stack_base;
62 unsigned long int __hurd_sigthread_stack_end;
63 unsigned long int *__hurd_sigthread_variables;
65 /* Defining these variables here avoids the inclusion of init-first.c.
66 We need to provide temporary storage for the per-thread variables
67 of the main user thread here, since it is used for storing the
68 `errno' variable. Note that this information is lost once we
69 relocate the dynamic linker. */
70 static unsigned long int threadvars[_HURD_THREADVAR_MAX];
71 unsigned long int __hurd_threadvar_stack_offset
72 = (unsigned long int) &threadvars;
73 unsigned long int __hurd_threadvar_stack_mask;
75 /* XXX loser kludge for vm_map kernel bug */
76 static vm_address_t fmha;
77 static vm_size_t fmhs;
78 static void unfmh(void){
79 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
80 static void fmh(void) {
81 error_t err;int x;mach_port_t p;
82 vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
83 while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){
84 __mach_port_deallocate(__mach_task_self(),p);
85 if (a+fmhs>=0x80000000U){
86 max=a; break;}
87 fmha=a+=fmhs;}
88 if (err) assert(err==KERN_NO_SPACE);
89 if (!fmha)fmhs=0;else{
90 fmhs=max-fmha;
91 err = __vm_map (__mach_task_self (),
92 &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
93 VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
94 assert_perror(err);}
96 /* XXX loser kludge for vm_map kernel bug */
100 Elf32_Addr
101 _dl_sysdep_start (void **start_argptr,
102 void (*dl_main) (const Elf32_Phdr *phdr, Elf32_Word phent,
103 Elf32_Addr *user_entry))
105 void go (int *argdata)
107 extern unsigned int _dl_skip_args; /* rtld.c */
108 char **p;
110 /* Cache the information in various global variables. */
111 _dl_argc = *argdata;
112 _dl_argv = 1 + (char **) argdata;
113 _environ = &_dl_argv[_dl_argc + 1];
114 for (p = _environ; *p++;); /* Skip environ pointers and terminator. */
116 if ((void *) p == _dl_argv[0])
118 static struct hurd_startup_data nodata;
119 _dl_hurd_data = &nodata;
120 nodata.user_entry = (vm_address_t) ENTRY_POINT;
122 else
123 _dl_hurd_data = (void *) p;
125 __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE;
127 if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
128 _dl_hurd_data->user_entry == 0)
129 _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
131 unfmh(); /* XXX */
133 #if 0 /* XXX make this work for real someday... */
134 if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
135 /* We were invoked as a command, not as the program interpreter.
136 The generic ld.so code supports this: it will parse the args
137 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
138 support an additional special syntax:
139 ld.so [-LIBS...] PROGRAM [ARGS...]
140 Each LIBS word consists of "FILENAME=MEMOBJ";
141 for example "-/lib/libc.so=123" says that the contents of
142 /lib/libc.so are found in a memory object whose port name
143 in our task is 123. */
144 while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
146 char *lastslash, *memobjname, *p;
147 struct link_map *l;
148 mach_port_t memobj;
149 error_t err;
151 ++_dl_skip_args;
152 --_dl_argc;
153 p = _dl_argv++[1] + 1;
155 memobjname = strchr (p, '=');
156 if (! memobjname)
157 _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
158 *memobjname++ = '\0';
159 memobj = 0;
160 while (*memobjname != '\0')
161 memobj = (memobj * 10) + (*memobjname++ - '0');
163 /* Add a user reference on the memory object port, so we will
164 still have one after _dl_map_object_from_fd calls our
165 `close'. */
166 err = __mach_port_mod_refs (__mach_task_self (), memobj,
167 MACH_PORT_RIGHT_SEND, +1);
168 assert_perror (err);
170 lastslash = strrchr (p, '/');
171 l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p,
172 memobj, strdup (p), 0);
174 /* Squirrel away the memory object port where it
175 can be retrieved by the program later. */
176 l->l_info[DT_NULL] = (void *) memobj;
178 #endif
180 /* Call elf/rtld.c's main program. It will set everything
181 up and leave us to transfer control to USER_ENTRY. */
182 (*dl_main) ((const Elf32_Phdr *) _dl_hurd_data->phdr,
183 _dl_hurd_data->phdrsz / sizeof (Elf32_Phdr),
184 &_dl_hurd_data->user_entry);
186 /* The call above might screw a few things up.
188 First of all, if _dl_skip_args is nonzero, we are ignoring
189 the first few arguments. However, if we have no Hurd startup
190 data, it is the magical convention that ARGV[0] == P. The
191 startup code in init-first.c will get confused if this is not
192 the case, so we must rearrange things to make it so. We'll
193 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
195 Secondly, if we need to be secure, it removes some dangerous
196 environment variables. If we have no Hurd startup date this
197 changes P (since that's the location after the terminating
198 NULL in the list of environment variables). We do the same
199 thing as in the first case but make sure we recalculate P.
200 If we do have Hurd startup data, we have to move the data
201 such that it starts just after the terminating NULL in the
202 environment list.
204 We use memmove, since the locations might overlap. */
205 if (__libc_enable_secure || _dl_skip_args)
207 char **newp;
209 for (newp = _environ; *newp++;);
211 if (_dl_argv[-_dl_skip_args] == (char *) p)
213 if ((char *) newp != _dl_argv[0])
215 assert ((char *) newp < _dl_argv[0]);
216 _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
217 strlen (_dl_argv[0]) + 1);
220 else
222 if ((void *) newp != _dl_hurd_data)
223 memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
228 extern void _dl_start_user (void);
229 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
230 to the RTLD_START code which will run the user's entry point. */
231 RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
235 /* Set up so we can do RPCs. */
236 __mach_init ();
238 /* Initialize frequently used global variable. */
239 _dl_pagesize = __getpagesize ();
241 fmh(); /* XXX */
243 /* See hurd/hurdstartup.c; this deals with getting information
244 from the exec server and slicing up the arguments.
245 Then it will call `go', above. */
246 _hurd_startup (start_argptr, &go);
248 LOSE;
249 abort ();
252 void
253 internal_function
254 _dl_sysdep_start_cleanup (void)
256 /* Deallocate the reply port and task port rights acquired by
257 __mach_init. We are done with them now, and the user will
258 reacquire them for himself when he wants them. */
259 __mig_dealloc_reply_port (MACH_PORT_NULL);
260 __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
263 /* Minimal open/close/mmap implementation sufficient for initial loading of
264 shared libraries. These are weak definitions so that when the
265 dynamic linker re-relocates itself to be user-visible (for -ldl),
266 it will get the user's definition (i.e. usually libc's). */
268 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
269 error. If STAT is non-zero, stat the file into that stat buffer. */
270 static error_t
271 open_file (const char *file_name, int flags,
272 mach_port_t *port, struct stat *stat)
274 enum retry_type doretry;
275 char retryname[1024]; /* XXX string_t LOSES! */
276 file_t startdir;
277 error_t err;
279 error_t use_init_port (int which, error_t (*operate) (file_t))
281 return (which < _dl_hurd_data->portarraysize
282 ? ((*operate) (_dl_hurd_data->portarray[which]))
283 : EGRATUITOUS);
285 file_t get_dtable_port (int fd)
287 if ((unsigned int) fd < _dl_hurd_data->dtablesize
288 && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
290 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
291 MACH_PORT_RIGHT_SEND, +1);
292 return _dl_hurd_data->dtable[fd];
294 errno = EBADF;
295 return MACH_PORT_NULL;
298 assert (!(flags & ~O_READ));
300 startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
301 INIT_PORT_CRDIR : INIT_PORT_CWDIR];
303 while (file_name[0] == '/')
304 file_name++;
306 err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
307 &doretry, retryname, port);
309 if (!err)
310 err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
311 __dir_lookup, doretry, retryname,
312 O_RDONLY, 0, port);
313 if (!err && stat)
315 err = __io_stat (*port, stat);
316 if (err)
317 __mach_port_deallocate (__mach_task_self (), *port);
320 return err;
323 int weak_function
324 __open (const char *file_name, int mode, ...)
326 mach_port_t port;
327 error_t err = open_file (file_name, mode, &port, 0);
328 if (err)
329 return __hurd_fail (err);
330 else
331 return (int)port;
334 int weak_function
335 __close (int fd)
337 if (fd != (int) MACH_PORT_NULL)
338 __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
339 return 0;
342 __ssize_t weak_function
343 __libc_read (int fd, void *buf, size_t nbytes)
345 error_t err;
346 char *data;
347 mach_msg_type_number_t nread;
349 data = buf;
350 err = __io_read ((mach_port_t) fd, &data, &nread, -1, nbytes);
351 if (err)
352 return __hurd_fail (err);
354 if (data != buf)
356 memcpy (buf, data, nread);
357 __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
360 return nread;
363 __ssize_t weak_function
364 __libc_write (int fd, const void *buf, size_t nbytes)
366 error_t err;
367 mach_msg_type_number_t nwrote;
369 assert (fd < _hurd_init_dtablesize);
371 err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
372 if (err)
373 return __hurd_fail (err);
375 return nwrote;
378 /* This is only used for printing messages (see dl-misc.c). */
379 __ssize_t weak_function
380 __writev (int fd, const struct iovec *iov, int niov)
382 int i;
383 size_t total = 0;
384 for (i = 0; i < niov; ++i)
385 total += iov[i].iov_len;
387 assert (fd < _hurd_init_dtablesize);
389 if (total != 0)
391 char buf[total], *bufp = buf;
392 error_t err;
393 mach_msg_type_number_t nwrote;
395 for (i = 0; i < niov; ++i)
396 bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
397 + iov[i].iov_len);
399 err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
400 if (err)
401 return __hurd_fail (err);
403 return nwrote;
405 return 0;
409 off_t weak_function
410 __lseek (int fd, off_t offset, int whence)
412 error_t err;
414 err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
415 if (err)
416 return __hurd_fail (err);
418 return offset;
421 __ptr_t weak_function
422 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
424 error_t err;
425 vm_prot_t vmprot;
426 vm_address_t mapaddr;
427 mach_port_t memobj_rd, memobj_wr;
429 vmprot = VM_PROT_NONE;
430 if (prot & PROT_READ)
431 vmprot |= VM_PROT_READ;
432 if (prot & PROT_WRITE)
433 vmprot |= VM_PROT_WRITE;
434 if (prot & PROT_EXEC)
435 vmprot |= VM_PROT_EXECUTE;
437 if (flags & MAP_ANON)
438 memobj_rd = MACH_PORT_NULL;
439 else
441 assert (!(flags & MAP_SHARED));
442 err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
443 if (err)
444 return (__ptr_t) __hurd_fail (err);
445 __mach_port_deallocate (__mach_task_self (), memobj_wr);
448 mapaddr = (vm_address_t) addr;
449 err = __vm_map (__mach_task_self (),
450 &mapaddr, (vm_size_t) len, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
451 !(flags & MAP_FIXED),
452 memobj_rd,
453 (vm_offset_t) offset,
454 flags & (MAP_COPY|MAP_PRIVATE),
455 vmprot, VM_PROT_ALL,
456 (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
457 if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
459 /* XXX this is not atomic as it is in unix! */
460 /* The region is already allocated; deallocate it first. */
461 err = __vm_deallocate (__mach_task_self (), mapaddr, len);
462 if (! err)
463 err = __vm_map (__mach_task_self (),
464 &mapaddr, (vm_size_t) len, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
465 !(flags & MAP_FIXED),
466 memobj_rd, (vm_offset_t) offset,
467 flags & (MAP_COPY|MAP_PRIVATE),
468 vmprot, VM_PROT_ALL,
469 (flags & MAP_SHARED)
470 ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
473 if ((flags & MAP_ANON) == 0)
474 __mach_port_deallocate (__mach_task_self (), memobj_rd);
476 return err ? (__ptr_t) __hurd_fail (err) : (__ptr_t) mapaddr;
479 int weak_function
480 __fxstat (int vers, int fd, struct stat *buf)
482 error_t err;
484 assert (vers == _STAT_VER);
486 err = __io_stat ((mach_port_t) fd, buf);
487 if (err)
488 return __hurd_fail (err);
490 return 0;
493 int weak_function
494 __xstat (int vers, const char *file, struct stat *buf)
496 error_t err;
497 mach_port_t port;
499 assert (vers == _STAT_VER);
501 err = open_file (file, 0, &port, buf);
502 if (err)
503 return __hurd_fail (err);
505 __mach_port_deallocate (__mach_task_self (), port);
507 return 0;
510 /* This function is called by the dynamic linker (rtld.c) to check
511 whether debugging malloc is allowed even for SUID binaries. This
512 stub will always fail, which means that malloc-debugging is always
513 disabled for SUID binaries. */
514 int weak_function
515 __access (const char *file, int type)
517 errno = ENOSYS;
518 return -1;
521 pid_t weak_function
522 __getpid ()
524 pid_t pid, ppid;
525 int orphaned;
527 if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
528 &pid, &ppid, &orphaned))
529 return -1;
531 return pid;
534 /* This is called only in some strange cases trying to guess a value
535 for $ORIGIN for the executable. The dynamic linker copes with
536 getcwd failing (dl-object.c), and it's too much hassle to include
537 the functionality here. (We could, it just requires duplicating or
538 reusing getcwd.c's code but using our special lookup function as in
539 `open', above.) */
540 char *
541 weak_function
542 __getcwd (char *buf, size_t size)
544 errno = ENOSYS;
545 return NULL;
548 void weak_function
549 _exit (int status)
551 __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
552 W_EXITCODE (status, 0), 0);
553 while (__task_terminate (__mach_task_self ()))
554 __mach_task_self_ = (__mach_task_self) ();
557 /* Try to get a machine dependent instruction which will make the
558 program crash. This is used in case everything else fails. */
559 #include <abort-instr.h>
560 #ifndef ABORT_INSTRUCTION
561 /* No such instruction is available. */
562 # define ABORT_INSTRUCTION
563 #endif
565 void weak_function
566 abort (void)
568 /* Try to abort using the system specific command. */
569 ABORT_INSTRUCTION;
571 /* If the abort instruction failed, exit. */
572 _exit (127);
574 /* If even this fails, make sure we never return. */
575 while (1)
576 /* Try for ever and ever. */
577 ABORT_INSTRUCTION;
580 /* This function is called by interruptible RPC stubs. For initial
581 dynamic linking, just use the normal mach_msg. Since this defn is
582 weak, the real defn in libc.so will override it if we are linked into
583 the user program (-ldl). */
585 error_t weak_function
586 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
587 mach_msg_option_t option,
588 mach_msg_size_t send_size,
589 mach_msg_size_t rcv_size,
590 mach_port_t rcv_name,
591 mach_msg_timeout_t timeout,
592 mach_port_t notify)
594 return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
595 timeout, notify);
599 void
600 internal_function
601 _dl_show_auxv (void)
603 /* There is nothing to print. Hurd has no auxiliary vector. */
607 /* Return an array of useful/necessary hardware capability names. */
608 const struct r_strlenpair *
609 internal_function
610 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
611 size_t *max_capstrlen)
613 struct r_strlenpair *result;
615 /* Return an empty array. Hurd has no hardware capabilities. */
616 result = (struct r_strlenpair *) malloc (sizeof (*result));
617 if (result == NULL)
618 _dl_signal_error (ENOMEM, NULL, NULL, "cannot create capability list");
620 result[0].str = (char *) result; /* Does not really matter. */
621 result[0].len = 0;
623 *sz = 1;
624 return result;
627 void weak_function
628 _dl_init_first (int argc, ...)
630 /* This no-op definition only gets used if libc is not linked in. */