This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


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] prelink: Add tls support for SH architecture.


This patch extend the prelink tool also for sh architecture adding the tls
support, and fixes some architecture specific issue.
The fix in the sh_undo_prelink_rela function is needed to restore all the GOT
entries to the original value.
In the prelink stage GOT[1] has been set to the first plt entry just after the
plt header (This is the necessary code to jump at PLT[0]).
To retrieve the other ones we need to add (28 * n) byte to the first one, where
n is the n-th entry of the PLTn (n = 0,1,2,...).
The fix in src/dwarf2.c avoid assertion fail at line 808 for layout[12],
cxx[12] and undosyslibs tests.

2009-06-25  Filippo Arcidiacono  <filippo.arcidiacono@st.com>

        * src/arch-sh.c: Added TLS relocation support on SH.
        * src/dwarf2.c: SH specific fix.
        * testsuite/reloc8.sh: Update test for SH.
        * testsuite/reloc9.sh: Update test for SH.
        * testsuite/tls3.sh: Update test for SH.
---
 src/arch-sh.c       |  101 +++++++++++++++++++++++++++++++++++++++++++++++----
 src/dwarf2.c        |    7 ++++
 testsuite/reloc8.sh |    3 ++
 testsuite/reloc9.sh |    3 ++
 testsuite/tls3.sh   |    2 +-
 5 files changed, 108 insertions(+), 8 deletions(-)

diff --git a/src/arch-sh.c b/src/arch-sh.c
index c5c9f52..1944a74 100644
--- a/src/arch-sh.c
+++ b/src/arch-sh.c
@@ -85,8 +85,10 @@ sh_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
       if (rela->r_addend && (Elf32_Addr) rela->r_addend >= start)
 	{
 	  rela->r_addend += (Elf32_Sword) adjust;
+          write_ne32 (dso, rela->r_offset, rela->r_addend);
 	  break;
 	}
+       break;
       /* FALLTHROUGH */
     case R_SH_JMP_SLOT:
       data = read_une32 (dso, rela->r_offset);
@@ -133,8 +135,26 @@ sh_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
       write_ne32 (dso, rela->r_offset, value);
       break;
     case R_SH_REL32:
-      write_ne32 (dso, rela->r_offset, value - rela->r_addend);
+      write_ne32 (dso, rela->r_offset, value - rela->r_offset);
       break;
+    case R_SH_TLS_DTPOFF32:
+      write_ne32 (dso, rela->r_offset, value);
+      break;
+    /* DTPMOD32 and TPOFF{32,} is impossible to predict unless prelink
+       sets the rules.  */
+    case R_SH_TLS_DTPMOD32:
+      if (dso->ehdr.e_type == ET_EXEC)
+        {
+          error (0, 0, "%s: R_SH_TLS_DTPMOD32 reloc in executable?",
+                 dso->filename);
+          return 1;
+        }
+      break;
+    case R_SH_TLS_TPOFF32:
+      if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+        write_ne32 (dso, rela->r_offset,
+                    (value + info->resolvetls->offset));
+       break;
     case R_SH_COPY:
       if (dso->ehdr.e_type == ET_EXEC)
 	/* COPY relocs are handled specially in generic code.  */
@@ -218,6 +238,7 @@ sh_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
 {
   GElf_Addr value;
   struct prelink_conflict *conflict;
+  struct prelink_tls *tls;
   GElf_Rela *ret;
 
   if (GELF_R_TYPE (rela->r_info) == R_SH_RELATIVE
@@ -227,8 +248,31 @@ sh_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
   conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
 			       GELF_R_TYPE (rela->r_info));
   if (conflict == NULL)
+    {
+      if (info->curtls == NULL)
     return 0;
-  value = conflict_lookup_value (conflict);
+      switch (GELF_R_TYPE (rela->r_info))
+	{
+	/* Even local DTPMOD and TPOFF relocs need conflicts.  */
+	case R_SH_TLS_DTPMOD32:
+	case R_SH_TLS_TPOFF32:
+	  break;
+	default:
+	  return 0;
+	}
+      value = 0;
+    }
+  else
+    {
+      /* DTPOFF32 wants to see only real conflicts, not lookups
+	 with reloc_class RTYPE_CLASS_TLS.  */
+      if (GELF_R_TYPE (rela->r_info) == R_SH_TLS_DTPOFF32
+	  && conflict->lookup.tls == conflict->conflict.tls
+	  && conflict->lookupval == conflict->conflictval)
+	return 0;
+
+      value = conflict_lookup_value (conflict);
+    }
   ret = prelink_conflict_add_rela (info);
   if (ret == NULL)
     return 1;
@@ -247,11 +291,38 @@ sh_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
       /* FALLTHROUGH */
     case R_SH_GLOB_DAT:
     case R_SH_JMP_SLOT:
-      ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
+      ret->r_addend = (Elf32_Sword) (value);
       break;
     case R_SH_COPY:
       error (0, 0, "R_SH_COPY should not be present in shared libraries");
       return 1;
+    case R_SH_TLS_DTPMOD32:
+    case R_SH_TLS_DTPOFF32:
+    case R_SH_TLS_TPOFF32:
+      if (conflict != NULL
+          && (conflict->reloc_class != RTYPE_CLASS_TLS
+              || conflict->lookup.tls == NULL))
+        {
+          error (0, 0, "%s: R_SH_TLS not resolving to STT_TLS symbol",
+                 dso->filename);
+          return 1;
+        }
+      tls = conflict ? conflict->lookup.tls : info->curtls;
+      ret->r_info = GELF_R_INFO (0, R_SH_DIR32);
+      switch (GELF_R_TYPE (rela->r_info))
+        {
+        case R_SH_TLS_DTPMOD32:
+          ret->r_addend = tls->modid;
+          break;
+        case R_SH_TLS_DTPOFF32:
+          ret->r_addend += value;
+          break;
+        case R_SH_TLS_TPOFF32:
+          ret->r_addend = value + tls->offset;
+          break;
+        }
+      break;
+
     default:
       error (0, 0, "%s: Unknown sh relocation type %d", dso->filename,
 	     (int) GELF_R_TYPE (rela->r_info));
@@ -348,7 +419,7 @@ sh_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
       break;
     case R_SH_RELATIVE:
       if (rela->r_addend)
-	write_le32 (dso, rela->r_offset, 0);
+	write_ne32 (dso, rela->r_offset, 0);
       break;
     case R_SH_JMP_SLOT:
       sec = addr_to_sec (dso, rela->r_offset);
@@ -365,15 +436,22 @@ sh_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
 
 	  assert (rela->r_offset >= dso->shdr[sec].sh_addr + 12);
 	  assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 3) == 0);
+      /*
+       * In the prelink stage GOT[1] has been set to the first plt entry 
+       * just after the plt header (This is the necessary code to jump at 
+       * PLT[0]).
+       * To retrieve the other ones we need to add (28 * n) byte to the 
+       * first one, where n is the n-th entry of the PLTn (n = 0,1,2,...).
+       */
 	  write_ne32 (dso, rela->r_offset,
-		      7 * (rela->r_offset - dso->shdr[sec].sh_addr - 12)
+		      28 * ((rela->r_offset - dso->shdr[sec].sh_addr - 12) / 4)
 		      + data);
 	}
       break;
     case R_SH_GLOB_DAT:
     case R_SH_DIR32:
     case R_SH_REL32:
-      write_ne32 (dso, rela->r_offset, 0);
+      write_ne32 (dso, rela->r_offset, rela->r_addend);
       break;
     case R_SH_COPY:
       if (dso->ehdr.e_type == ET_EXEC)
@@ -381,6 +459,11 @@ sh_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
 	return 0;
       error (0, 0, "%s: R_SH_COPY reloc in shared library?", dso->filename);
       return 1;
+    case R_SH_TLS_DTPMOD32:
+    case R_SH_TLS_DTPOFF32:
+    case R_SH_TLS_TPOFF32:
+      write_ne32 (dso, rela->r_offset, 0);
+      break;
     default:
       error (0, 0, "%s: Unknown sh relocation type %d", dso->filename,
 	     (int) GELF_R_TYPE (rela->r_info));
@@ -402,6 +485,10 @@ sh_reloc_class (int reloc_type)
     {
     case R_SH_COPY: return RTYPE_CLASS_COPY;
     case R_SH_JMP_SLOT: return RTYPE_CLASS_PLT;
+    case R_SH_TLS_DTPMOD32:
+    case R_SH_TLS_DTPOFF32:
+    case R_SH_TLS_TPOFF32:
+      return RTYPE_CLASS_TLS;
     default: return RTYPE_CLASS_VALID;
     }
 }
@@ -441,6 +528,6 @@ PL_ARCH = {
      even dlopened libraries will get the slots they desire.  */
   .mmap_base = 0x30000000,
   .mmap_end =  0x40000000,
-  .max_page_size = 0x2000,
+  .max_page_size = 0x10000,
   .page_size = 0x1000
 };
diff --git a/src/dwarf2.c b/src/dwarf2.c
index 4c27836..4d3e1b9 100644
--- a/src/dwarf2.c
+++ b/src/dwarf2.c
@@ -789,6 +789,13 @@ adjust_dwarf2_aranges (DSO *dso, GElf_Addr start, GElf_Addr adjust)
 	}
 
       ptr += 6;
+#ifdef __SH4__
+/*
+ * This fix skips padding to avoid assertion fail at line 808 for 
+ * layout[12], cxx[12] and undosyslibs tests.
+ */
+      ptr += 8;
+#endif
       while (ptr < endcu)
 	{
 	  addr = read_ptr (ptr);
diff --git a/testsuite/reloc8.sh b/testsuite/reloc8.sh
index ea0a89e..d2377f0 100755
--- a/testsuite/reloc8.sh
+++ b/testsuite/reloc8.sh
@@ -8,6 +8,9 @@ NOCOPYRELOC=-Wl,-z,nocopyreloc
 case "`uname -m`" in
   x86_64|s390*) if file reloc1lib1.so | grep -q 64-bit; then NOCOPYRELOC=; fi;;
 esac
+case "`uname -m`" in
+  sh4) NOCOPYRELOC=;
+esac
 $CC -shared -O2 -Wl,-z,nocombreloc -fpic -o reloc8lib1.so $srcdir/reloc3lib1.c
 $CC -shared -O2 -Wl,-z,nocombreloc -fpic -o reloc8lib2.so $srcdir/reloc1lib2.c reloc8lib1.so
 BINS="reloc8"
diff --git a/testsuite/reloc9.sh b/testsuite/reloc9.sh
index 41fe578..4b2b57c 100755
--- a/testsuite/reloc9.sh
+++ b/testsuite/reloc9.sh
@@ -8,6 +8,9 @@ NOCOPYRELOC=-Wl,-z,nocopyreloc
 case "`uname -m`" in
   x86_64|s390*) if file reloc1lib1.so | grep -q 64-bit; then NOCOPYRELOC=; fi;;
 esac
+case "`uname -m`" in
+  sh4) NOCOPYRELOC=;
+esac
 $CC -shared -O2 -Wl,-z,nocombreloc -fpic -o reloc9lib1.so $srcdir/reloc3lib1.c
 $CC -shared -O2 -Wl,-z,nocombreloc -fpic -o reloc9lib2.so $srcdir/reloc1lib2.c reloc9lib1.so
 BINS="reloc9"
diff --git a/testsuite/tls3.sh b/testsuite/tls3.sh
index 34cbfd7..6ccb159 100755
--- a/testsuite/tls3.sh
+++ b/testsuite/tls3.sh
@@ -7,7 +7,7 @@ echo '__thread int a; int main (void) { return a; }' \
 ( ./tlstest || { rm -f tlstest; exit 77; } ) 2>/dev/null || exit 77
 SHFLAGS=
 case "`uname -m`" in
-  ia64|ppc*|x86_64|alpha*|s390*|mips*|arm*) SHFLAGS=-fpic;; # Does not support non-pic shared libs
+  ia64|ppc*|x86_64|alpha*|s390*|mips*|arm*|sh4) SHFLAGS=-fpic;; # Does not support non-pic shared libs
 esac
 # Disable this test under SELinux if textrel
 test -z "$SHFLAGS" -a -x /usr/sbin/getenforce -a "`/usr/sbin/getenforce`" = Enforcing && exit 77
-- 
1.6.0.6


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