about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--elf/do-rel.h29
1 files changed, 25 insertions, 4 deletions
diff --git a/elf/do-rel.h b/elf/do-rel.h
index 7c9afa83ba..b1c60331b6 100644
--- a/elf/do-rel.h
+++ b/elf/do-rel.h
@@ -1,5 +1,5 @@
 /* Do relocations for ELF dynamic linking.
-   Copyright (C) 1995,96,97,98,99,2000 Free Software Foundation, Inc.
+   Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -22,8 +22,11 @@
 
 #ifdef DO_RELA
 # define elf_dynamic_do_rel	elf_dynamic_do_rela
+# define RELCOUNT_IDX		VERSYMIDX (DT_RELACOUNT)
 # define Rel			Rela
 # define elf_machine_rel	elf_machine_rela
+#else
+# define RELCOUNT_IDX		VERSYMIDX (DT_RELCOUNT)
 #endif
 
 #ifndef VERSYMIDX
@@ -42,11 +45,11 @@ elf_dynamic_do_rel (struct link_map *map,
 {
   const ElfW(Rel) *r = (const void *) reladdr;
   const ElfW(Rel) *end = (const void *) (reladdr + relsize);
+  ElfW(Addr) l_addr = map->l_addr;
 
   if (lazy)
     {
       /* Doing lazy PLT relocations; they need very little info.  */
-      ElfW(Addr) l_addr = map->l_addr;
       for (; r < end; ++r)
 	elf_machine_lazy_rel (map, l_addr, r);
     }
@@ -54,6 +57,10 @@ 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) *endrel = end;
+      end -= nrelative;
 
       if (map->l_info[VERSYMIDX (DT_VERSYM)])
 	{
@@ -65,13 +72,27 @@ elf_dynamic_do_rel (struct link_map *map,
 	      ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)];
 	      elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
 			       &map->l_versions[ndx],
-			       (void *) (map->l_addr + r->r_offset));
+			       (void *) (l_addr + r->r_offset));
 	    }
 	}
       else
 	for (; r < end; ++r)
 	  elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
-			   (void *) (map->l_addr + r->r_offset));
+			   (void *) (l_addr + r->r_offset));
+
+#ifndef RTLD_BOOTSTRAP
+      /* This is defined in rtld.c, but nowhere in the static libc.a; make
+	 the reference weak so static programs can still link.  This
+	 declaration cannot be done when compiling rtld.c (i.e. #ifdef
+	 RTLD_BOOTSTRAP) because rtld.c contains the common defn for
+	 _dl_rtld_map, which is incompatible with a weak decl in the same
+	 file.  */
+      weak_extern (_dl_rtld_map);
+      if (map != &_dl_rtld_map) /* Already done in rtld itself.  */
+#endif
+	for (; r < endrel; ++r)
+	  elf_machine_rel_relative (l_addr, r,
+				    (void *) (l_addr + r->r_offset));
     }
 }