about summary refs log tree commit diff
path: root/elf/rtld.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/rtld.c')
-rw-r--r--elf/rtld.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/elf/rtld.c b/elf/rtld.c
index 064cd20dd3..4146c0e9bf 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -129,6 +129,9 @@ static hp_timing_t relocate_time;
 static hp_timing_t load_time;
 extern unsigned long int _dl_num_relocations;	/* in dl-lookup.c */
 
+static ElfW(Addr) _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
+				   hp_timing_t start_time);
+
 #ifdef RTLD_START
 RTLD_START
 #else
@@ -140,7 +143,6 @@ _dl_start (void *arg)
 {
   struct link_map bootstrap_map;
   hp_timing_t start_time;
-  ElfW(Addr) start_addr;
 
   /* This #define produces dynamic linking inline functions for
      bootstrap relocation instead of general-purpose relocation.  */
@@ -175,7 +177,22 @@ _dl_start (void *arg)
   /* Now life is sane; we can call functions and access global data.
      Set up to use the operating system facilities, and find out from
      the operating system's program loader where to find the program
-     header table in core.  */
+     header table in core.  Put the rest of _dl_start into a separate
+     function, that way the compiler cannot put accesses to the GOT
+     before ELF_DYNAMIC_RELOCATE.  */
+  return _dl_start_final (arg, &bootstrap_map, start_time);
+}
+
+
+static ElfW(Addr)
+_dl_start_final (void *arg, struct link_map *bootstrap_map_p,
+		 hp_timing_t start_time)
+{
+  /* The use of `alloca' here looks ridiculous but it helps.  The goal
+     is to avoid the function from being inlined.  There is no official
+     way to do this so we use this trick.  gcc never inlines functions
+     which use `alloca'.  */
+  ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
 
   if (HP_TIMING_AVAIL)
     {
@@ -188,10 +205,10 @@ _dl_start (void *arg)
     }
 
   /* Transfer data about ourselves to the permanent link_map structure.  */
-  _dl_rtld_map.l_addr = bootstrap_map.l_addr;
-  _dl_rtld_map.l_ld = bootstrap_map.l_ld;
+  _dl_rtld_map.l_addr = bootstrap_map_p->l_addr;
+  _dl_rtld_map.l_ld = bootstrap_map_p->l_ld;
   _dl_rtld_map.l_opencount = 1;
-  memcpy (_dl_rtld_map.l_info, bootstrap_map.l_info,
+  memcpy (_dl_rtld_map.l_info, bootstrap_map_p->l_info,
 	  sizeof _dl_rtld_map.l_info);
   _dl_setup_hash (&_dl_rtld_map);
 
@@ -203,7 +220,7 @@ _dl_start (void *arg)
      file access.  It will call `dl_main' (below) to do all the real work
      of the dynamic linker, and then unwind our frame and run the user
      entry point on the same stack we entered on.  */
-  start_addr =  _dl_sysdep_start (arg, &dl_main);
+  *start_addr =  _dl_sysdep_start (arg, &dl_main);
 
   if (HP_TIMING_AVAIL)
     {
@@ -219,7 +236,7 @@ _dl_start (void *arg)
   if (_dl_debug_statistics)
     print_statistics ();
 
-  return start_addr;
+  return *start_addr;
 }
 
 /* Now life is peachy; we can do all normal operations.