aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/mach/hurd/dl-sysdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/dl-sysdep.c')
-rw-r--r--sysdeps/mach/hurd/dl-sysdep.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c
new file mode 100644
index 0000000000..1dca319433
--- /dev/null
+++ b/sysdeps/mach/hurd/dl-sysdep.c
@@ -0,0 +1,494 @@
+/* Operating system support for run-time dynamic linker. Hurd version.
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <link.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <sysdep.h>
+#include <mach/mig_support.h>
+#include "hurdstartup.h"
+#include <mach/host_info.h>
+#include "../stdio/_itoa.h"
+#include <hurd/auth.h>
+#include <hurd/term.h>
+#include <stdarg.h>
+
+#include "dl-machine.h"
+
+extern int _dl_argc;
+extern char **_dl_argv;
+extern char **_environ;
+
+struct hurd_startup_data *_dl_hurd_data;
+
+Elf32_Addr
+_dl_sysdep_start (void **start_argptr,
+ void (*dl_main) (const Elf32_Phdr *phdr, Elf32_Word phent,
+ Elf32_Addr *user_entry))
+{
+ void go (int *argdata)
+ {
+ char **p;
+
+ /* Cache the information in various global variables. */
+ _dl_argc = *argdata++;
+ _dl_argv = (void *) argdata;
+ _environ = &_dl_argv[_dl_argc + 1];
+ for (p = _environ; *p; ++p);
+ _dl_hurd_data = (void *) ++p;
+
+ _dl_secure = _dl_hurd_data->flags & EXEC_SECURE;
+
+ /* Call elf/rtld.c's main program. It will set everything
+ up and leave us to transfer control to USER_ENTRY. */
+ (*dl_main) ((const Elf32_Phdr *) _dl_hurd_data->phdr,
+ _dl_hurd_data->phdrsz / sizeof (Elf32_Phdr),
+ &_dl_hurd_data->user_entry);
+
+ {
+ extern void _dl_start_user (void);
+ /* Unwind the stack to ARGDATA and simulate a return from _dl_start
+ to the RTLD_START code which will run the user's entry point. */
+ RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
+ }
+ }
+
+ /* See hurd/hurdstartup.c; this deals with getting information
+ from the exec server and slicing up the arguments.
+ Then it will call `go', above. */
+ _hurd_startup (start_argptr, &go);
+
+ LOSE;
+}
+
+/* This is called when all other dynamic linking is finished, before the
+ dynamic linker re-relocates itself when ld.so itself appears in a
+ DT_NEEDED entry. It is called whether of not ld.so is being linked in.
+
+ We take this opportunity to deallocate the reply port and task-self send
+ right user reference we have acquired, since they will not be used again
+ before the library and user code runs. The C library will acquire its
+ own ports in its initialization. */
+
+void
+_dl_sysdep_prepare_for_ld_reloc (void)
+{
+ __mig_dealloc_reply_port (__mig_get_reply_port ());
+ __mach_port_deallocate (__mach_task_self (), __mach_task_self ());
+}
+
+int
+_dl_sysdep_open_zero_fill (void)
+{
+ return (int) MACH_PORT_NULL;
+}
+
+
+void
+_dl_sysdep_fatal (const char *msg, ...)
+{
+ extern __typeof (__io_write) __hurd_intr_rpc_io_write;
+ va_list ap;
+
+ va_start (ap, msg);
+ do
+ {
+ size_t len = strlen (msg);
+ mach_msg_type_number_t nwrote;
+ do
+ {
+ if (__hurd_intr_rpc_io_write (_hurd_init_dtable[2],
+ msg, len, -1, &nwrote))
+ break;
+ len -= nwrote;
+ msg += nwrote;
+ } while (nwrote > 0);
+ msg = va_arg (ap, const char *);
+ } while (msg);
+ va_end (ap);
+
+ _exit (127);
+}
+
+
+/* Minimal open/close/mmap implementation sufficient for initial loading of
+ shared libraries. These are weak definitions so that when the
+ dynamic linker re-relocates itself to be user-visible (for -ldl),
+ it will get the user's definition (i.e. usually libc's). */
+
+int
+open (const char *file_name, int mode, ...)
+{
+ extern __typeof (__dir_lookup) __hurd_intr_rpc_dir_lookup;
+ extern __typeof (__io_reauthenticate) __hurd_intr_rpc_io_reauthenticate;
+ enum retry_type doretry;
+ char retryname[1024]; /* XXX string_t LOSES! */
+ file_t startdir, newpt, fileport;
+ int dealloc_dir;
+ int nloops;
+
+
+ assert (mode == O_RDONLY);
+
+
+ startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
+ INIT_PORT_CRDIR : INIT_PORT_CWDIR];
+
+ while (file_name[0] == '/')
+ file_name++;
+
+ if (errno = __hurd_intr_rpc_dir_lookup (startdir, file_name, mode, 0,
+ &doretry, retryname, &fileport))
+ return -1;
+
+ dealloc_dir = 0;
+ nloops = 0;
+ errno = 0;
+
+ while (1)
+ {
+ if (dealloc_dir)
+ __mach_port_deallocate (__mach_task_self (), startdir);
+ if (errno)
+ return -1;
+
+ switch (doretry)
+ {
+ case FS_RETRY_REAUTH:
+ {
+ mach_port_t ref = __mach_reply_port ();
+ errno = __hurd_intr_rpc_io_reauthenticate
+ (fileport, ref, MACH_MSG_TYPE_MAKE_SEND);
+ if (! errno)
+ errno = __auth_user_authenticate
+ (_dl_hurd_data->portarray[INIT_PORT_AUTH],
+ fileport,
+ ref, MACH_MSG_TYPE_MAKE_SEND,
+ &newpt);
+ __mach_port_destroy (__mach_task_self (), ref);
+ }
+ __mach_port_deallocate (__mach_task_self (), fileport);
+ if (errno)
+ return -1;
+ fileport = newpt;
+ /* Fall through. */
+
+ case FS_RETRY_NORMAL:
+#ifdef SYMLOOP_MAX
+ if (nloops++ >= SYMLOOP_MAX)
+ {
+ errno = ELOOP;
+ return -1;
+ }
+#endif
+
+ /* An empty RETRYNAME indicates we have the final port. */
+ if (retryname[0] == '\0')
+ {
+ mach_port_t memobj_rd, memobj_wr;
+ extern __typeof (__io_map) __hurd_intr_rpc_io_map;
+
+ dealloc_dir = 1;
+
+ opened:
+ /* We have the file open. Now map it. */
+ errno = __hurd_intr_rpc_io_map (fileport,
+ &memobj_rd, &memobj_wr);
+ if (dealloc_dir)
+ __mach_port_deallocate (__mach_task_self (), fileport);
+ if (errno)
+ return -1;
+ if (memobj_wr != MACH_PORT_NULL)
+ __mach_port_deallocate (__mach_task_self (), memobj_wr);
+
+ return (int) memobj_rd;
+ }
+
+ startdir = fileport;
+ dealloc_dir = 1;
+ file_name = retryname;
+ break;
+
+ case FS_RETRY_MAGICAL:
+ switch (retryname[0])
+ {
+ case '/':
+ startdir = _dl_hurd_data->portarray[INIT_PORT_CRDIR];
+ dealloc_dir = 0;
+ if (fileport != MACH_PORT_NULL)
+ __mach_port_deallocate (__mach_task_self (), fileport);
+ file_name = &retryname[1];
+ break;
+
+ case 'f':
+ if (retryname[1] == 'd' && retryname[2] == '/')
+ {
+ int fd;
+ char *end;
+ errno = 0;
+ fd = (int) strtol (retryname, &end, 10);
+ if (end == NULL || errno || /* Malformed number. */
+ /* Check for excess text after the number. A slash
+ is valid; it ends the component. Anything else
+ does not name a numeric file descriptor. */
+ (*end != '/' && *end != '\0'))
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ if (fd < 0 || fd >= _dl_hurd_data->dtablesize ||
+ _dl_hurd_data->dtable[fd] == MACH_PORT_NULL)
+ {
+ /* If the name was a proper number, but the file
+ descriptor does not exist, we return EBADF instead
+ of ENOENT. */
+ errno = EBADF;
+ return -1;
+ }
+ fileport = _dl_hurd_data->dtable[fd];
+ if (*end == '\0')
+ {
+ /* This descriptor is the file port we want. */
+ dealloc_dir = 0;
+ goto opened;
+ }
+ else
+ {
+ /* Do a normal retry on the remaining components. */
+ startdir = fileport;
+ dealloc_dir = 1;
+ file_name = end + 1; /* Skip the slash. */
+ break;
+ }
+ }
+ else
+ goto bad_magic;
+ break;
+
+ case 'm':
+ if (retryname[1] == 'a' && retryname[2] == 'c' &&
+ retryname[3] == 'h' && retryname[4] == 't' &&
+ retryname[5] == 'y' && retryname[6] == 'p' &&
+ retryname[7] == 'e')
+ {
+ error_t err;
+ struct host_basic_info hostinfo;
+ mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT;
+ char *p;
+ if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
+ (natural_t *) &hostinfo,
+ &hostinfocnt))
+ return err;
+ if (hostinfocnt != HOST_BASIC_INFO_COUNT)
+ return EGRATUITOUS;
+ p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
+ *--p = '/';
+ p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
+ if (p < retryname)
+ abort (); /* XXX write this right if this ever happens */
+ if (p > retryname)
+ strcpy (retryname, p);
+ startdir = fileport;
+ dealloc_dir = 1;
+ }
+ else
+ goto bad_magic;
+ break;
+
+ case 't':
+ if (retryname[1] == 't' && retryname[2] == 'y')
+ switch (retryname[3])
+ {
+ error_t opentty (file_t *result)
+ {
+ error_t err;
+ file_t unauth;
+ err = __termctty_open_terminal
+ (_dl_hurd_data->portarray[INIT_PORT_CTTYID],
+ mode, &unauth);
+ if (! err)
+ {
+ mach_port_t ref = __mach_reply_port ();
+ err = __hurd_intr_rpc_io_reauthenticate
+ (unauth, ref, MACH_MSG_TYPE_MAKE_SEND);
+ if (! err)
+ err = __auth_user_authenticate
+ (_dl_hurd_data->portarray[INIT_PORT_AUTH],
+ unauth,
+ ref, MACH_MSG_TYPE_MAKE_SEND,
+ result);
+ __mach_port_deallocate (__mach_task_self (),
+ unauth);
+ __mach_port_destroy (__mach_task_self (), ref);
+ }
+ return err;
+ }
+
+ case '\0':
+ if (errno = opentty (&fileport))
+ return -1;
+ dealloc_dir = 1;
+ goto opened;
+ case '/':
+ if (errno = opentty (&startdir))
+ return -1;
+ dealloc_dir = 1;
+ strcpy (retryname, &retryname[4]);
+ break;
+ default:
+ goto bad_magic;
+ }
+ else
+ goto bad_magic;
+ break;
+
+ default:
+ bad_magic:
+ errno = EGRATUITOUS;
+ return -1;
+ }
+ break;
+
+ default:
+ errno = EGRATUITOUS;
+ return -1;
+ }
+
+ errno = __hurd_intr_rpc_dir_lookup (startdir, file_name, mode, 0,
+ &doretry, retryname, &fileport);
+ }
+}
+
+int
+close (int fd)
+{
+ if (fd != (int) MACH_PORT_NULL)
+ __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
+ return 0;
+}
+
+caddr_t
+mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+ vm_prot_t vmprot;
+ vm_address_t mapaddr;
+
+ vmprot = VM_PROT_NONE;
+ if (prot & PROT_READ)
+ vmprot |= VM_PROT_READ;
+ if (prot & PROT_WRITE)
+ vmprot |= VM_PROT_WRITE;
+ if (prot & PROT_EXEC)
+ vmprot |= VM_PROT_EXECUTE;
+
+ mapaddr = (vm_address_t) addr;
+ errno = __vm_map (__mach_task_self (),
+ &mapaddr, (vm_size_t) len, (vm_address_t) 0,
+ !(flags & MAP_FIXED),
+ (mach_port_t) fd, (vm_offset_t) offset,
+ flags & (MAP_COPY|MAP_PRIVATE),
+ vmprot, VM_PROT_ALL,
+ (flags & MAP_INHERIT) ? VM_INHERIT_COPY : VM_INHERIT_NONE);
+ return errno ? (caddr_t) -1 : (caddr_t) mapaddr;
+}
+
+void
+_exit (int status)
+{
+ extern __typeof (__proc_mark_exit) __hurd_intr_rpc_proc_mark_exit;
+ __hurd_intr_rpc_proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
+ W_EXITCODE (status, 0));
+ while (__task_terminate (__mach_task_self ()))
+ __mach_task_self_ = (__mach_task_self) ();
+}
+
+weak_symbol (_exit)
+weak_symbol (open)
+weak_symbol (close)
+weak_symbol (mmap)
+
+/* Minimal `malloc' allocator for use while loading shared libraries.
+ Only small blocks are allocated, and none are ever freed. */
+
+void *
+malloc (size_t n)
+{
+ static vm_address_t ptr, end;
+ void *block;
+
+ if (end == 0)
+ {
+ /* Consume any unused space in the last page of our data segment. */
+ extern char _end;
+ ptr = (vm_address_t) &_end;
+ end = round_page (ptr);
+ }
+
+ /* Make sure the allocation pointer is ideally aligned. */
+ ptr += sizeof (double) - 1;
+ ptr &= ~(sizeof (double) - 1);
+
+ if (ptr + n >= end)
+ {
+ /* Insufficient space left; allocate another page. */
+ vm_address_t page;
+ assert (n <= __vm_page_size);
+ __vm_allocate (__mach_task_self (), &page, __vm_page_size, 1);
+ if (page != end)
+ ptr = page;
+ end = page + __vm_page_size;
+ }
+
+ block = (void *) ptr;
+ ptr += n;
+ return block;
+}
+
+weak_symbol (malloc)
+
+/* These should never be called. */
+void *realloc (void *ptr, size_t n) { ptr += n; abort (); }
+void free (void *ptr) { ptr = ptr; abort (); }
+weak_symbol (realloc)
+weak_symbol (free)
+
+/* Avoid signal frobnication in setjmp/longjmp. */
+
+int __sigjmp_save (sigjmp_buf env, int savemask)
+{ env[0].__mask_was_saved = savemask; return 0; }
+weak_symbol (__sigjmp_save)
+
+void
+longjmp (jmp_buf env, int val) { __longjmp (env[0].__jmpbuf, val); }
+weak_symbol (longjmp)
+
+
+/* Stub out this function that is called by interruptible RPC stubs. It
+ should never get called during initial dynamic linking, because we use
+ only the raw MiG stub functions __hurd_intr_rpc_*. Since this defn is
+ weak, the real defn in libc.so will override it if we are linked into
+ the user program (-ldl). */
+struct hurd_sigstate *
+_hurd_thread_sigstate (thread_t thread) { thread = thread; abort (); }
+weak_symbol (_hurd_thread_sigstate)