This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Updated prelink patch for glibc


Hi!

Here is updated prelink patch against current glibc.
I've removed the portions where it dealt with DT_FILTER/DT_AUXILIARY, since
they have wrong semantics and will be eventually rewritten anyway (still
need to adjust prelink testcase so that it doesn't test it).

2001-12-11  Jakub Jelinek  <jakub@redhat.com>

	* elf/Makefile (dl-routines): Add conflict.
	(rtld-ldscript-in, rtld-ldscript, rtld-parms): Remove.
	(ld.so): Add _begin local symbol.
	* elf/elf.h (DT_VALTAGIDX, DT_VALNUM, DT_ADDRTAGIDX, DT_ADDRNUM):
	Define.
	* elf/dl-deps.c (_dl_build_local_scope): New.
	(_dl_map_object_deps): If LD_TRACE_PRELINKING, compute local scopes
	of all libraries.
	* elf/do-rel.h (VALIDX): Define.
	(elf_dynamic_do_rel): If ELF_MACHINE_PLT_REL is defined, don't do
	lazy binding for RELA.  If DT_GNU_PRELINKED, DT_RELACOUNT relocations
	can be skipped.
	* elf/dl-conflict.c: New file.
	* elf/dl-lookup.c (_dl_debug_bindings): New.
	(_dl_lookup_symbol): Use _dl_debug_bindings.  Reference_name is always
	non-NULL.
	(_dl_lookup_symbol_skip): Likewise.
	(_dl_lookup_versioned_symbol): Likewise.
	(_dl_lookup_versioned_symbol_skip): Likewise.
	* elf/dl-runtime.c (PLTREL): If ELF_MACHINE_PLT_REL is defined,
	define to ElfW(Rel).
	* elf/dynamic-link.h (elf_get_dynamic_info): Record selected dynamic
	tags in the DT_VALRNGLO..DT_VALRNGHI and DT_ADDRRNGLO..DT_ADDRRNGHI
	ranges.
	Don't adjust address dynamic tags if l_addr is 0.
	* elf/rtld.c (_dl_trace_prelink, _dl_trace_prelink_map): New.
	(_dl_start): Skip ELF_DYNAMIC_RELOCATE if ld.so is prelinked.
	(VALIDX, ADDRIDX): Define.
	(_dl_start_final): Initialize _dl_rtld_map's l_map_start and l_map_end.
	(dl_main): Print library list for LD_TRACE_PRELINKING.
	If prelinking information can be used, skip relocating libraries and
	call _dl_resolve_conflicts instead.
	(process_envvars): Handle LD_TRACE_PRELINKING envvar.
	* elf/dl-load.c (_dl_map_object): Don't create fake libs
	if LD_TRACE_PRELINKING.
	* include/link.h (struct link_map) [l_info]: Add DT_VALNUM
	+ DT_ADDRNUM.
	* sysdeps/generic/ldsodefs.h (_dl_trace_prelink_map): New.
	(DL_DEBUG_PRELINK): Define.
	(_dl_resolve_conflicts): Add prototype.

	* sysdeps/alpha/dl-machine.h (elf_machine_runtime_setup): Reinitialize
	.plt for prelinked libraries where prelinking info cannot be used.
	(elf_machine_rela): If relocating R_ALPHA_JMP_SLOT in .gnu.conflict
	section, use RESOLVE_CONFLICT_FIND_MAP to find out reloc's link_map.
	* sysdeps/arm/bits/link.h: New file.
	* sysdeps/arm/dl-machine.h (elf_machine_runtime_setup): Save original
	content of .got[1].
	(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
	(ELF_MACHINE_PLT_REL): Define.
	(elf_machine_rela, elf_machine_rela_relative): New.
	(elf_machine_lazy_rel): Reinitialize R_ARM_JUMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/i386/bits/link.h: New file.
	* sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Save original
	content of .got[1].
	(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
	(ELF_MACHINE_PLT_REL): Define.
	(elf_machine_rela, elf_machine_rela_relative): New.
	(elf_machine_lazy_rel): Reinitialize R_386_JUMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/powerpc/dl-machine.h (elf_machine_rela): If relocating
	conflicts, skip finaladdr computation.  Use RESOLVE_CONFLICT_FIND_MAP
	to find out map for R_PPC_JMP_SLOT relocs.
	* sysdeps/sparc/sparc32/dl-machine.h (VALIDX): Define.
	(OPCODE_BA): Define.
	(elf_machine_runtime_setup): Reinitialize .plt for prelinked
	libraries where prelinking info cannot be used.
	(sparc_fixup_plt): Renamed from elf_machine_fixup_plt.
	(elf_machine_fixup_plt): Call sparc_fixup_plt.
	(elf_machine_rela): Set value to 0 if relocating conflicts.
	Call sparc_fixup_plt for R_SPARC_JMP_SLOT.
	* sysdeps/sparc/sparc64/dl-machine.h (VALIDX): Define.
	(sparc64_fixup_plt): Fix a typo.
	(elf_machine_rela): Set value to 0 if relocating conflicts.
	Handle R_SPARC_JMP_SLOT relocs when relocating conflicts.
	(elf_machine_runtime_setup): Reinitialize .plt for prelinked
	libraries where prelinking info cannot be used.
	* sysdeps/sh/bits/link.h: New file.
	* sysdeps/sh/dl-machine.h (elf_machine_runtime_setup): Save original
	content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_SH_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/s390/s390-32/bits/link.h: New file.
	* sysdeps/s390/s390-32/dl-machine.h (elf_machine_runtime_setup):
	Save original content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/s390/s390-64/bits/link.h: New file.
	* sysdeps/s390/s390-64/dl-machine.h (elf_machine_runtime_setup):
	Save original content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/x86_64/bits/link.h: New file.
	* sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup):
	Save original content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_X86_64_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.

--- libc/elf/Makefile.jj	Wed Nov 21 13:35:08 2001
+++ libc/elf/Makefile	Tue Dec 11 17:10:47 2001
@@ -29,7 +29,7 @@ routines	= $(dl-routines) dl-open dl-clo
 # profiled libraries.
 dl-routines	= $(addprefix dl-,load cache lookup object reloc deps \
 			          runtime error init fini debug misc \
-				  version profile)
+				  version profile conflict)
 all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
 # But they are absent from the shared libc, because that code is in ld.so.
 elide-routines.os = $(all-dl-routines) dl-support enbl-secure \
@@ -154,30 +154,16 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routi
 $(objpfx)librtld.os: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a
 	$(reloc-link) '-Wl,-(' $^ -lgcc '-Wl,-)'
 
-# Do we need a linker script?
-rtld-ldscript-in := $(firstword $(wildcard $(+sysdep_dirs:%=%/rtld-ldscript.in)))
-
-ifneq (,$(rtld-ldscript-in))
-rtld-ldscript = $(objpfx)rtld-ldscript
-generated += rtld-ldscript
-
-LDFLAGS-rtld = -T $(rtld-ldscript)
-before-compile += $(rtld-ldscript)
-
-rtld-parms = $(wildcard $(+sysdep_dirs:%=%/rtld-parms))
-include $(rtld-parms)
-
-$(rtld-ldscript): $(rtld-ldscript-in) $(rtld-parms)
-	sed -e 's#@@rtld-oformat@@#$(rtld-oformat)#' \
-	    -e 's#@@rtld-arch@@#$(rtld-arch)#' \
-	    -e 's#@@rtld-entry@@#$(rtld-entry)#' \
-	    -e 's#@@rtld-base@@#$(rtld-base)#' $< >$@
-endif
-
-$(objpfx)ld.so: $(objpfx)librtld.os $(rtld-ldscript) $(ld-map)
-	$(LINK.o) -nostdlib -nostartfiles -shared -o $@ $(LDFLAGS-rtld) \
-		  $(filter-out $(rtld-ldscript) $(map-file),$^)		\
-		  $(load-map-file) -Wl,-soname=$(rtld-installed-name)
+$(objpfx)ld.so: $(objpfx)librtld.os $(ld-map)
+	$(LINK.o) -nostdlib -nostartfiles -shared			\
+		  $(LDFLAGS-rtld) -Wl,--verbose 2>&1 |			\
+		  sed -e '/^=========/,/^=========/!d;/^=========/d'	\
+		      -e 's/\. = 0 + SIZEOF_HEADERS;/& _begin = . - SIZEOF_HEADERS;/' \
+		  > $@.lds;						\
+	$(LINK.o) -nostdlib -nostartfiles -shared -o $@ $(LDFLAGS-rtld)	\
+		  $(filter-out $(map-file),$^) $(load-map-file)		\
+		  -Wl,-soname=$(rtld-installed-name) -T $@.lds;		\
+	rm -f $@.lds
 
 # interp.c exists just to get this string into the libraries.
 CFLAGS-interp.c = -D'RUNTIME_LINKER="$(slibdir)/$(rtld-installed-name)"'
--- libc/elf/elf.h.jj	Wed Nov 21 13:32:18 2001
+++ libc/elf/elf.h	Mon Dec 10 19:24:18 2001
@@ -676,6 +676,8 @@ typedef struct
 #define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
 #define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
 #define DT_VALRNGHI	0x6ffffdff
+#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
+#define DT_VALNUM 12
 
 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
    Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
@@ -692,6 +694,8 @@ typedef struct
 #define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
 #define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
 #define DT_ADDRRNGHI	0x6ffffeff
+#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
+#define DT_ADDRNUM 10
 
 /* The versioning entry types.  The next are defined as part of the
    GNU extension.  */
--- libc/elf/dl-deps.c.jj	Thu Sep 27 23:26:27 2001
+++ libc/elf/dl-deps.c	Tue Dec 11 17:22:10 2001
@@ -21,6 +21,7 @@
 #include <dlfcn.h>
 #include <errno.h>
 #include <libintl.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -70,6 +71,21 @@ openaux (void *a)
 			      args->trace_mode, 0);
 }
 
+static ptrdiff_t
+internal_function
+_dl_build_local_scope (struct link_map **list, struct link_map *map)
+{
+  struct link_map **p = list;
+  struct link_map **q;
+
+  *p++ = map;
+  map->l_reserved = 1;
+  if (map->l_initfini)
+    for (q = map->l_initfini + 1; *q; ++q)
+      if (! (*q)->l_reserved)
+	p += _dl_build_local_scope (p, *q);
+  return p - list;
+}
 
 
 /* We use a very special kind of list to track the path
@@ -491,6 +507,50 @@ _dl_map_object_deps (struct link_map *ma
       runp->map->l_reserved = 0;
     }
 
+  if (__builtin_expect(_dl_debug_mask & DL_DEBUG_PRELINK, 0) != 0
+      && map == _dl_loaded)
+    {
+      /* If we are to compute conflicts, we have to build local scope
+	 for each library, not just the ultimate loader.  */
+      for (i = 0; i < nlist; ++i)
+	{
+	  struct link_map *l = map->l_searchlist.r_list[i];
+	  unsigned int j, cnt;
+
+	  /* The local scope has been already computed.  */
+	  if (l == map
+	      || (l->l_local_scope[0]
+		  && l->l_local_scope[0]->r_nlist) != 0)
+	    continue;
+
+	  if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
+	    {
+	      /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
+		 rewritten, no need to bother with prelinking the old
+		 implementation.  */
+	      _dl_signal_error (EINVAL, l->l_name,
+				N_("Filters not supported with LD_TRACE_PRELINKING"));
+	    }
+
+	  cnt = _dl_build_local_scope (map->l_initfini, l);
+	  assert (cnt <= nlist);
+	  for (j = 0; j < cnt; j++)
+	    map->l_initfini[j]->l_reserved = 0;
+
+	  l->l_local_scope[0] =
+	    (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
+					    + cnt * sizeof (struct link_map *));
+	  if (l->l_local_scope[0] == NULL)
+	    _dl_signal_error (ENOMEM, map->l_name, NULL,
+			      N_("cannot allocate symbol search list"));
+	  l->l_local_scope[0]->r_nlist = cnt;
+	  l->l_local_scope[0]->r_list =
+	    (struct link_map **) (l->l_local_scope[0] + 1);
+	  memcpy (l->l_local_scope[0]->r_list, map->l_initfini,
+		  cnt * sizeof (struct link_map *));
+	}
+    }
+
   /* Maybe we can remove some relocation dependencies now.  */
   assert (map->l_searchlist.r_list[0] == map);
   for (i = 0; i < map->l_reldepsact; ++i)
--- libc/elf/do-rel.h.jj	Thu Sep 27 23:26:28 2001
+++ libc/elf/do-rel.h	Mon Dec 10 19:24:18 2001
@@ -33,6 +33,10 @@
 #ifndef VERSYMIDX
 # define VERSYMIDX(sym)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
 #endif
+#ifndef VALIDX
+# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+		      + DT_EXTRANUM + DT_VALTAGIDX (tag))
+#endif
 
 /* Perform the relocations in MAP on the running program image as specified
    by RELTAG, SZTAG.  If LAZY is nonzero, this is the first pass on PLT
@@ -48,7 +52,7 @@ elf_dynamic_do_rel (struct link_map *map
   const ElfW(Rel) *end = (const void *) (reladdr + relsize);
   ElfW(Addr) l_addr = map->l_addr;
 
-#ifndef RTLD_BOOTSTRAP
+#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP
   /* We never bind lazily during ld.so bootstrap.  Unfortunately gcc is
      not clever enough to see through all the function calls to realize
      that.  */
@@ -81,8 +85,11 @@ elf_dynamic_do_rel (struct link_map *map
 	/* Rela platforms get the offset from r_addend and this must
 	   be copied in the relocation address.  Therefore we can skip
 	   the relative relocations only if this is for rel
-	   relocations.  */
+	   relocations...  */
 	if (l_addr != 0)
+# else
+	/* ...or we know the object has been prelinked.  */
+	if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)])
 # endif
 #endif
 	  for (; relative < r; ++relative)
--- libc/elf/dl-conflict.c.jj	Mon Dec 10 19:24:18 2001
+++ libc/elf/dl-conflict.c	Mon Dec 10 19:24:18 2001
@@ -0,0 +1,66 @@
+/* Resolve conflicts against already prelinked libraries.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include "dynamic-link.h"
+
+extern unsigned long int _dl_num_cache_relocations;	/* in dl-lookup.c */
+
+void
+_dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
+		       ElfW(Rela) *conflictend)
+{
+  if (__builtin_expect (_dl_debug_mask & DL_DEBUG_RELOC, 0))
+    _dl_printf ("\nconflict processing: %s\n",
+		l->l_name[0] ? l->l_name : _dl_argv[0]);
+
+  {
+    /* Do the conflict relocation of the object and library GOT and other
+       data.  */
+
+    /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */
+#define RESOLVE_MAP(ref, version, flags) (*ref = NULL, 0)
+#define RESOLVE(ref, version, flags) (*ref = NULL, 0)
+#define RESOLVE_CONFLICT_FIND_MAP(map, r_offset)		\
+do								\
+  {								\
+    while (resolve_conflict_map->l_map_end < (r_offset)		\
+	   || resolve_conflict_map->l_map_start > (r_offset))	\
+      resolve_conflict_map					\
+	= resolve_conflict_map->l_next;				\
+    (map) = resolve_conflict_map;				\
+  } while (0)
+
+    struct link_map *resolve_conflict_map = _dl_loaded;
+
+#include "dynamic-link.h"
+
+    _dl_num_cache_relocations += conflictend - conflict;
+
+    for (; conflict < conflictend; ++conflict)
+      elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset);
+  }
+}
--- libc/elf/dl-lookup.c.jj	Wed Nov 21 13:35:08 2001
+++ libc/elf/dl-lookup.c	Mon Dec 10 19:24:18 2001
@@ -194,6 +194,12 @@ _dl_do_lookup_versioned (const char *und
 			 const struct r_found_version *const version,
 			 struct link_map *skip, int type_class);
 
+static void
+internal_function
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+		    const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
+		    struct sym_val *value, const struct r_found_version *version,
+		    int type_class, int protected);
 
 /* Search loaded objects' symbol tables for a definition of the symbol
    UNDEF_NAME.  */
@@ -204,7 +210,7 @@ _dl_lookup_symbol (const char *undef_nam
 		   const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
 		   int type_class, int explicit)
 {
-  unsigned long int hash = _dl_elf_hash (undef_name);
+  const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
   int protected;
@@ -241,7 +247,7 @@ _dl_lookup_symbol (const char *undef_nam
       if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
 	/* We could find no value for a strong reference.  */
 	/* XXX We cannot translate the messages.  */
-	_dl_signal_cerror (0, (reference_name && reference_name[0]
+	_dl_signal_cerror (0, (reference_name[0]
 			       ? reference_name
 			       : (_dl_argv[0] ?: "<main program>")),
 			   N_("relocation error"),
@@ -251,25 +257,7 @@ _dl_lookup_symbol (const char *undef_nam
     }
 
   protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
-
-  if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
-    {
-      const char *reference_name = undef_map ? undef_map->l_name : NULL;
-
-      _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n",
-			(reference_name && reference_name[0]
-			 ? reference_name : (_dl_argv[0] ?: "<main program>")),
-			current_value.m->l_name[0]
-			? current_value.m->l_name : _dl_argv[0],
-			protected ? "protected" : "normal", undef_name);
-    }
-
-  if (__builtin_expect (protected == 0, 1))
-    {
-      *ref = current_value.s;
-      return LOOKUP_VALUE (current_value.m);
-    }
-  else
+  if (__builtin_expect (protected != 0, 0))
     {
       /* It is very tricky. We need to figure out what value to
          return for the protected symbol */
@@ -280,14 +268,20 @@ _dl_lookup_symbol (const char *undef_nam
 			   0, NULL, ELF_RTYPE_CLASS_PLT))
 	  break;
 
-      if (protected_value.s == NULL || protected_value.m == undef_map)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
 	{
-	  *ref = current_value.s;
-	  return LOOKUP_VALUE (current_value.m);
+	  current_value.s = *ref;
+	  current_value.m = undef_map;
 	}
-
-      return LOOKUP_VALUE (undef_map);
     }
+
+  if (__builtin_expect (_dl_debug_mask
+			& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
+    _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
+			&current_value, NULL, type_class, protected);
+
+  *ref = current_value.s;
+  return LOOKUP_VALUE (current_value.m);
 }
 
 
@@ -303,7 +297,6 @@ _dl_lookup_symbol_skip (const char *unde
 			struct r_scope_elem *symbol_scope[],
 			struct link_map *skip_map)
 {
-  const char *reference_name = undef_map ? undef_map->l_name : NULL;
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
@@ -332,20 +325,7 @@ _dl_lookup_symbol_skip (const char *unde
 
   protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
 
-  if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
-    _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n",
-		       (reference_name && reference_name[0]
-			? reference_name : (_dl_argv[0] ?: "<main program>")),
-		       current_value.m->l_name[0]
-		       ? current_value.m->l_name : _dl_argv[0],
-		       protected ? "protected" : "normal", undef_name);
-
-  if (__builtin_expect (protected == 0, 1))
-    {
-      *ref = current_value.s;
-      return LOOKUP_VALUE (current_value.m);
-    }
-  else
+  if (__builtin_expect (protected != 0, 0))
     {
       /* It is very tricky.  We need to figure out what value to
          return for the protected symbol.  */
@@ -359,14 +339,20 @@ _dl_lookup_symbol_skip (const char *unde
 			     0, skip_map, ELF_RTYPE_CLASS_PLT))
 	    break;
 
-      if (protected_value.s == NULL || protected_value.m == undef_map)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
 	{
-	  *ref = current_value.s;
-	  return LOOKUP_VALUE (current_value.m);
+	  current_value.s = *ref;
+	  current_value.m = undef_map;
 	}
-
-      return LOOKUP_VALUE (undef_map);
     }
+
+  if (__builtin_expect (_dl_debug_mask
+			& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
+    _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
+			&current_value, NULL, 0, protected);
+
+  *ref = current_value.s;
+  return LOOKUP_VALUE (current_value.m);
 }
 
 
@@ -383,7 +369,7 @@ _dl_lookup_versioned_symbol (const char 
 			     const struct r_found_version *version,
 			     int type_class, int explicit)
 {
-  unsigned long int hash = _dl_elf_hash (undef_name);
+  const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
   int protected;
@@ -423,7 +409,7 @@ _dl_lookup_versioned_symbol (const char 
 	  const char *reference_name = undef_map ? undef_map->l_name : NULL;
 
 	  /* XXX We cannot translate the message.  */
-	  _dl_signal_cerror (0, (reference_name && reference_name[0]
+	  _dl_signal_cerror (0, (reference_name[0]
 				 ? reference_name
 				 : (_dl_argv[0] ?: "<main program>")),
 			     N_("relocation error"),
@@ -447,7 +433,7 @@ _dl_lookup_versioned_symbol (const char 
 	  const char *reference_name = undef_map ? undef_map->l_name : NULL;
 
 	  /* XXX We cannot translate the message.  */
-	  _dl_signal_cerror (0, (reference_name && reference_name[0]
+	  _dl_signal_cerror (0, (reference_name[0]
 				 ? reference_name
 				 : (_dl_argv[0] ?: "<main program>")), NULL,
 			     make_string (undefined_msg, undef_name,
@@ -460,25 +446,7 @@ _dl_lookup_versioned_symbol (const char 
 
   protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
 
-  if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
-    {
-      const char *reference_name = undef_map ? undef_map->l_name : NULL;
-
-      _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n",
-			(reference_name && reference_name[0]
-			 ? reference_name : (_dl_argv[0] ?: "<main program>")),
-			current_value.m->l_name[0]
-			? current_value.m->l_name : _dl_argv[0],
-			protected ? "protected" : "normal",
-			undef_name, version->name);
-    }
-
-  if (__builtin_expect (protected == 0, 1))
-    {
-      *ref = current_value.s;
-      return LOOKUP_VALUE (current_value.m);
-    }
-  else
+  if (__builtin_expect (protected != 0, 0))
     {
       /* It is very tricky. We need to figure out what value to
          return for the protected symbol */
@@ -490,14 +458,20 @@ _dl_lookup_versioned_symbol (const char 
 				     ELF_RTYPE_CLASS_PLT))
 	  break;
 
-      if (protected_value.s == NULL || protected_value.m == undef_map)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
 	{
-	  *ref = current_value.s;
-	  return LOOKUP_VALUE (current_value.m);
+	  current_value.s = *ref;
+	  current_value.m = undef_map;
 	}
-
-      return LOOKUP_VALUE (undef_map);
     }
+
+  if (__builtin_expect (_dl_debug_mask
+			& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
+    _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
+			&current_value, version, type_class, protected);
+
+  *ref = current_value.s;
+  return LOOKUP_VALUE (current_value.m);
 }
 
 
@@ -512,7 +486,7 @@ _dl_lookup_versioned_symbol_skip (const 
 				  const struct r_found_version *version,
 				  struct link_map *skip_map)
 {
-  const char *reference_name = undef_map ? undef_map->l_name : NULL;
+  const char *reference_name = undef_map->l_name;
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
@@ -543,7 +517,7 @@ _dl_lookup_versioned_symbol_skip (const 
 	  __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
 		     undef_name, len + 1);
 	  /* XXX We cannot translate the messages.  */
-	  _dl_signal_cerror (0, (reference_name && reference_name[0]
+	  _dl_signal_cerror (0, (reference_name[0]
 				 ? reference_name
 				 : (_dl_argv[0] ?: "<main program>")),
 			     NULL, buf);
@@ -554,21 +528,7 @@ _dl_lookup_versioned_symbol_skip (const 
 
   protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
 
-  if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
-    _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n",
-		      (reference_name && reference_name[0]
-		       ? reference_name : (_dl_argv[0] ?: "<main program>")),
-		      current_value.m->l_name[0]
-		      ? current_value.m->l_name : _dl_argv[0],
-		      protected ? "protected" : "normal",
-		      undef_name, version->name);
-
-  if (__builtin_expect (protected == 0, 1))
-    {
-      *ref = current_value.s;
-      return LOOKUP_VALUE (current_value.m);
-    }
-  else
+  if (__builtin_expect (protected != 0, 0))
     {
       /* It is very tricky. We need to figure out what value to
          return for the protected symbol */
@@ -584,14 +544,20 @@ _dl_lookup_versioned_symbol_skip (const 
 				       skip_map, ELF_RTYPE_CLASS_PLT))
 	    break;
 
-      if (protected_value.s == NULL || protected_value.m == undef_map)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
 	{
-	  *ref = current_value.s;
-	  return LOOKUP_VALUE (current_value.m);
+	  current_value.s = *ref;
+	  current_value.m = undef_map;
 	}
-
-      return LOOKUP_VALUE (undef_map);
     }
+
+  if (__builtin_expect (_dl_debug_mask
+			& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
+    _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
+			&current_value, version, 0, protected);
+
+  *ref = current_value.s;
+  return LOOKUP_VALUE (current_value.m);
 }
 
 
@@ -615,6 +581,79 @@ _dl_setup_hash (struct link_map *map)
   map->l_chain = hash;
 }
 
+static void
+internal_function
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+		    const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
+		    struct sym_val *value, const struct r_found_version *version,
+		    int type_class, int protected)
+{
+  const char *reference_name = undef_map->l_name;
+
+  if (_dl_debug_mask & DL_DEBUG_BINDINGS)
+    {
+      _dl_debug_printf ("binding file %s to %s: %s symbol `%s'",
+			(reference_name[0]
+			 ? reference_name : (_dl_argv[0] ?: "<main program>")),
+			value->m->l_name[0] ? value->m->l_name : _dl_argv[0],
+			protected ? "protected" : "normal",
+			undef_name);
+      if (version)
+	_dl_debug_printf_c (" [%s]\n", version->name);
+      else
+	_dl_debug_printf_c ("\n");
+    }
+#ifdef SHARED
+  if (_dl_debug_mask & DL_DEBUG_PRELINK)
+    {
+      int conflict = 0;
+      struct sym_val val = { NULL, NULL };
+
+      if ((_dl_trace_prelink_map == NULL
+	   || _dl_trace_prelink_map == _dl_loaded)
+	  && undef_map != _dl_loaded)
+	{
+	  const unsigned long int hash = _dl_elf_hash (undef_name);
+
+	  if (version == 0)
+	    _dl_do_lookup (undef_name, hash, *ref, &val,
+			   undef_map->l_local_scope[0], 0, NULL, type_class);
+	  else
+	    _dl_do_lookup_versioned (undef_name, hash, *ref, &val,
+				     undef_map->l_local_scope[0], 0, version,
+				     NULL, type_class);
+
+	  if (val.s != value->s || val.m != value->m)
+	    conflict = 1;
+	}
+
+      if (conflict
+	  || _dl_trace_prelink_map == undef_map
+	  || _dl_trace_prelink_map == NULL)
+	{
+	  _dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ",
+		      conflict ? "conflict" : "lookup",
+		      (int) sizeof (ElfW(Addr)) * 2, undef_map->l_map_start,
+		      (int) sizeof (ElfW(Addr)) * 2,
+		      ((ElfW(Addr)) *ref) - undef_map->l_map_start,
+		      (int) sizeof (ElfW(Addr)) * 2,
+		      (ElfW(Addr)) (value->s ? value->m->l_map_start : 0),
+		      (int) sizeof (ElfW(Addr)) * 2,
+		      (ElfW(Addr)) (value->s ? value->s->st_value : 0));
+
+	  if (conflict)
+	    _dl_printf ("x 0x%0*Zx 0x%0*Zx ",
+			(int) sizeof (ElfW(Addr)) * 2,
+			(ElfW(Addr)) (val.s ? val.m->l_map_start : 0),
+			(int) sizeof (ElfW(Addr)) * 2,
+			(ElfW(Addr)) (val.s ? val.s->st_value : 0));
+
+	  _dl_printf ("/%x %s\n", type_class, undef_name);
+	}
+    }
+#endif
+}
+
 /* These are here so that we only inline do_lookup{,_versioned} in the common
    case, not everywhere.  */
 static int
--- libc/elf/dl-runtime.c.jj	Wed Nov 21 13:35:08 2001
+++ libc/elf/dl-runtime.c	Mon Dec 10 19:24:18 2001
@@ -23,7 +23,8 @@
 #include <ldsodefs.h>
 #include "dynamic-link.h"
 
-#if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
+#if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
+    || ELF_MACHINE_NO_REL
 # define PLTREL  ElfW(Rela)
 #else
 # define PLTREL  ElfW(Rel)
--- libc/elf/dynamic-link.h.jj	Thu Sep 27 23:26:28 2001
+++ libc/elf/dynamic-link.h	Mon Dec 10 19:24:18 2001
@@ -1,5 +1,5 @@
 /* Inline functions for 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
@@ -58,31 +58,39 @@ elf_get_dynamic_info (struct link_map *l
       else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
 	info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
 	     + DT_VERSIONTAGNUM] = dyn;
+      else if ((Elf32_Word) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
+	info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+	     + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
+      else if ((Elf32_Word) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
+	info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+	     + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
       else
 	assert (! "bad dynamic tag");
       ++dyn;
     }
 #ifndef DL_RO_DYN_SECTION
-  if (info[DT_PLTGOT] != NULL)
-    info[DT_PLTGOT]->d_un.d_ptr += l_addr;
-  if (info[DT_STRTAB] != NULL)
-    info[DT_STRTAB]->d_un.d_ptr += l_addr;
-  if (info[DT_SYMTAB] != NULL)
-    info[DT_SYMTAB]->d_un.d_ptr += l_addr;
-# if ! ELF_MACHINE_NO_RELA
-  if (info[DT_RELA] != NULL)
+  /* Don't adjust .dynamic unnecessarily.  */
+  if (l_addr)
     {
-      assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
-      info[DT_RELA]->d_un.d_ptr += l_addr;
-    }
+      if (info[DT_PLTGOT] != NULL)
+	info[DT_PLTGOT]->d_un.d_ptr += l_addr;
+      if (info[DT_STRTAB] != NULL)
+	info[DT_STRTAB]->d_un.d_ptr += l_addr;
+      if (info[DT_SYMTAB] != NULL)
+	info[DT_SYMTAB]->d_un.d_ptr += l_addr;
+# if ! ELF_MACHINE_NO_RELA
+      if (info[DT_RELA] != NULL)
+	info[DT_RELA]->d_un.d_ptr += l_addr;
 # endif
 # if ! ELF_MACHINE_NO_REL
-  if (info[DT_REL] != NULL)
-    {
-      assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
-      info[DT_REL]->d_un.d_ptr += l_addr;
-    }
+      if (info[DT_REL] != NULL)
+	info[DT_REL]->d_un.d_ptr += l_addr;
 # endif
+      if (info[DT_JMPREL] != NULL)
+	info[DT_JMPREL]->d_un.d_ptr += l_addr;
+      if (info[VERSYMIDX (DT_VERSYM)] != NULL)
+	info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
+    }
 #endif
   if (info[DT_PLTREL] != NULL)
     {
@@ -95,12 +103,14 @@ elf_get_dynamic_info (struct link_map *l
 	      || info[DT_PLTREL]->d_un.d_val == DT_RELA);
 # endif
     }
-#ifndef DL_RO_DYN_SECTION
-  if (info[DT_JMPREL] != NULL)
-    info[DT_JMPREL]->d_un.d_ptr += l_addr;
-  if (info[VERSYMIDX (DT_VERSYM)] != NULL)
-    info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
-#endif
+# if ! ELF_MACHINE_NO_RELA
+  if (info[DT_RELA] != NULL)
+    assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
+# endif
+# if ! ELF_MACHINE_NO_REL
+  if (info[DT_REL] != NULL)
+    assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
+# endif
   if (info[DT_FLAGS] != NULL)
     {
       /* Flags are used.  Translate to the old form where available.
@@ -177,8 +187,8 @@ elf_get_dynamic_info (struct link_map *l
 									      \
     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;	      \
+	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[DT_PLTREL]					      \
 	&& (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
--- libc/elf/rtld.c.jj	Wed Nov 21 13:35:25 2001
+++ libc/elf/rtld.c	Mon Dec 10 19:26:28 2001
@@ -67,6 +67,8 @@ struct r_search_path *_dl_search_paths;
 const char *_dl_profile;
 const char *_dl_profile_output;
 struct link_map *_dl_profile_map;
+const char *_dl_trace_prelink;
+struct link_map *_dl_trace_prelink_map;
 int _dl_lazy = 1;
 /* XXX I know about at least one case where we depend on the old weak
    behavior (it has to do with librt).  Until we get DSO groups implemented
@@ -183,10 +185,14 @@ _dl_start (void *arg)
   ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
 #endif
 
-  /* Relocate ourselves so we can do normal function calls and
-     data access using the global offset table.  */
+  if (bootstrap_map.l_addr || ! bootstrap_map.l_info[VALIDX(DT_GNU_PRELINKED)])
+    {
+      /* Relocate ourselves so we can do normal function calls and
+	 data access using the global offset table.  */
+
+      ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
+    }
 
-  ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
   /* Please note that we don't allow profiling of this object and
      therefore need not test whether we have to allocate the array
      for the relocation results (as done in dl-reloc.c).  */
@@ -209,6 +215,15 @@ _dl_start (void *arg)
 }
 
 
+#ifndef VALIDX
+# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+		      + DT_EXTRANUM + DT_VALTAGIDX (tag))
+#endif
+#ifndef ADDRIDX
+# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+		       + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
+#endif
+
 static ElfW(Addr)
 _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
 		 hp_timing_t start_time)
@@ -218,6 +233,7 @@ _dl_start_final (void *arg, struct link_
      way to do this so we use this trick.  gcc never inlines functions
      which use `alloca'.  */
   ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
+  extern char _begin[], _end[];
 
   if (HP_TIMING_AVAIL)
     {
@@ -237,10 +253,8 @@ _dl_start_final (void *arg, struct link_
 	  sizeof _dl_rtld_map.l_info);
   _dl_setup_hash (&_dl_rtld_map);
   _dl_rtld_map.l_mach = bootstrap_map_p->l_mach;
-
-/* 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;
+  _dl_rtld_map.l_map_start = (ElfW(Addr)) _begin;
+  _dl_rtld_map.l_map_end = (ElfW(Addr)) _end;
 
   /* 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
@@ -383,6 +397,7 @@ dl_main (const ElfW(Phdr) *phdr,
   char *file;
   int has_interp = 0;
   unsigned int i;
+  int prelinked = 0;
   int rtld_is_main = 0;
 #ifndef HP_TIMING_NONAVAIL
   hp_timing_t start;
@@ -885,13 +900,42 @@ of this helper program; chances are you 
 	{
 	  struct link_map *l;
 
-	  for (l = _dl_loaded->l_next; l; l = l->l_next)
-	    if (l->l_faked)
-	      /* The library was not found.  */
-	      _dl_printf ("\t%s => not found\n", l->l_libname->name);
-	    else
-	      _dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name,
-			  l->l_name, (int) sizeof l->l_addr * 2, l->l_addr);
+	  if (_dl_debug_mask & DL_DEBUG_PRELINK)
+	    {
+	      struct r_scope_elem *scope = &_dl_loaded->l_searchlist;
+
+	      for (i = 0; i < scope->r_nlist; i++)
+		{
+		  l = scope->r_list [i];
+		  if (l->l_faked)
+		    {
+		      _dl_printf ("\t%s => not found\n", l->l_libname->name);
+		      continue;
+		    }
+		  if (_dl_name_match_p (_dl_trace_prelink, l))
+		    _dl_trace_prelink_map = l;
+		  _dl_printf ("\t%s => %s (0x%0*Zx, 0x%0*Zx)\n",
+			      l->l_libname->name[0] ? l->l_libname->name
+			      : _dl_argv[0] ?: "<main program>",
+			      l->l_name[0] ? l->l_name
+			      : _dl_argv[0] ?: "<main program>",
+			      (int) sizeof l->l_map_start * 2,
+			      l->l_map_start,
+			      (int) sizeof l->l_addr * 2,
+			      l->l_addr);
+		}
+	    }
+	  else
+	    {
+	      for (l = _dl_loaded->l_next; l; l = l->l_next)
+		if (l->l_faked)
+		  /* The library was not found.  */
+		  _dl_printf ("\t%s => not found\n", l->l_libname->name);
+		else
+		  _dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name,
+			      l->l_name, (int) sizeof l->l_map_start * 2,
+			      l->l_map_start);
+	    }
 	}
 
       if (__builtin_expect (mode, trace) != trace)
@@ -936,6 +980,10 @@ of this helper program; chances are you 
 		    }
 		  l = l->l_prev;
 		} while (l);
+
+	      if ((_dl_debug_mask & DL_DEBUG_PRELINK)
+		  && _dl_rtld_map.l_opencount > 1)
+		_dl_relocate_object (&_dl_rtld_map, _dl_loaded->l_scope, 0, 0);
 	    }
 
 #define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED))
@@ -1014,6 +1062,84 @@ of this helper program; chances are you 
       _exit (0);
     }
 
+  if (_dl_loaded->l_info [ADDRIDX (DT_GNU_LIBLIST)]
+      && ! __builtin_expect (_dl_profile != NULL, 0))
+    {
+      ElfW(Lib) *liblist, *liblistend;
+      struct link_map **r_list, **r_listend, *l;
+      const char *strtab = (const void *)
+			   D_PTR (_dl_loaded, l_info[DT_STRTAB]);
+
+      assert (_dl_loaded->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
+      liblist = (ElfW(Lib) *)
+		_dl_loaded->l_info [ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
+      liblistend = (ElfW(Lib) *)
+		   ((char *) liblist
+		    + _dl_loaded->l_info [VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val);
+      r_list = _dl_loaded->l_searchlist.r_list;
+      r_listend = r_list + _dl_loaded->l_searchlist.r_nlist;
+
+      for (; r_list < r_listend && liblist < liblistend; r_list++)
+	{
+	  l = *r_list;
+
+	  if (l == _dl_loaded)
+	    continue;
+
+	  /* If the library is not mapped where it should, fail.  */
+	  if (l->l_addr)
+	    break;
+
+	  /* Next, check if checksum matches.  */
+	  if (l->l_info [VALIDX(DT_CHECKSUM)] == NULL
+	      || l->l_info [VALIDX(DT_CHECKSUM)]->d_un.d_val
+		 != liblist->l_checksum)
+	    break;
+
+	  if (l->l_info [VALIDX(DT_GNU_PRELINKED)] == NULL
+	      || l->l_info [VALIDX(DT_GNU_PRELINKED)]->d_un.d_val
+		 != liblist->l_time_stamp)
+	    break;
+
+	  if (! _dl_name_match_p (strtab + liblist->l_name, l))
+	    break;
+
+	  ++liblist;
+	}
+
+
+      if (r_list == r_listend && liblist == liblistend)
+	prelinked = 1;
+
+      if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0))
+	_dl_printf ("\nprelink checking: %s\n", prelinked ? "ok" : "failed");
+    }
+
+  if (prelinked)
+    {
+      if (_dl_loaded->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
+	{
+	  ElfW(Rela) *conflict, *conflictend;
+#ifndef HP_TIMING_NONAVAIL
+	  hp_timing_t start;
+	  hp_timing_t stop;
+#endif
+
+	  HP_TIMING_NOW (start);
+	  assert (_dl_loaded->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
+	  conflict = (ElfW(Rela) *)
+		     _dl_loaded->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
+	  conflictend = (ElfW(Rela) *)
+			((char *) conflict
+			 + _dl_loaded->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
+	  _dl_resolve_conflicts (_dl_loaded, conflict, conflictend);
+	  HP_TIMING_NOW (stop);
+	  HP_TIMING_DIFF (relocate_time, start, stop);
+	}
+
+      _dl_sysdep_start_cleanup ();
+    }
+  else
   {
     /* Now we have all the objects loaded.  Relocate them all except for
        the dynamic linker itself.  We do this in reverse order so that copy
@@ -1094,7 +1220,7 @@ of this helper program; chances are you 
   _dl_main_searchlist = &_dl_loaded->l_searchlist;
   _dl_global_scope[0] = &_dl_loaded->l_searchlist;
 
-  /* Safe the information about the original global scope list since
+  /* Save the information about the original global scope list since
      we need it in the memory handling later.  */
   _dl_initial_searchlist = *_dl_main_searchlist;
 
@@ -1371,6 +1497,17 @@ process_envvars (enum mode *modep)
 	    _dl_profile_output = &envline[15];
 	  break;
 
+	case 16:
+	  /* The mode of the dynamic linker can be set.  */
+	  if (memcmp (envline, "TRACE_PRELINKING", 16) == 0)
+	    {
+	      mode = trace;
+	      _dl_verbose = 1;
+	      _dl_debug_mask |= DL_DEBUG_PRELINK;
+	      _dl_trace_prelink = &envline[17];
+	    }
+	  break;
+
 	case 20:
 	  /* The mode of the dynamic linker can be set.  */
 	  if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0)
--- libc/elf/dl-load.c.jj	Wed Nov 21 13:35:08 2001
+++ libc/elf/dl-load.c	Mon Dec 10 19:24:18 2001
@@ -1782,7 +1782,8 @@ _dl_map_object (struct link_map *loader,
 
   if (__builtin_expect (fd, 0) == -1)
     {
-      if (trace_mode)
+      if (trace_mode
+	  && __builtin_expect (_dl_debug_mask & DL_DEBUG_PRELINK, 0) == 0)
 	{
 	  /* We haven't found an appropriate library.  But since we
 	     are only interested in the list of libraries this isn't
--- libc/include/link.h.jj	Thu Sep 27 23:26:30 2001
+++ libc/include/link.h	Mon Dec 10 19:24:18 2001
@@ -132,14 +132,20 @@ struct link_map
     /* Indexed pointers to dynamic section.
        [0,DT_NUM) are indexed by the processor-independent tags.
        [DT_NUM,DT_NUM+DT_THISPROCNUM) are indexed by the tag minus DT_LOPROC.
-       [DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_EXTRANUM) are indexed
-       by DT_EXTRATAGIDX(tagvalue) and
+       [DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM) are
+       indexed by DT_VERSIONTAGIDX(tagvalue).
        [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM,
-        DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM)
-       are indexed by DT_EXTRATAGIDX(tagvalue) (see <elf.h>).  */
+	DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM) are indexed by
+       DT_EXTRATAGIDX(tagvalue).
+       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM,
+	DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM) are
+       indexed by DT_VALTAGIDX(tagvalue) and
+       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM,
+	DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM+DT_ADDRNUM)
+       are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>.  */
 
     ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
-		     + DT_EXTRANUM];
+		     + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
     const ElfW(Phdr) *l_phdr;	/* Pointer to program header table in core.  */
     ElfW(Addr) l_entry;		/* Entry point location.  */
     ElfW(Half) l_phnum;		/* Number of program header entries.  */
--- libc/sysdeps/alpha/dl-machine.h.jj	Thu Sep 27 23:26:30 2001
+++ libc/sysdeps/alpha/dl-machine.h	Mon Dec 10 19:24:18 2001
@@ -122,8 +122,30 @@ elf_machine_runtime_setup (struct link_m
       *(Elf64_Addr *)(plt + 24) = (Elf64_Addr) l;
 
       /* If the first instruction of the plt entry is not
-	 "br $28, plt0", we cannot do lazy relocation.  */
-      lazy = (*(unsigned int *)(plt + 32) == 0xc39ffff7);
+	 "br $28, plt0", we have to reinitialize .plt for lazy relocation.  */
+      if (*(unsigned int *)(plt + 32) != 0xc39ffff7)
+	{
+	  unsigned int val = 0xc39ffff7;
+	  unsigned int *slot, *end;
+	  const Elf64_Rela *rela = D_PTR (l, l_info[DT_JMPREL]);
+	  Elf64_Addr l_addr = l->l_addr;
+
+	  /* br t12,.+4; ldq t12,12(t12); nop; jmp t12,(t12),.+4 */
+	  *(unsigned long *)plt = 0xa77b000cc3600000;
+	  *(unsigned long *)(plt + 8) = 0x6b7b000047ff041f;
+	  slot = (unsigned int *)(plt + 32);
+	  end = (unsigned int *)(plt + 32
+				 + l->l_info[DT_PLTRELSZ]->d_un.d_val / 2);
+	  while (slot < end)
+	    {
+	      /* br at,.plt+0 */
+	      *slot = val;
+	      *(Elf64_Addr *) rela->r_offset = (Elf64_Addr) slot - l_addr;
+	      val -= 3;
+	      slot += 3;
+	      ++rela;
+	    }
+	}
     }
 
   return lazy;
@@ -520,8 +542,23 @@ elf_machine_rela (struct link_map *map,
 
       if (r_type == R_ALPHA_GLOB_DAT)
 	*reloc_addr = sym_value;
-      else if (r_type  == R_ALPHA_JMP_SLOT)
+#ifdef RESOLVE_CONFLICT_FIND_MAP
+      /* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have
+	 R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits
+	 are .rela.plt index.  */
+      else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT)
+	{
+	  /* elf_machine_fixup_plt needs the map reloc_addr points into,
+	     while in _dl_resolve_conflicts map is _dl_loaded.  */
+	  RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
+	  reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
+		  + (r_type >> 8);
+	  elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
+	}
+#else
+      else if (r_type == R_ALPHA_JMP_SLOT)
 	elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
+#endif
 #ifndef RTLD_BOOTSTRAP
       else if (r_type == R_ALPHA_REFQUAD)
 	{
--- libc/sysdeps/arm/bits/link.h.jj	Mon Dec 10 19:24:18 2001
+++ libc/sysdeps/arm/bits/link.h	Mon Dec 10 19:24:18 2001
@@ -0,0 +1,4 @@
+struct link_map_machine
+  {
+    Elf32_Addr plt; /* Address of .plt */
+  };
--- libc/sysdeps/arm/dl-machine.h.jj	Wed Nov 21 13:35:25 2001
+++ libc/sysdeps/arm/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -92,6 +92,11 @@ elf_machine_runtime_setup (struct link_m
 	 index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt.  */
+      if (got[1])
+	l->l_mach.plt = got[1] + l->l_addr;
       got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
 
       /* The got[2] entry contains the address of a function which gets
@@ -334,8 +339,9 @@ _dl_start_user:
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT	R_ARM_JUMP_SLOT
 
-/* The ARM never uses Elf32_Rela relocations.  */
-#define ELF_MACHINE_NO_RELA 1
+/* ARM never uses Elf32_Rela relocations for the dynamic linker.
+   Prelinked libraries may use Elf32_Rela though.  */
+#define ELF_MACHINE_PLT_REL 1
 
 /* We define an initialization functions.  This is called very early in
    _dl_sysdep_start.  */
@@ -371,6 +377,12 @@ elf_machine_plt_value (struct link_map *
 
 #ifdef RESOLVE
 
+/* ARM never uses Elf32_Rela relocations for the dynamic linker.
+   Prelinked libraries may use Elf32_Rela though.  */
+#ifdef RTLD_BOOTSTRAP
+#define ELF_MACHINE_NO_RELA 1
+#endif
+
 extern char **_dl_argv;
 
 /* Deal with an out-of-range PC24 reloc.  */
@@ -517,6 +529,64 @@ elf_machine_rel (struct link_map *map, c
     }
 }
 
+#ifndef RTLD_BOOTSTRAP
+static inline void
+elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+		  const Elf32_Sym *sym, const struct r_found_version *version,
+		  Elf32_Addr *const reloc_addr)
+{
+  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+
+  if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
+    *reloc_addr = map->l_addr + reloc->r_addend;
+#ifndef RTLD_BOOTSTRAP
+  else if (__builtin_expect (r_type == R_ARM_NONE, 0))
+    return;
+#endif
+  else
+    {
+      const Elf32_Sym *const refsym = sym;
+      Elf32_Addr value = RESOLVE (&sym, version, r_type);
+      if (sym)
+	value += sym->st_value;
+
+      switch (r_type)
+	{
+	case R_ARM_GLOB_DAT:
+	case R_ARM_JUMP_SLOT:
+	case R_ARM_ABS32:
+	  *reloc_addr = value + reloc->r_addend;
+	  break;
+	case R_ARM_PC24:
+	  {
+	     Elf32_Addr newvalue, topbits;
+
+	     newvalue = value + reloc->r_addend - (Elf32_Addr)reloc_addr;
+	     topbits = newvalue & 0xfe000000;
+	     if (topbits != 0xfe000000 && topbits != 0x00000000)
+	       {
+		 newvalue = fix_bad_pc24(reloc_addr, value)
+		   - (Elf32_Addr)reloc_addr + (addend << 2);
+		 topbits = newvalue & 0xfe000000;
+		 if (topbits != 0xfe000000 && topbits != 0x00000000)
+		   {
+		     _dl_signal_error (0, map->l_name, NULL,
+				       "R_ARM_PC24 relocation out of range");
+		   }
+	       }
+	     newvalue >>= 2;
+	     value = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
+	     *reloc_addr = value;
+	  }
+	  break;
+	default:
+	  _dl_reloc_bad_type (map, r_type, 0);
+	  break;
+	}
+    }
+}
+#endif
+
 static inline void
 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
 			  Elf32_Addr *const reloc_addr)
@@ -524,6 +594,15 @@ elf_machine_rel_relative (Elf32_Addr l_a
   *reloc_addr += l_addr;
 }
 
+#ifndef RTLD_BOOTSTRAP
+static inline void
+elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
+			   Elf32_Addr *const reloc_addr)
+{
+  *reloc_addr = l_addr + reloc->r_addend;
+}
+#endif
+
 static inline void
 elf_machine_lazy_rel (struct link_map *map,
 		      Elf32_Addr l_addr, const Elf32_Rel *reloc)
@@ -532,7 +611,12 @@ elf_machine_lazy_rel (struct link_map *m
   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_ARM_JUMP_SLOT, 1))
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr = map->l_mach.plt;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
--- libc/sysdeps/generic/ldsodefs.h.jj	Wed Nov 21 13:32:37 2001
+++ libc/sysdeps/generic/ldsodefs.h	Mon Dec 10 19:36:18 2001
@@ -207,6 +207,8 @@ extern const char *_dl_profile;
 extern struct link_map *_dl_profile_map;
 /* Filename of the output file.  */
 extern const char *_dl_profile_output;
+/* Map of shared object to be prelink traced.  */
+extern struct link_map *_dl_trace_prelink_map;
 
 /* If nonzero the appropriate debug information is printed.  */
 extern int _dl_debug_mask;
@@ -220,6 +222,7 @@ extern int _dl_debug_mask;
 #define DL_DEBUG_STATISTICS (1 << 7)
 /* This one is used only internally.  */
 #define DL_DEBUG_HELP       (1 << 8)
+#define DL_DEBUG_PRELINK    (1 << 9)
 
 /* Expect cache ID.  */
 extern int _dl_correct_cache_id;
@@ -435,6 +438,11 @@ extern void _dl_reloc_bad_type (struct l
 				unsigned int type, int plt)
      internal_function __attribute__ ((__noreturn__));
 
+/* Resolve conflicts if prelinking.  */
+extern void _dl_resolve_conflicts (struct link_map *l,
+				   ElfW(Rela) *conflict,
+				   ElfW(Rela) *conflictend);
+
 /* Check the version dependencies of all objects available through
    MAP.  If VERBOSE print some more diagnostics.  */
 extern int _dl_check_all_versions (struct link_map *map, int verbose,
--- libc/sysdeps/i386/bits/link.h.jj	Mon Dec 10 19:24:19 2001
+++ libc/sysdeps/i386/bits/link.h	Mon Dec 10 19:24:19 2001
@@ -0,0 +1,5 @@
+struct link_map_machine
+  {
+    Elf32_Addr plt; /* Address of .plt + 0x16 */
+    Elf32_Addr gotplt; /* Address of .got + 0x0c */
+  };
--- libc/sysdeps/i386/dl-machine.h.jj	Thu Sep 27 23:26:38 2001
+++ libc/sysdeps/i386/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -87,6 +87,14 @@ elf_machine_runtime_setup (struct link_m
 	 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt + 0x16.  */
+      if (got[1])
+	{
+	  l->l_mach.plt = got[1] + l->l_addr;
+	  l->l_mach.gotplt = (Elf32_Addr) &got[3];
+	}	  
       got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
 
       /* The got[2] entry contains the address of a function which gets
@@ -258,8 +266,9 @@ _dl_start_user:\n\
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT	R_386_JMP_SLOT
 
-/* The i386 never uses Elf32_Rela relocations.  */
-#define ELF_MACHINE_NO_RELA 1
+/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
+   Prelinked libraries may use Elf32_Rela though.  */
+#define ELF_MACHINE_PLT_REL 1
 
 /* We define an initialization functions.  This is called very early in
    _dl_sysdep_start.  */
@@ -295,6 +304,12 @@ elf_machine_plt_value (struct link_map *
 
 #ifdef RESOLVE
 
+/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
+   Prelinked libraries may use Elf32_Rela though.  */
+#ifdef RTLD_BOOTSTRAP
+#define ELF_MACHINE_NO_RELA 1
+#endif
+
 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
    MAP is the object containing the reloc.  */
 
@@ -378,6 +393,41 @@ elf_machine_rel (struct link_map *map, c
     }
 }
 
+#ifndef RTLD_BOOTSTRAP
+static inline void
+elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+		  const Elf32_Sym *sym, const struct r_found_version *version,
+		  Elf32_Addr *const reloc_addr)
+{
+  if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
+    *reloc_addr = map->l_addr + reloc->r_addend;
+  else if (ELF32_R_TYPE (reloc->r_info) != R_386_NONE)
+    {
+/*      const Elf32_Sym *const refsym = sym; */
+      Elf32_Addr value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
+      if (sym)
+	value += sym->st_value;
+
+      switch (ELF32_R_TYPE (reloc->r_info))
+	{
+	case R_386_GLOB_DAT:
+	case R_386_JMP_SLOT:
+	case R_386_32:
+	  *reloc_addr = value + reloc->r_addend;
+	  break;
+	case R_386_PC32:
+	  *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
+	  break;
+	default:
+	  /* We add these checks in the version to relocate ld.so only
+	     if we are still debugging.  */
+	  _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
+	  break;
+	}
+    }
+}
+#endif
+
 static inline void
 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
 			  Elf32_Addr *const reloc_addr)
@@ -386,6 +436,15 @@ elf_machine_rel_relative (Elf32_Addr l_a
   *reloc_addr += l_addr;
 }
 
+#ifndef RTLD_BOOTSTRAP
+static inline void
+elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
+			   Elf32_Addr *const reloc_addr)
+{
+  *reloc_addr = l_addr + reloc->r_addend;
+}
+#endif
+
 static inline void
 elf_machine_lazy_rel (struct link_map *map,
 		      Elf32_Addr l_addr, const Elf32_Rel *reloc)
@@ -394,9 +453,26 @@ elf_machine_lazy_rel (struct link_map *m
   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr =
+	  map->l_mach.plt
+	  + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
 
+#ifndef RTLD_BOOTSTRAP
+
+static inline void
+elf_machine_lazy_rela (struct link_map *map,
+		       Elf32_Addr l_addr, const Elf32_Rela *reloc)
+{
+}
+
+#endif
+
 #endif /* RESOLVE */
--- libc/sysdeps/powerpc/dl-machine.h.jj	Mon Aug 27 12:04:30 2001
+++ libc/sysdeps/powerpc/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -347,6 +347,7 @@ elf_machine_rela (struct link_map *map, 
   Elf32_Word loadbase, finaladdr;
   const int rinfo = ELF32_R_TYPE (reloc->r_info);
 
+#ifndef RESOLVE_CONFLICT_FIND_MAP
   if (__builtin_expect (rinfo == R_PPC_NONE, 0))
     return;
 
@@ -375,6 +376,11 @@ elf_machine_rela (struct link_map *map, 
 	finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
 		     + reloc->r_addend);
     }
+#else
+  finaladdr = reloc->r_addend;
+  if (rinfo == R_PPC_JMP_SLOT)
+    RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
+#endif
 
   /* A small amount of code is duplicated here for speed.  In libc,
      more than 90% of the relocs are R_PPC_RELATIVE; in the X11 shared
--- libc/sysdeps/sparc/sparc32/dl-machine.h.jj	Thu Sep 27 23:26:38 2001
+++ libc/sysdeps/sparc/sparc32/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -23,6 +23,10 @@
 #include <sys/param.h>
 #include <ldsodefs.h>
 
+#ifndef VALIDX
+# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+		      + DT_EXTRANUM + DT_VALTAGIDX (tag))
+#endif
 
 /* Some SPARC opcodes we need to use for self-modifying code.  */
 #define OPCODE_NOP	0x01000000 /* nop */
@@ -30,6 +34,7 @@
 #define OPCODE_SETHI_G1	0x03000000 /* sethi ?, %g1; add value>>10 */
 #define OPCODE_JMP_G1	0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
 #define OPCODE_SAVE_SP	0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
+#define OPCODE_BA	0x30800000 /* b,a ?; add PC-rel word address */
 
 /* Protect some broken versions of gcc from misinterpreting weak addresses.  */
 #define WEAKADDR(x)	({ __typeof(x) *_px = &x;			\
@@ -139,6 +144,37 @@ elf_machine_runtime_setup (struct link_m
       plt[1] = OPCODE_CALL | ((rfunc - (Elf32_Addr) &plt[1]) >> 2);
       plt[2] = OPCODE_NOP;	/* Fill call delay slot.  */
       plt[3] = (Elf32_Addr) l;
+      if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
+	  || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
+	{
+	  /* Need to reinitialize .plt to undo prelinking.  */
+	  unsigned long *hwcap;
+	  int do_flush;
+	  Elf32_Rela *rela = (Elf32_Rela *) D_PTR (l, l_info[DT_JMPREL]);
+	  Elf32_Rela *relaend
+	    = (Elf32_Rela *) ((char *) rela
+			      + l->l_info[DT_PLTRELSZ]->d_un.d_val);
+	  weak_extern (_dl_hwcap);
+	  hwcap = WEAKADDR(_dl_hwcap);
+	  do_flush = (!hwcap || (*hwcap & HWCAP_SPARC_FLUSH));
+
+	  /* prelink must ensure there are no R_SPARC_NONE relocs left
+	     in .rela.plt.  */
+	  while (rela < relaend)
+	    {
+	      *(unsigned int *) rela->r_offset
+		= OPCODE_SETHI_G1 | (rela->r_offset - (Elf32_Addr) plt);
+	      *(unsigned int *) (rela->r_offset + 4)
+		= OPCODE_BA | ((((Elf32_Addr) plt
+				 - rela->r_offset - 4) >> 2) & 0x3fffff);
+	      if (do_flush)
+		{
+		  __asm __volatile ("flush %0" : : "r"(rela->r_offset));
+		  __asm __volatile ("flush %0+4" : : "r"(rela->r_offset));
+		}
+	      ++rela;
+	    }
+	}
     }
 
   return lazy;
@@ -292,10 +328,10 @@ _dl_start_user:
 	.previous");
 
 static inline Elf32_Addr
-elf_machine_fixup_plt (struct link_map *map, lookup_t t,
-		       const Elf32_Rela *reloc,
-		       Elf32_Addr *reloc_addr, Elf32_Addr value)
+sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
+		 Elf32_Addr value, int t)
 {
+  Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
 #ifndef RTLD_BOOTSTRAP
   /* Note that we don't mask the hwcap here, as the flush is essential to
      functionality on those cpu's that implement it.  */
@@ -309,23 +345,44 @@ elf_machine_fixup_plt (struct link_map *
      ld.so will not execute corrupt PLT entry instructions. */
   const int do_flush = 1;
 #endif
+  
+  if (0 && disp >= -0x800000 && disp < 0x800000)
+    {
+      /* Don't need to worry about thread safety. We're writing just one
+	 instruction.  */
 
-  /* For thread safety, write the instructions from the bottom and
-     flush before we overwrite the critical "b,a".  This of course
-     need not be done during bootstrapping, since there are no threads.
-     But we also can't tell if we _can_ use flush, so don't. */
-
-  reloc_addr[2] = OPCODE_JMP_G1 | (value & 0x3ff);
-  if (do_flush)
-    __asm __volatile ("flush %0+8" : : "r"(reloc_addr));
-
-  reloc_addr[1] = OPCODE_SETHI_G1 | (value >> 10);
-  if (do_flush)
-    __asm __volatile ("flush %0+4" : : "r"(reloc_addr));
+      reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff);
+      if (do_flush)
+	__asm __volatile ("flush %0" : : "r"(reloc_addr));
+    }
+  else
+    {
+      /* For thread safety, write the instructions from the bottom and
+	 flush before we overwrite the critical "b,a".  This of course
+	 need not be done during bootstrapping, since there are no threads.
+	 But we also can't tell if we _can_ use flush, so don't. */
+
+      reloc_addr += t;
+      reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
+      if (do_flush)
+	__asm __volatile ("flush %0+4" : : "r"(reloc_addr));
+
+      reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
+      if (do_flush)
+	__asm __volatile ("flush %0" : : "r"(reloc_addr));
+    }
 
   return value;
 }
 
+static inline Elf32_Addr
+elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const Elf32_Rela *reloc,
+		       Elf32_Addr *reloc_addr, Elf32_Addr value)
+{
+  return sparc_fixup_plt (reloc, reloc_addr, value, 1);
+}
+
 /* Return the final value of a plt relocation.  */
 static inline Elf32_Addr
 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
@@ -366,10 +423,11 @@ elf_machine_rela (struct link_map *map, 
   else
 #endif
     {
-#ifndef RTLD_BOOTSTRAP
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
       const Elf32_Sym *const refsym = sym;
 #endif
       Elf32_Addr value;
+#ifndef RESOLVE_CONFLICT_FIND_MAP
       if (sym->st_shndx != SHN_UNDEF &&
 	  ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
 	value = map->l_addr;
@@ -379,11 +437,14 @@ elf_machine_rela (struct link_map *map, 
 	  if (sym)
 	    value += sym->st_value;
 	}
+#else
+      value = 0;
+#endif
       value += reloc->r_addend;	/* Assume copy relocs have zero addend.  */
 
       switch (r_type)
 	{
-#ifndef RTLD_BOOTSTRAP
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
 	case R_SPARC_COPY:
 	  if (sym == NULL)
 	    /* This can happen in trace mode if an object could not be
@@ -410,7 +471,9 @@ elf_machine_rela (struct link_map *map, 
 	  *reloc_addr = value;
 	  break;
 	case R_SPARC_JMP_SLOT:
-	  elf_machine_fixup_plt(map, 0, reloc, reloc_addr, value);
+	  /* At this point we don't need to bother with thread safety,
+	     so we can optimize the first instruction of .plt out.  */
+	  sparc_fixup_plt (reloc, reloc_addr, value, 0);
 	  break;
 #ifndef RTLD_BOOTSTRAP
 	case R_SPARC_8:
--- libc/sysdeps/sparc/sparc64/dl-machine.h.jj	Mon Oct  1 12:18:57 2001
+++ libc/sysdeps/sparc/sparc64/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -24,6 +24,11 @@
 #include <ldsodefs.h>
 #include <sysdep.h>
 
+#ifndef VALIDX
+# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+		      + DT_EXTRANUM + DT_VALTAGIDX (tag))
+#endif
+
 #define ELF64_R_TYPE_ID(info)	((info) & 0xff)
 #define ELF64_R_TYPE_DATA(info) ((info) >> 8)
 
@@ -147,7 +152,7 @@ sparc64_fixup_plt (struct link_map *map,
       insns[1] = 0x40000000 | (displacement >> 2);
       __asm __volatile ("flush %0 + 4" : : "r" (insns));
 
-      insns[t] = 0x8210000f;
+      insns[0] = 0x8210000f;
       __asm __volatile ("flush %0" : : "r" (insns));
     }
   /* Worst case, ho hum...  */
@@ -251,10 +256,11 @@ elf_machine_rela (struct link_map *map, 
   else
 #endif
     {
-#ifndef RTLD_BOOTSTRAP
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
       const Elf64_Sym *const refsym = sym;
 #endif
       Elf64_Addr value;
+#ifndef RESOLVE_CONFLICT_FIND_MAP
       if (sym->st_shndx != SHN_UNDEF &&
 	  ELF64_ST_BIND (sym->st_info) == STB_LOCAL)
 	value = map->l_addr;
@@ -264,11 +270,14 @@ elf_machine_rela (struct link_map *map, 
 	  if (sym)
 	    value += sym->st_value;
 	}
+#else
+      value = 0;
+#endif
       value += reloc->r_addend;	/* Assume copy relocs have zero addend.  */
 
       switch (r_type)
 	{
-#ifndef RTLD_BOOTSTRAP
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
 	case R_SPARC_COPY:
 	  if (sym == NULL)
 	    /* This can happen in trace mode if an object could not be
@@ -371,8 +380,18 @@ elf_machine_rela (struct link_map *map, 
 	  break;
 #endif
 	case R_SPARC_JMP_SLOT:
+#ifdef RESOLVE_CONFLICT_FIND_MAP
+	  /* R_SPARC_JMP_SLOT conflicts against .plt[32768+]
+	     relocs should be turned into R_SPARC_64 relocs
+	     in .gnu.conflict section.
+	     r_addend non-zero does not mean it is a .plt[32768+]
+	     reloc, instead it is the actual address of the function
+	     to call.  */
+	  sparc64_fixup_plt (NULL, reloc, reloc_addr, value, 0, 0);
+#else
 	  sparc64_fixup_plt (map, reloc, reloc_addr, value,
 			     reloc->r_addend, 0);
+#endif
 	  break;
 #ifndef RTLD_BOOTSTRAP
 	case R_SPARC_UA16:
@@ -536,6 +555,47 @@ elf_machine_runtime_setup (struct link_m
       /* Now put the magic cookie at the beginning of .PLT2
 	 Entry .PLT3 is unused by this implementation.  */
       *((struct link_map **)(&plt[16 + 0])) = l;
+
+      if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
+	  || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
+	{
+	  /* Need to reinitialize .plt to undo prelinking.  */
+	  Elf64_Rela *rela = (Elf64_Rela *) D_PTR (l, l_info[DT_JMPREL]);
+	  Elf64_Rela *relaend
+	    = (Elf64_Rela *) ((char *) rela
+			      + l->l_info[DT_PLTRELSZ]->d_un.d_val);
+
+	  /* prelink must ensure there are no R_SPARC_NONE relocs left
+	     in .rela.plt.  */
+	  while (rela < relaend)
+	    {
+	      if (__builtin_expect (rela->r_addend, 0) != 0)
+		{
+                  Elf64_Addr slot = ((rela->r_offset + 0x400
+				      - (Elf64_Addr) plt)
+				     / 0x1400) * 0x1400
+				    + (Elf64_Addr) plt - 0x400;
+		  /* ldx [%o7 + X], %g1  */
+		  unsigned int first_ldx = *(unsigned int *)(slot + 12);
+		  Elf64_Addr ptr = slot + (first_ldx & 0xfff) + 4;
+
+		  *(Elf64_Addr *) rela->r_offset
+		    = (Elf64_Addr) plt
+		      - (slot + ((rela->r_offset - ptr) / 8) * 24 + 4);
+		  ++rela;
+		  continue;
+		}
+
+	      *(unsigned int *) rela->r_offset
+		= 0x03000000 | (rela->r_offset - (Elf64_Addr) plt);
+	      *(unsigned int *) (rela->r_offset + 4)
+		= 0x30680000 | ((((Elf64_Addr) plt + 32
+				  - rela->r_offset - 4) >> 2) & 0x7ffff);
+	      __asm __volatile ("flush %0" : : "r" (rela->r_offset));
+	      __asm __volatile ("flush %0+4" : : "r" (rela->r_offset));
+	      ++rela;
+	    }
+	}
     }
 
   return lazy;
--- libc/sysdeps/sh/bits/link.h.jj	Mon Dec 10 19:24:19 2001
+++ libc/sysdeps/sh/bits/link.h	Mon Dec 10 19:24:19 2001
@@ -0,0 +1,5 @@
+struct link_map_machine
+  {
+    Elf32_Addr plt; /* Address of .plt + 36 */
+    Elf32_Addr gotplt; /* Address of .got + 0x0c */
+  };
--- libc/sysdeps/sh/dl-machine.h.jj	Wed Nov 21 13:35:25 2001
+++ libc/sysdeps/sh/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -85,6 +85,14 @@ elf_machine_runtime_setup (struct link_m
 	 offset into the .rela.plt section and _GLOBAL_OFFSET_TABLE_[1],
 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt + 36.  */
+      if (got[1])
+	{
+	  l->l_mach.plt = got[1] + l->l_addr;
+	  l->l_mach.gotplt = (Elf32_Addr) &got[3];
+	}
       got[1] = (Elf32_Addr) l;	/* Identify this shared object.	 */
 
       /* The got[2] entry contains the address of a function which gets
@@ -582,7 +590,14 @@ elf_machine_lazy_rel (struct link_map *m
   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
   /* Check for unexpected PLT reloc type.  */
   if (ELF32_R_TYPE (reloc->r_info) == R_SH_JMP_SLOT)
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr =
+	  map->l_mach.plt
+	  + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 7;
+    }
   else
     _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
 }
--- libc/sysdeps/s390/s390-32/bits/link.h.jj	Mon Dec 10 19:24:19 2001
+++ libc/sysdeps/s390/s390-32/bits/link.h	Mon Dec 10 19:24:19 2001
@@ -0,0 +1,5 @@
+struct link_map_machine
+  {
+    Elf32_Addr plt; /* Address of .plt + 0x2c */
+    Elf32_Addr gotplt; /* Address of .got + 0x0c */
+  };
--- libc/sysdeps/s390/s390-32/dl-machine.h.jj	Mon Aug 27 12:04:30 2001
+++ libc/sysdeps/s390/s390-32/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -92,6 +92,14 @@ elf_machine_runtime_setup (struct link_m
 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       Elf32_Addr *got;
       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt + 0x2c.  */
+      if (got[1])
+	{
+	  l->l_mach.plt = got[1] + l->l_addr;
+	  l->l_mach.gotplt = (Elf32_Addr) &got[3];
+	}
       got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
 
       /* The got[2] entry contains the address of a function which gets
@@ -454,7 +462,14 @@ elf_machine_lazy_rel (struct link_map *m
   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_390_JMP_SLOT, 1))
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr =
+	  map->l_mach.plt
+	  + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 8;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
--- libc/sysdeps/s390/s390-64/bits/link.h.jj	Mon Dec 10 19:24:19 2001
+++ libc/sysdeps/s390/s390-64/bits/link.h	Mon Dec 10 19:24:19 2001
@@ -0,0 +1,5 @@
+struct link_map_machine
+  {
+    Elf64_Addr plt; /* Address of .plt + 0x2e */
+    Elf64_Addr gotplt; /* Address of .got + 0x18 */
+  };
--- libc/sysdeps/s390/s390-64/dl-machine.h.jj	Mon Aug 27 12:04:55 2001
+++ libc/sysdeps/s390/s390-64/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -85,6 +85,14 @@ elf_machine_runtime_setup (struct link_m
 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       Elf64_Addr *got;
       got = (Elf64_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt + 0x2e.  */
+      if (got[1])
+	{
+	  l->l_mach.plt = got[1] + l->l_addr;
+	  l->l_mach.gotplt = (Elf64_Addr) &got[3];
+	}
       got[1] = (Elf64_Addr) l;	/* Identify this shared object.	 */
 
       /* The got[2] entry contains the address of a function which gets
@@ -434,7 +442,14 @@ elf_machine_lazy_rel (struct link_map *m
   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_390_JMP_SLOT, 1))
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr =
+	  map->l_mach.plt
+	  + (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 4;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
--- libc/sysdeps/x86_64/bits/link.h.jj	Mon Dec 10 19:24:19 2001
+++ libc/sysdeps/x86_64/bits/link.h	Mon Dec 10 19:24:19 2001
@@ -0,0 +1,5 @@
+struct link_map_machine
+  {
+    Elf64_Addr plt; /* Address of .plt + 0x16 */
+    Elf64_Addr gotplt; /* Address of .got + 0x18 */
+  };
--- libc/sysdeps/x86_64/dl-machine.h.jj	Wed Sep 19 12:12:07 2001
+++ libc/sysdeps/x86_64/dl-machine.h	Mon Dec 10 19:24:19 2001
@@ -76,6 +76,14 @@ elf_machine_runtime_setup (struct link_m
 	 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       got = (Elf64_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt + 0x16.  */
+      if (got[1])
+	{
+	  l->l_mach.plt = got[1] + l->l_addr;
+	  l->l_mach.gotplt = (Elf64_Addr) &got[3];
+	}
       got[1] = (Elf64_Addr) l;	/* Identify this shared object.  */
 
       /* The got[2] entry contains the address of a function which gets
@@ -409,7 +417,14 @@ elf_machine_lazy_rel (struct link_map *m
 
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_X86_64_JUMP_SLOT, 1))
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr =
+	  map->l_mach.plt
+	  + (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 2;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]