about summary refs log tree commit diff
path: root/elf/rtld.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2001-12-12 00:21:26 +0000
committerUlrich Drepper <drepper@redhat.com>2001-12-12 00:21:26 +0000
commit32e6df3621edc5067dfd6e87a387e1751f67f708 (patch)
tree957300a92ed16417fb46ce240d19f965fe773181 /elf/rtld.c
parent4be601a15e63d03adf55c48c19dda2d2e7377d8a (diff)
downloadglibc-32e6df3621edc5067dfd6e87a387e1751f67f708.tar.gz
glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.tar.xz
glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.zip
Update.
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 variables.
	(_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 declaration.
	(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.
Diffstat (limited to 'elf/rtld.c')
-rw-r--r--elf/rtld.c167
1 files changed, 152 insertions, 15 deletions
diff --git a/elf/rtld.c b/elf/rtld.c
index 8ed86eaedb..a05bbe9a62 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -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_map *bootstrap_map_p,
      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_map *bootstrap_map_p,
 	  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 did not intend to run this program.\n\
 	{
 	  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 did not intend to run this program.\n\
 		    }
 		  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 did not intend to run this program.\n\
       _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 did not intend to run this program.\n\
   _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)