about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-load.c9
-rw-r--r--elf/dynamic-link.h91
-rw-r--r--elf/link.h4
-rw-r--r--elf/rtld.c18
4 files changed, 84 insertions, 38 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 81c1d8ba2e..e961cb0784 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -848,6 +848,11 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
 	__mprotect ((caddr_t) (l->l_addr + c->mapend),
 		    loadcmds[nloadcmds - 1].allocend - c->mapend,
 		    0);
+
+	/* Remember which part of the address space this object uses.  */
+	l->l_map_start = c->mapstart + l->l_addr;
+	l->l_map_end = l->l_map_start + maplength;
+
 	goto postmap;
       }
     else
@@ -857,6 +862,10 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
 	ELF_FIXED_ADDRESS (loader, c->mapstart);
       }
 
+    /* Remember which part of the address space this object uses.  */
+    l->l_map_start = c->mapstart + l->l_addr;
+    l->l_map_end = l->l_map_start + maplength;
+
     while (c < &loadcmds[nloadcmds])
       {
 	if (c->mapend > c->mapstart)
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 9d7ae3d3fa..9e2ca03543 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -83,60 +83,75 @@ elf_get_dynamic_info (ElfW(Dyn) *dyn,
 #ifdef ELF_MACHINE_PLTREL_OVERLAP
 #define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, lazy) \
   do {									      \
-    ElfW(Addr) r_addr, r_size, p_addr, p_size;				      \
+    struct { ElfW(Addr) start, size;  int lazy; } ranges[3];		      \
+    int ranges_index;							      \
+									      \
+    ranges[0].lazy = ranges[2].lazy = 0;				      \
+    ranges[1].lazy = 1;							      \
+    ranges[0].size = ranges[1].size = ranges[2].size = 0;		      \
+									      \
     if ((map)->l_info[DT_##RELOC])					      \
       {									      \
-        r_addr = (map)->l_info[DT_##RELOC]->d_un.d_ptr;			      \
-        r_size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;		      \
-        if ((map)->l_info[DT_PLTREL] &&					      \
-            (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)		      \
-	  {								      \
-	    p_addr = (map)->l_info[DT_JMPREL]->d_un.d_ptr;		      \
-	    p_size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;		      \
-	    if (r_addr <= p_addr && r_addr+r_size > p_addr)		      \
-	      {								      \
-		ElfW(Addr) r2_addr, r2_size;				      \
-		r2_addr = p_addr + p_size;				      \
-		if (r2_addr < r_addr + r_size)				      \
-		  {							      \
-		    r2_size = r_addr + r_size - r2_addr;		      \
-		    elf_dynamic_do_##reloc ((map), r2_addr, r2_size, 0);      \
-		  }							      \
-		r_size = p_addr - r_addr;				      \
-	      }								      \
-	  }								      \
-									      \
-	elf_dynamic_do_##reloc ((map), r_addr, r_size, 0);		      \
-	if (p_addr)							      \
-	  elf_dynamic_do_##reloc ((map), p_addr, p_size, (lazy));	      \
+	ranges[0].start = (map)->l_info[DT_##RELOC]->d_un.d_ptr;	      \
+	ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;	      \
       }									      \
-    else if ((map)->l_info[DT_PLTREL] &&				      \
-	     (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)	      \
-      {									      \
-	p_addr = (map)->l_info[DT_JMPREL]->d_un.d_ptr;			      \
-	p_size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;		      \
 									      \
-	elf_dynamic_do_##reloc ((map), p_addr, p_size, (lazy));		      \
+     if ((lazy)								      \
+	&& (map)->l_info[DT_PLTREL]					      \
+	&& (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)		      \
+      {									      \
+	ranges[1].start = (map)->l_info[DT_JMPREL]->d_un.d_ptr;		      \
+	ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;	      \
+	ranges[2].start = ranges[1].start + ranges[1].size;		      \
+	ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start;  \
+	ranges[0].size = ranges[1].start - ranges[0].start;		      \
       }									      \
+									      \
+    for (ranges_index = 0; ranges_index < 3; ++ranges_index)		      \
+      elf_dynamic_do_##reloc ((map),					      \
+			      ranges[ranges_index].start,		      \
+			      ranges[ranges_index].size,		      \
+			      ranges[ranges_index].lazy);		      \
   } while (0)
 #else
 #define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, lazy) \
   do {									      \
+    struct { ElfW(Addr) start, size;  int lazy; } ranges[2];		      \
+    int ranges_index;							      \
+    ranges[0].lazy = 0;							      \
+    ranges[1].lazy = 1;							      \
+    ranges[0].size = ranges[1].size = 0;				      \
+    ranges[0].start = 0;						      \
+									      \
     if ((map)->l_info[DT_##RELOC])					      \
       {									      \
-	ElfW(Addr) r_addr, r_size;					      \
-        r_addr = (map)->l_info[DT_##RELOC]->d_un.d_ptr;			      \
-        r_size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;		      \
-	elf_dynamic_do_##reloc ((map), r_addr, r_size, 0);		      \
+        ranges[0].start = (map)->l_info[DT_##RELOC]->d_un.d_ptr;	      \
+        ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;	      \
       }									      \
     if ((map)->l_info[DT_PLTREL] &&					      \
 	(map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)		      \
       {									      \
-	ElfW(Addr) p_addr, p_size;					      \
-	p_addr = (map)->l_info[DT_JMPREL]->d_un.d_ptr;			      \
-	p_size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;		      \
-	elf_dynamic_do_##reloc ((map), p_addr, p_size, (lazy));		      \
+	ElfW(Addr) start = (map)->l_info[DT_JMPREL]->d_un.d_ptr;	      \
+									      \
+	if (lazy							      \
+	    /* This test does not only detect whether the relocation	      \
+	       sections are in the right order, it also checks whether	      \
+	       there is a DT_REL/DT_RELA section.  */			      \
+	    || ranges[0].start + ranges[0].size != start)		      \
+	  {								      \
+	    ranges[1].start = start;					      \
+	    ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;	      \
+	  }								      \
+	else								      \
+	  /* Combine processing the sections.  */			      \
+	  ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val;	      \
       }									      \
+									      \
+    for (ranges_index = 0; ranges_index < 2; ++ranges_index)		      \
+      elf_dynamic_do_##reloc ((map),					      \
+			      ranges[ranges_index].start,		      \
+			      ranges[ranges_index].size,		      \
+			      ranges[ranges_index].lazy);		      \
   } while (0)
 #endif
 
diff --git a/elf/link.h b/elf/link.h
index 40f7435a84..e31dd2dd65 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -164,6 +164,10 @@ struct link_map
 
     /* String specifying the path where this object was found.  */
     const char *l_origin;
+
+    /* Start and finish of memory map for this object.  l_map_start
+       need not be the same as l_addr.  */
+    ElfW(Addr) l_map_start, l_map_end;
   };
 
 #endif /* link.h */
diff --git a/elf/rtld.c b/elf/rtld.c
index 3ae51e68ab..b25fb20fd3 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -165,6 +165,10 @@ _dl_start (void *arg)
 			    _dl_rtld_map.l_info[DT_RPATH]->d_un.d_val);
     }
 
+/* Don't bother trying to work out how ld.so is mapped in memory.  */
+  _dl_rtld_map.l_map_start = ~0;
+  _dl_rtld_map.l_map_end = ~0;
+
   /* Call the OS-dependent function to set up life so we can do things like
      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
@@ -432,6 +436,11 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 information for the program.  */
     }
 
+  /* It is not safe to load stuff after the main program.  */
+  main_map->l_map_end = ~0;
+  /* Perhaps the executable has no PT_LOAD header entries at all.  */
+  main_map->l_map_start = ~0;
+
   /* Scan the program header table for the dynamic section.  */
   for (ph = phdr; ph < &phdr[phent]; ++ph)
     switch (ph->p_type)
@@ -474,6 +483,15 @@ of this helper program; chances are you did not intend to run this program.\n\
 
 	has_interp = 1;
 	break;
+      case PT_LOAD:
+	/* Remember where the main program starts in memory.  */
+	{
+	  ElfW(Addr) mapstart;
+	  mapstart = main_map->l_addr + (ph->p_vaddr & ~(ph->p_align - 1));
+	  if (main_map->l_map_start > mapstart)
+	    main_map->l_map_start = mapstart;
+	}
+	break;
       }
   if (! _dl_rtld_map.l_libname && _dl_rtld_map.l_name)
     {