about summary refs log tree commit diff
path: root/elf/dynamic-link.h
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/dynamic-link.h
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/dynamic-link.h')
-rw-r--r--elf/dynamic-link.h31
1 files changed, 21 insertions, 10 deletions
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