about summary refs log tree commit diff
path: root/sysdeps/mach
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach')
-rw-r--r--sysdeps/mach/hurd/dl-sysdep.c15
-rw-r--r--sysdeps/mach/hurd/i386/init-first.c71
2 files changed, 68 insertions, 18 deletions
diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c
index 1dca319433..d4845213f4 100644
--- a/sysdeps/mach/hurd/dl-sysdep.c
+++ b/sysdeps/mach/hurd/dl-sysdep.c
@@ -36,6 +36,8 @@ Cambridge, MA 02139, USA.  */
 
 #include "dl-machine.h"
 
+extern void __mach_init (void);
+
 extern int _dl_argc;
 extern char **_dl_argv;
 extern char **_environ;
@@ -52,8 +54,8 @@ _dl_sysdep_start (void **start_argptr,
       char **p;
 
       /* Cache the information in various global variables.  */
-      _dl_argc = *argdata++;
-      _dl_argv = (void *) argdata;
+      _dl_argc = *argdata;
+      _dl_argv = (void *) &argdata[1];
       _environ = &_dl_argv[_dl_argc + 1];
       for (p = _environ; *p; ++p);
       _dl_hurd_data = (void *) ++p;
@@ -66,6 +68,12 @@ _dl_sysdep_start (void **start_argptr,
 		  _dl_hurd_data->phdrsz / sizeof (Elf32_Phdr),
 		  &_dl_hurd_data->user_entry);
 
+      /* Deallocate the reply port and task port rights acquired by
+	 __mach_init.  We are done with them now, and the user will
+	 reacquire them for himself when he wants them.  */
+      __mig_dealloc_reply_port (MACH_PORT_NULL);
+      __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
+
       {
 	extern void _dl_start_user (void);
 	/* Unwind the stack to ARGDATA and simulate a return from _dl_start
@@ -74,6 +82,9 @@ _dl_sysdep_start (void **start_argptr,
       }
     }
 
+  /* Set up so we can do RPCs.  */
+  __mach_init ();
+
   /* See hurd/hurdstartup.c; this deals with getting information
      from the exec server and slicing up the arguments.
      Then it will call `go', above.  */
diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c
index d747e75c7d..74b15c8f2f 100644
--- a/sysdeps/mach/hurd/i386/init-first.c
+++ b/sysdeps/mach/hurd/i386/init-first.c
@@ -95,8 +95,8 @@ init1 (int argc, char *arg0, ...)
   __libc_init (argc, argv, __environ);
 }
 
-static void 
-init (int *data, int retaddr)
+static void
+init (int *data, void *usercode, void **retaddrloc)
 {
   int argc = *data;
   char **argv = (void *) (data + 1);
@@ -115,6 +115,11 @@ init (int *data, int retaddr)
   if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
     __hurd_threadvar_max = _HURD_THREADVAR_MAX;
 
+
+  /* After possibly switching stacks, call `init1' (above) with the user
+     code as the return address, and the argument data immediately above
+     that on the stack.  */
+
   if (_cthread_init_routine)
     {
       /* Initialize cthreads, which will allocate us a new stack to run on.  */
@@ -136,13 +141,45 @@ init (int *data, int retaddr)
 	/* Copy the Hurd startup data block to the new stack.  */
 	*od = *d;
 
-      data = newsp;
+      /* Push the user code address on the top of the new stack.  It will
+	 be the return address for `init1'; we will jump there with NEWSP
+	 as the stack pointer.  */
+      *--(void **) newsp = usercode;
+      /* Mutate our own return address to run the code below.  */
+      *retaddrloc = &&switch_stacks;
+      /* Force NEWSP into %ecx and &init1 into %eax, which are not restored
+         by function return.  */
+      asm volatile ("# a %0 c %1" : : "a" (&init1), "c" (newsp));
+      return;
+    switch_stacks:
+      /* Our return address was redirected to here, so at this point our
+	 stack is unwound and callers' registers restored.  Only %ecx and
+	 %eax are call-clobbered and thus still have the values we set just
+	 above.  Fetch from there the new stack pointer we will run on, and
+	 jmp to the run-time address of `init1'; when it returns, it will
+	 run the user code with the argument data at the top of the stack.  */
+      asm volatile ("movl %ecx, %esp; jmp *%eax");
+      /* NOTREACHED */
+    }
+  else
+    {
+      /* We are not switching stacks, but we must play some games with
+	 the one we've got, similar to the stack-switching code above.  */
+      *retaddrloc = &&call_init1;
+      /* Force the user code address into %ecx and the run-time address of
+	 `init1' into %eax, for use below.  */
+      asm volatile ("# a %0 c %1" : : "a" (&init1), "c" (usercode));
+      return;
+    call_init1:
+      /* As in the stack-switching case, at this point our stack is unwound
+	 and callers' registers restored, and only %ecx and %eax
+	 communicate values from the lines above.  In this case we have
+	 stashed in %ecx the user code return address.  Push it on the top
+	 of the stack so it acts as init1's return address, and then jump
+	 there.  */
+      asm volatile ("pushl %ecx; jmp *%eax");
+      /* NOTREACHED */
     }
-
-  /* Call `init1' (above) with the user code as the return address,
-     and the argument data immediately above that on the stack.  */
-  *--data = retaddr;
-  asm volatile ("movl %0, %%esp; jmp %*%1" : : "g" (data), "r" (&init1));
 }  
 
 
@@ -151,30 +188,32 @@ init (int *data, int retaddr)
    It is called just before the user _start code from i386/elf/start.S,
    with the stack set up as that code gets it.  */
 
-static void soinit (int argc, ...) __attribute__ ((unused, section (".init")));
+/* NOTE!  The linker notices the magical name `_init' and sets the DT_INIT
+   pointer in the dynamic section based solely on that.  It is convention
+   for this function to be in the `.init' section, but the symbol name is
+   the only thing that really matters!!  */
+/*void _init (int argc, ...) __attribute__ ((unused, section (".init")));*/
 
-static void
-soinit (int argc, ...)
+void
+_init (int argc, ...)
 {
   /* Initialize data structures so we can do RPCs.  */
   __mach_init ();
 
   RUN_HOOK (_hurd_preinit_hook, ());
   
-  init (&argc, (&argc)[-1]);
-
-  (void) &soinit;		/* Avoid gcc optimizing this fn out.  */
+  init (&argc, ((void **) &argc)[-1], &((void **) &argc)[-1]);
 }
 #endif
 
 
 void
-__libc_init_first (int argc, ...)
+__libc_init_first (int argc __attribute__ ((unused)), ...)
 {
 #ifndef PIC
   void doinit (int *data)
     {
-      init (data, (&argc)[-1]);
+      init (data, ((void **) &argc)[-1], &((void **) &data)[-1]);
     }
 
   /* Initialize data structures so we can do RPCs.  */