about summary refs log tree commit diff
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