about summary refs log tree commit diff
path: root/sysdeps/sparc
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 /sysdeps/sparc
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 'sysdeps/sparc')
-rw-r--r--sysdeps/sparc/sparc32/dl-machine.h99
-rw-r--r--sysdeps/sparc/sparc64/dl-machine.h66
2 files changed, 144 insertions, 21 deletions
diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h
index d98848b5dd..19a3897edb 100644
--- a/sysdeps/sparc/sparc32/dl-machine.h
+++ b/sysdeps/sparc/sparc32/dl-machine.h
@@ -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_map *l, int lazy, int profile)
       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 *map, lookup_t t,
      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, const Elf32_Rela *reloc,
   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, const Elf32_Rela *reloc,
 	  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, const Elf32_Rela *reloc,
 	  *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:
diff --git a/sysdeps/sparc/sparc64/dl-machine.h b/sysdeps/sparc/sparc64/dl-machine.h
index 9d2f2187ae..913f98a5e1 100644
--- a/sysdeps/sparc/sparc64/dl-machine.h
+++ b/sysdeps/sparc/sparc64/dl-machine.h
@@ -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, const Elf64_Rela *reloc,
       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, const Elf64_Rela *reloc,
   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, const Elf64_Rela *reloc,
 	  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, const Elf64_Rela *reloc,
 	  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_map *l, int lazy, int profile)
       /* 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;