about summary refs log tree commit diff
path: root/sysdeps/mach
diff options
context:
space:
mode:
authorThomas Schwinge <thomas@schwinge.name>2012-05-10 13:20:47 -0700
committerRoland McGrath <roland@hack.frob.com>2012-05-10 15:57:23 -0700
commit18bad2ae1bd1797782d51231d24f7b773c2bfff6 (patch)
tree02e995d107df7b992921eb0f9d189e4a074af166 /sysdeps/mach
parent5aa3a74a59916b489e9cf7c4dce9eb149e106c6c (diff)
downloadglibc-18bad2ae1bd1797782d51231d24f7b773c2bfff6.tar.gz
glibc-18bad2ae1bd1797782d51231d24f7b773c2bfff6.tar.xz
glibc-18bad2ae1bd1797782d51231d24f7b773c2bfff6.zip
Hurd: Avoid init-first.c miscompilation.
Diffstat (limited to 'sysdeps/mach')
-rw-r--r--sysdeps/mach/hurd/i386/init-first.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c
index 4785e8dbec..f4bf624680 100644
--- a/sysdeps/mach/hurd/i386/init-first.c
+++ b/sysdeps/mach/hurd/i386/init-first.c
@@ -122,7 +122,7 @@ init1 (int argc, char *arg0, ...)
     {
 #ifndef SHARED
       /* We may need to see our own phdrs, e.g. for TLS setup.
-         Try the usual kludge to find the headers without help from
+	 Try the usual kludge to find the headers without help from
 	 the exec server.  */
       extern const void _start;
       const ElfW(Ehdr) *const ehdr = &_start;
@@ -225,7 +225,7 @@ init (int *data)
 
 #ifdef SHARED
       /* And readjust the dynamic linker's idea of where the argument
-         vector lives.  */
+	 vector lives.  */
       assert (_dl_argv == argv);
       _dl_argv = (void *) (newsp + 1);
 #endif
@@ -244,9 +244,16 @@ init (int *data)
       /* 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.  */
-      *--newsp = data[-1];
-      ((void **) data)[-1] = switch_stacks;
-      /* Force NEWSP into %ecx and &init1 into %eax, which are not restored
+      /* The following expression would typically be written as
+	 ``__builtin_return_address (0)''.  But, for example, GCC 4.4.6 doesn't
+	 recognize that this read operation may alias the following write
+	 operation, and thus is free to reorder the two, clobbering the
+	 original return address.  */
+      *--newsp = *((int *) __builtin_frame_address (0) + 1);
+      /* GCC 4.4.6 also wants us to force loading *NEWSP already here.  */
+      asm volatile ("# %0" : : "X" (*newsp));
+      *((void **) __builtin_frame_address (0) + 1) = &switch_stacks;
+      /* Force NEWSP into %eax and &init1 into %ecx, which are not restored
 	 by function return.  */
       asm volatile ("# a %0 c %1" : : "a" (newsp), "c" (&init1));
     }
@@ -273,8 +280,15 @@ init (int *data)
 
       /* The argument data is just above the stack frame we will unwind by
 	 returning.  Mutate our own return address to run the code below.  */
-      usercode = data[-1];
-      data[-1] = (int) &call_init1;
+      /* The following expression would typically be written as
+	 ``__builtin_return_address (0)''.  But, for example, GCC 4.4.6 doesn't
+	 recognize that this read operation may alias the following write
+	 operation, and thus is free to reorder the two, clobbering the
+	 original return address.  */
+      usercode = *((int *) __builtin_frame_address (0) + 1);
+      /* GCC 4.4.6 also wants us to force loading USERCODE already here.  */
+      asm volatile ("# %0" : : "X" (usercode));
+      *((void **) __builtin_frame_address (0) + 1) = &call_init1;
       /* Force USERCODE into %eax and &init1 into %ecx, which are not
 	 restored by function return.  */
       asm volatile ("# a %0 c %1" : : "a" (usercode), "c" (&init1));
@@ -322,11 +336,12 @@ first_init (void)
    stack set up just as the user will see it, so it can switch stacks.  */
 
 void
-_dl_init_first (void)
+_dl_init_first (int argc, ...)
 {
   first_init ();
 
-  init ((int *) __builtin_frame_address (0) + 2);
+  /* If we use ``__builtin_frame_address (0) + 2'' here, GCC gets confused.  */
+  init (&argc);
 }
 #endif
 
@@ -360,15 +375,17 @@ _hurd_stack_setup (void)
   void doinit (intptr_t *data)
     {
       /* This function gets called with the argument data at TOS.  */
-      void doinit1 (void)
+      void doinit1 (int argc, ...)
 	{
-	  init ((int *) __builtin_frame_address (0) + 2);
+	  /* If we use ``__builtin_frame_address (0) + 2'' here, GCC gets
+	     confused.  */
+	  init ((int *) &argc);
 	}
 
       /* Push the user return address after the argument data, and then
-         jump to `doinit1' (above), so it is as if __libc_init_first's
-         caller had called `doinit1' with the argument data already on the
-         stack.  */
+	 jump to `doinit1' (above), so it is as if __libc_init_first's
+	 caller had called `doinit1' with the argument data already on the
+	 stack.  */
       *--data = caller;
       asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack.  */
 		    "movl $0, %%ebp\n" /* Clear outermost frame pointer.  */