summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@gcc.gnu.org>2018-03-28 12:17:15 +0200
committerEric Botcazou <ebotcazou@gcc.gnu.org>2018-03-28 12:31:27 +0200
commit99181ccac0fc7d82e7dabb05dc7466e91f1645d3 (patch)
treec75e52cc92f5bc1c35a5832ef9db5fe020c1d137
parentf14da2782fd25511855048944aecee16864e73ea (diff)
downloadbinutils-gdb-99181ccac0fc7d82e7dabb05dc7466e91f1645d3.tar.gz
PR ld/22972 on SPARC.
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.
-rw-r--r--bfd/ChangeLog11
-rw-r--r--bfd/elfxx-sparc.c22
-rw-r--r--ld/ChangeLog9
-rw-r--r--ld/testsuite/ld-sparc/got-hidden32.s18
-rw-r--r--ld/testsuite/ld-sparc/got-hidden64.s18
-rw-r--r--ld/testsuite/ld-sparc/gotop-hidden.c13
-rw-r--r--ld/testsuite/ld-sparc/pass.out1
-rw-r--r--ld/testsuite/ld-sparc/sparc.exp29
8 files changed, 116 insertions, 5 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index b6b05ecf103..fcb953ab7e1 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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-26 H.J. Lu <hongjiu.lu@intel.com>
Backport from master branch
diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c
index bf4d4dc25c8..596d71ed882 100644
--- a/bfd/elfxx-sparc.c
+++ b/bfd/elfxx-sparc.c
@@ -692,9 +692,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;
@@ -1583,7 +1586,8 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
local_got_refcounts[r_symndx] += 1;
break;
}
- 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,
@@ -1620,7 +1624,13 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
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:
@@ -3159,12 +3169,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))
{
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 05223f4a534..430f58e61d4 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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-26 H.J. Lu <hongjiu.lu@intel.com>
Backport from master branch
diff --git a/ld/testsuite/ld-sparc/got-hidden32.s b/ld/testsuite/ld-sparc/got-hidden32.s
new file mode 100644
index 00000000000..cd1ecf2d947
--- /dev/null
+++ b/ld/testsuite/ld-sparc/got-hidden32.s
@@ -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
index 00000000000..50e75ca4525
--- /dev/null
+++ b/ld/testsuite/ld-sparc/got-hidden64.s
@@ -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
index 00000000000..d769c6ddc66
--- /dev/null
+++ b/ld/testsuite/ld-sparc/gotop-hidden.c
@@ -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
index 00000000000..7ef22e9a431
--- /dev/null
+++ b/ld/testsuite/ld-sparc/pass.out
@@ -0,0 +1 @@
+PASS
diff --git a/ld/testsuite/ld-sparc/sparc.exp b/ld/testsuite/ld-sparc/sparc.exp
index e8aa0c284c1..41aa2e68b2e 100644
--- a/ld/testsuite/ld-sparc/sparc.exp
+++ b/ld/testsuite/ld-sparc/sparc.exp
@@ -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" \
+ ] \
+ ]
+}