PR ld/22972 on SPARC.
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 28 Mar 2018 10:17:15 +0000 (12:17 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 28 Mar 2018 10:17:15 +0000 (12:17 +0200)
This is a regression for the corner case of a hidden symbol in a PIC/PIE
binary which is subject to both a new-style GOTDATA relocation and an
old-style GOT relocation.  In this case, depending  on the link order,
the R_SPARC_RELATIVE dynamic relocation for the GOT slot needed because
of the old-style relocation can be replaced with R_SPARC_NONE coming
from the GOTDATA relocation.

The fix simply records whether an old-style GOT relocation is seen for a
symbol and prevents the R_SPARC_NONE from being generated in this case.

bfd/
* elfxx-sparc.c (struct _bfd_sparc_elf_link_hash_entry): Add new flag
has_old_style_got_reloc.
(_bfd_sparc_elf_check_relocs) <GOT relocations>: Set it for old-style
relocations.  Fix a couple of long lines.
(_bfd_sparc_elf_relocate_section) <R_SPARC_GOTDATA_OP>: Do not generate
a R_SPARC_NONE for the GOT slot if the symbol is also subject to
old-style GOT relocations.
ld/
* testsuite/ld-sparc/sparc.exp: Add test for mixed GOTDATA/GOT relocs.
* testsuite/ld-sparc/gotop-hidden.c: New file.
* testsuite/ld-sparc/got-hidden32.s: Likewise.
* testsuite/ld-sparc/got-hidden64.s: Likewise.
* testsuite/ld-sparc/pass.out: Likewise.

bfd/ChangeLog
bfd/elfxx-sparc.c
ld/ChangeLog
ld/testsuite/ld-sparc/got-hidden32.s [new file with mode: 0644]
ld/testsuite/ld-sparc/got-hidden64.s [new file with mode: 0644]
ld/testsuite/ld-sparc/gotop-hidden.c [new file with mode: 0644]
ld/testsuite/ld-sparc/pass.out [new file with mode: 0644]
ld/testsuite/ld-sparc/sparc.exp

index 426561a..dd6ccab 100644 (file)
@@ -1,3 +1,14 @@
+2018-03-28  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR ld/22972
+       * elfxx-sparc.c (struct _bfd_sparc_elf_link_hash_entry): Add new flag
+       has_old_style_got_reloc.
+       (_bfd_sparc_elf_check_relocs) <GOT relocations>: Set it for old-style
+       relocations.  Fix a couple of long lines.
+       (_bfd_sparc_elf_relocate_section) <R_SPARC_GOTDATA_OP>: Do not generate
+       a R_SPARC_NONE for the GOT slot if the symbol is also subject to old-style
+       GOT relocations.
+
 2018-03-25  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/23000
index 849182f..81812af 100644 (file)
@@ -701,9 +701,12 @@ struct _bfd_sparc_elf_link_hash_entry
 #define GOT_TLS_IE      3
   unsigned char tls_type;
 
-    /* Symbol has GOT or PLT relocations.  */
+  /* Symbol has GOT or PLT relocations.  */
   unsigned int has_got_reloc : 1;
 
+  /* Symbol has old-style, non-relaxable GOT relocations.  */
+  unsigned int has_old_style_got_reloc : 1;
+
   /* Symbol has non-GOT/non-PLT relocations in text sections.  */
   unsigned int has_non_got_reloc : 1;
 
@@ -1569,11 +1572,12 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    && r_type != R_SPARC_GOTDATA_OP_LOX10)
                  local_got_refcounts[r_symndx] += 1;
 
-               old_tls_type = _bfd_sparc_elf_local_got_tls_type (abfd) [r_symndx];
+               old_tls_type
+                 = _bfd_sparc_elf_local_got_tls_type (abfd) [r_symndx];
              }
 
-           /* If a TLS symbol is accessed using IE at least once, there is no point
-              in using the dynamic model for it.  */
+           /* If a TLS symbol is accessed using IE at least once, there is no
+              point in using the dynamic model for it.  */
            if (old_tls_type != tls_type)
              {
                if (old_tls_type == GOT_UNKNOWN)
@@ -1603,7 +1607,13 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            return FALSE;
 
          if (eh != NULL)
-           eh->has_got_reloc = 1;
+           {
+             eh->has_got_reloc = 1;
+             if (r_type == R_SPARC_GOT10
+                 || r_type == R_SPARC_GOT13
+                 || r_type == R_SPARC_GOT22)
+               eh->has_old_style_got_reloc = 1;
+           }
          break;
 
        case R_SPARC_TLS_GD_CALL:
@@ -3138,12 +3148,14 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
              bfd_put_32 (output_bfd, relocation, contents + rel->r_offset);
 
              /* If the symbol is global but not dynamic, an .rela.* slot has
-                been allocated for it in the GOT so output R_SPARC_NONE here.
-                See also the handling of other GOT relocations just below.  */
+                been allocated for it in the GOT so output R_SPARC_NONE here,
+                if it isn't also subject to another, old-style GOT relocation.
+                See also the handling of these GOT relocations just below.  */
              if (h != NULL
                  && h->dynindx == -1
                  && !h->forced_local
                  && h->root.type != bfd_link_hash_undefweak
+                 && !eh->has_old_style_got_reloc
                  && (h->got.offset & 1) == 0
                  && bfd_link_pic (info))
                {
index dfdc648..5f34819 100644 (file)
@@ -1,3 +1,12 @@
+2018-03-28  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR ld/22972
+       * testsuite/ld-sparc/sparc.exp: Add test for mixed GOTDATA/GOT relocs.
+       * testsuite/ld-sparc/gotop-hidden.c: New file.
+       * testsuite/ld-sparc/got-hidden32.s: Likewise.
+       * testsuite/ld-sparc/got-hidden64.s: Likewise.
+       * testsuite/ld-sparc/pass.out: Likewise.
+
 2018-03-25  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/23000
diff --git a/ld/testsuite/ld-sparc/got-hidden32.s b/ld/testsuite/ld-sparc/got-hidden32.s
new file mode 100644 (file)
index 0000000..cd1ecf2
--- /dev/null
@@ -0,0 +1,18 @@
+       .text
+.LLGETPC0:
+       retl
+        add    %o7, %l7, %l7
+       .global foo
+       .type foo, #function
+       .proc   04
+foo:
+       save    %sp, -104, %sp
+       sethi   %hi(_GLOBAL_OFFSET_TABLE_-4), %l7
+       call    .LLGETPC0
+        add    %l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
+       sethi   %hi(var), %g1
+       or      %g1, %lo(var), %g1
+       ld      [%l7+%g1], %g1
+       ld      [%g1], %i0
+       ret
+        restore
diff --git a/ld/testsuite/ld-sparc/got-hidden64.s b/ld/testsuite/ld-sparc/got-hidden64.s
new file mode 100644 (file)
index 0000000..50e75ca
--- /dev/null
@@ -0,0 +1,18 @@
+       .text
+.LLGETPC0:
+       retl
+        add    %o7, %l7, %l7
+       .global foo
+       .type foo, #function
+       .proc   04
+foo:
+       save    %sp, -160, %sp
+       sethi   %hi(_GLOBAL_OFFSET_TABLE_-4), %l7
+       call    .LLGETPC0
+        add    %l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
+       sethi   %hi(var), %g1
+       or      %g1, %lo(var), %g1
+       ldx     [%l7+%g1], %g1
+       ld      [%g1], %i0
+       ret
+        restore
diff --git a/ld/testsuite/ld-sparc/gotop-hidden.c b/ld/testsuite/ld-sparc/gotop-hidden.c
new file mode 100644 (file)
index 0000000..d769c6d
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+extern unsigned int foo (void);
+
+__attribute__((visibility("hidden"))) unsigned int var = 0xdeadbeef;
+
+int main (void)
+{
+  if (var == foo ())
+    puts ("PASS");
+
+  return 0;
+}
diff --git a/ld/testsuite/ld-sparc/pass.out b/ld/testsuite/ld-sparc/pass.out
new file mode 100644 (file)
index 0000000..7ef22e9
--- /dev/null
@@ -0,0 +1 @@
+PASS
index e8aa0c2..41aa2e6 100644 (file)
@@ -146,8 +146,37 @@ set sparc64tests {
 if { ![istarget "sparc64-*-elf*"] } {
     run_ld_link_tests $sparctests
 }
+
 if { !([istarget "sparc-*-elf*"]
        || [istarget "sparc-sun-solaris2.5*"]
        || [istarget "sparc-sun-solaris2.6"]) } {
     run_ld_link_tests $sparc64tests
 }
+
+if { [istarget "sparc*-*-linux*"] && [isnative] } {
+    run_ld_link_exec_tests [list \
+       [list \
+           "32-bit: mixed GOTDATA/GOT relocations" \
+           "-pie -m32" \
+           "" \
+           { gotop-hidden.c got-hidden32.s } \
+           "gotop-hidden32" \
+           "pass.out" \
+           "-fPIE -m32" \
+       ] \
+    ]
+}
+
+if { [istarget "sparc64-*-linux*"] && [isnative] } {
+    run_ld_link_exec_tests [list \
+       [list \
+           "64-bit: mixed GOTDATA/GOT relocations" \
+           "-pie -m64" \
+           "" \
+           { gotop-hidden.c got-hidden64.s } \
+           "gotop-hidden64" \
+           "pass.out" \
+           "-fPIE -m64" \
+       ] \
+    ]
+}