summaryrefslogtreecommitdiff
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.c73
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