diff options
Diffstat (limited to 'sysdeps/mach/hurd/dl-sysdep.c')
-rw-r--r-- | sysdeps/mach/hurd/dl-sysdep.c | 494 |
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) |