about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-10-16 09:34:51 -0400
committerUlrich Drepper <drepper@gmail.com>2011-10-16 09:34:51 -0400
commite453f6cd0ccdd64a3f5f156e2c5f70085e9289e7 (patch)
tree52ffc06dedd14b973a77112d6847614eb976542f /elf
parent79b195b55af84a9044dfb26ebdc49d9f308829af (diff)
downloadglibc-e453f6cd0ccdd64a3f5f156e2c5f70085e9289e7.tar.gz
glibc-e453f6cd0ccdd64a3f5f156e2c5f70085e9289e7.tar.xz
glibc-e453f6cd0ccdd64a3f5f156e2c5f70085e9289e7.zip
Fix potential problem with skipping relocations
We never seem to have hit this problem but way relative relocations
were skipped was wrong.  There are relative relocations only in the
DT_REL/DT_RELA section.  The elf_dynamic_do_##reloc function skipped
the entries in all calls, though.
Diffstat (limited to 'elf')
-rw-r--r--elf/do-rel.h17
-rw-r--r--elf/dynamic-link.h31
2 files changed, 27 insertions, 21 deletions
diff --git a/elf/do-rel.h b/elf/do-rel.h
index 6187b9ed7a..69f2f0e467 100644
--- a/elf/do-rel.h
+++ b/elf/do-rel.h
@@ -21,13 +21,10 @@
    `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.  */
 
 #ifdef DO_RELA
-# define elf_dynamic_do_rel		elf_dynamic_do_rela
-# define RELCOUNT_IDX			VERSYMIDX (DT_RELACOUNT)
+# define elf_dynamic_do_Rel		elf_dynamic_do_Rela
 # define Rel				Rela
 # define elf_machine_rel		elf_machine_rela
 # define elf_machine_rel_relative	elf_machine_rela_relative
-#else
-# define RELCOUNT_IDX			VERSYMIDX (DT_RELCOUNT)
 #endif
 
 #ifndef DO_ELF_MACHINE_REL_RELATIVE
@@ -50,9 +47,9 @@
    than fully resolved now.  */
 
 auto inline void __attribute__ ((always_inline))
-elf_dynamic_do_rel (struct link_map *map,
+elf_dynamic_do_Rel (struct link_map *map,
 		    ElfW(Addr) reladdr, ElfW(Addr) relsize,
-		    int lazy, int skip_ifunc)
+		    ElfW(Word) nrelative, int lazy, int skip_ifunc)
 {
   const ElfW(Rel) *r = (const void *) reladdr;
   const ElfW(Rel) *end = (const void *) (reladdr + relsize);
@@ -73,10 +70,8 @@ elf_dynamic_do_rel (struct link_map *map,
     {
       const ElfW(Sym) *const symtab =
 	(const void *) D_PTR (map, l_info[DT_SYMTAB]);
-      ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL
-			      ? 0 : map->l_info[RELCOUNT_IDX]->d_un.d_val);
       const ElfW(Rel) *relative = r;
-      r = r + MIN (nrelative, relsize / sizeof (ElfW(Rel)));
+      r += nrelative;
 
 #ifndef RTLD_BOOTSTRAP
       /* This is defined in rtld.c, but nowhere in the static libc.a; make
@@ -131,9 +126,9 @@ elf_dynamic_do_rel (struct link_map *map,
     }
 }
 
-#undef elf_dynamic_do_rel
+#undef elf_dynamic_do_Rel
 #undef Rel
 #undef elf_machine_rel
 #undef elf_machine_rel_relative
 #undef DO_ELF_MACHINE_REL_RELATIVE
-#undef RELCOUNT_IDX
+#undef DO_RELA
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 2bdab45464..486408d3c5 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -258,17 +258,23 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
 # ifdef ELF_MACHINE_PLTREL_OVERLAP
 #  define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
   do {									      \
-    struct { ElfW(Addr) start, size; int lazy; } ranges[3];		      \
+    struct { ElfW(Addr) start, size; ElfW(Word) nrelative; 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;		      \
+    ranges[0].nrelative = ranges[1].nrelative = ranges[2].nrelative = 0;      \
 									      \
     if ((map)->l_info[DT_##RELOC])					      \
       {									      \
 	ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]);		      \
 	ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;	      \
+	if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL)		      \
+	  ranges[0].nrelative						      \
+	    = MIN (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val,    \
+		   ranges[0].size / sizeof (ElfW(reloc)));		      \
       }									      \
 									      \
     if ((do_lazy)							      \
@@ -286,21 +292,24 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
       elf_dynamic_do_##reloc ((map),					      \
 			      ranges[ranges_index].start,		      \
 			      ranges[ranges_index].size,		      \
+			      ranges[ranges_index].nrelative,		      \
 			      ranges[ranges_index].lazy,		      \
 			      skip_ifunc);				      \
   } while (0)
 # else
 #  define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
   do {									      \
-    struct { ElfW(Addr) start, size; int lazy; } ranges[2];		      \
-    ranges[0].lazy = 0;							      \
-    ranges[0].size = ranges[1].size = 0;				      \
-    ranges[0].start = 0;						      \
+    struct { ElfW(Addr) start, size; ElfW(Word) nrelative; int lazy; }	      \
+      ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };			      \
 									      \
     if ((map)->l_info[DT_##RELOC])					      \
       {									      \
 	ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]);		      \
 	ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;	      \
+	if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL)		      \
+	  ranges[0].nrelative						      \
+	    = MIN (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val,    \
+		   ranges[0].size / sizeof (ElfW(reloc)));		      \
       }									      \
     if ((map)->l_info[DT_PLTREL]					      \
 	&& (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
@@ -312,7 +321,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
 		/* 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))		      \
+		|| __builtin_expect (ranges[0].start + ranges[0].size	      \
+				     != start, 0)))			      \
 	  {								      \
 	    ranges[1].start = start;					      \
 	    ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;	      \
@@ -327,8 +337,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
       }									      \
 									      \
     if (ELF_DURING_STARTUP)						      \
-      elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0,      \
-			      skip_ifunc);				      \
+      elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size,	      \
+			      ranges[0].nrelative, 0, skip_ifunc);	      \
     else								      \
       {									      \
 	int ranges_index;						      \
@@ -336,6 +346,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
 	  elf_dynamic_do_##reloc ((map),				      \
 				  ranges[ranges_index].start,		      \
 				  ranges[ranges_index].size,		      \
+				  ranges[ranges_index].nrelative,	      \
 				  ranges[ranges_index].lazy,		      \
 				  skip_ifunc);				      \
       }									      \
@@ -351,7 +362,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
 # if ! ELF_MACHINE_NO_REL
 #  include "do-rel.h"
 #  define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \
-  _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, skip_ifunc, _ELF_CHECK_REL)
+  _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL)
 # else
 #  define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) /* Nothing to do.  */
 # endif
@@ -360,7 +371,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
 #  define DO_RELA
 #  include "do-rel.h"
 #  define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) \
-  _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, skip_ifunc, _ELF_CHECK_REL)
+  _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL)
 # else
 #  define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do.  */
 # endif