PR20989, sparc GOT sequence optimisation
authorAlan Modra <amodra@gmail.com>
Mon, 2 Jan 2017 11:36:28 +0000 (22:06 +1030)
committerAlan Modra <amodra@gmail.com>
Mon, 2 Jan 2017 11:36:28 +0000 (22:06 +1030)
PR ld/20989
* elfxx-sparc.c (gdop_relative_offset_ok): New function.
(_bfd_sparc_elf_relocate_section): Use it to validate GOT
indirect to GOT pointer relative code edit.

bfd/ChangeLog
bfd/elfxx-sparc.c

index 6a61d61fee1bf2809d6731be3394909dd7b3ee32..c129543fd742730f152a2ad0f08377a67689f422 100644 (file)
@@ -1,3 +1,10 @@
+2017-01-02  Alan Modra  <amodra@gmail.com>
+
+       PR ld/20989
+       * elfxx-sparc.c (gdop_relative_offset_ok): New function.
+       (_bfd_sparc_elf_relocate_section): Use it to validate GOT
+       indirect to GOT pointer relative code edit.
+
 2017-01-02  Alan Modra  <amodra@gmail.com>
 
        Update year range in copyright notice of all files.
index 4ec013d6072376a2e08e2cd03b18242a45b6952f..f66525e11ffd5e5270283d2f3ab5f3a5e6a4c7fc 100644 (file)
@@ -2927,6 +2927,33 @@ gdopoff (struct bfd_link_info *info, bfd_vma address)
   return address - got_base;
 }
 
+/* Return whether H is local and its ADDRESS is within 4G of
+   _GLOBAL_OFFSET_TABLE_ and thus the offset may be calculated by a
+   sethi, xor sequence.  */
+
+static bfd_boolean
+gdop_relative_offset_ok (struct bfd_link_info *info,
+                        struct elf_link_hash_entry *h,
+                        bfd_vma address ATTRIBUTE_UNUSED)
+{
+  if (!SYMBOL_REFERENCES_LOCAL (info, h))
+    return FALSE;
+  /* If H is undefined, ADDRESS will be zero.  We can't allow a
+     relative offset to "zero" when producing PIEs or shared libs.
+     Note that to get here with an undefined symbol it must also be
+     hidden or internal visibility.  */
+  if (bfd_link_pic (info)
+      && h != NULL
+      && (h->root.type == bfd_link_hash_undefweak
+         || h->root.type == bfd_link_hash_undefined))
+    return FALSE;
+#ifdef BFD64
+  return gdopoff (info, address) + ((bfd_vma) 1 << 32) < (bfd_vma) 2 << 32;
+#else
+  return TRUE;
+#endif
+}
+
 /* Relocate a SPARC ELF section.  */
 
 bfd_boolean
@@ -3168,7 +3195,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
        {
        case R_SPARC_GOTDATA_OP_HIX22:
        case R_SPARC_GOTDATA_OP_LOX10:
-         if (SYMBOL_REFERENCES_LOCAL (info, h))
+         if (gdop_relative_offset_ok (info, h, relocation))
            {
              r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22
                        ? R_SPARC_GOTDATA_HIX22
@@ -3178,7 +3205,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_SPARC_GOTDATA_OP:
-         if (SYMBOL_REFERENCES_LOCAL (info, h))
+         if (gdop_relative_offset_ok (info, h, relocation))
            {
              bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);