diff options
Diffstat (limited to 'sysdeps/mach/hurd/dl-sysdep.c')
-rw-r--r-- | sysdeps/mach/hurd/dl-sysdep.c | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c index e55a615287..2daf74957c 100644 --- a/sysdeps/mach/hurd/dl-sysdep.c +++ b/sysdeps/mach/hurd/dl-sysdep.c @@ -80,20 +80,75 @@ _dl_sysdep_start (void **start_argptr, void (*dl_main) (const Elf32_Phdr *phdr, Elf32_Word phent, Elf32_Addr *user_entry)) { + extern void _start (); + void go (int *argdata) { + extern unsigned int _dl_skip_args; /* rtld.c */ char **p; /* Cache the information in various global variables. */ _dl_argc = *argdata; - _dl_argv = (void *) &argdata[1]; + _dl_argv = 1 + (char **) argdata; _environ = &_dl_argv[_dl_argc + 1]; - for (p = _environ; *p; ++p); - _dl_hurd_data = (void *) ++p; + for (p = _environ; *p++;); /* Skip environ pointers and terminator. */ + + if ((void *) p == _dl_argv[0]) + { + static struct hurd_startup_data nodata; + _dl_hurd_data = &nodata; + nodata.user_entry = (vm_address_t) &_start; + } + else + _dl_hurd_data = (void *) p; _dl_secure = _dl_hurd_data->flags & EXEC_SECURE; unfmh(); /* XXX */ + + if (_dl_hurd_data->user_entry == (vm_address_t) &_start) + /* We were invoked as a command, not as the program interpreter. + The generic ld.so code supports this: it will parse the args + as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we + support an additional special syntax: + ld.so [-LIBS...] PROGRAM [ARGS...] + Each LIBS word consists of "FILENAME=MEMOBJ"; + for example "-/lib/libc.so=123" says that the contents of + /lib/libc.so are found in a memory object whose port name + in our task is 123. */ + while (_dl_argc > 2 && _dl_argv[1][0] == '-') + { + char *lastslash, *memobjname, *p; + struct link_map *l; + mach_port_t memobj; + error_t err; + + ++_dl_skip_args; + --_dl_argc; + p = _dl_argv++[1] + 1; + + memobjname = strchr (p, '='); + if (! memobjname) + _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL); + *memobjname++ = '\0'; + memobj = (mach_port_t) atoi (memobjname); + + /* Add a user reference on the memory object port, so we will + still have one after _dl_map_object_from_fd calls our + `close'. */ + err = __mach_port_mod_refs (__mach_task_self (), memobj, + MACH_PORT_RIGHT_SEND, +1); + assert_perror (err); + + lastslash = strrchr (p, '/'); + l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p, + memobj, strdup (p)); + + /* Squirrel away the memory object port where it + can be retrieved by the program later. */ + l->l_info[DT_NULL] = (void *) memobj; + } + /* 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, @@ -106,6 +161,18 @@ unfmh(); /* XXX */ __mig_dealloc_reply_port (MACH_PORT_NULL); __mach_port_deallocate (__mach_task_self (), __mach_task_self_); + if (_dl_skip_args && _dl_argv[-_dl_skip_args] == (char *) p) + { + /* We are ignoring the first few arguments, but we have no Hurd + startup data. It is magical convention that ARGV[0] == P in + this case. The startup code in init-first.c will get confused + if this is not the case, so we must rearrange things to make + it so. Overwrite the original ARGV[0] at P with + ARGV[_dl_skip_args]. */ + assert ((char *) p < _dl_argv[0]); + _dl_argv[0] = strcpy ((char *) p, _dl_argv[0]); + } + { extern void _dl_start_user (void); /* Unwind the stack to ARGDATA and simulate a return from _dl_start |