aboutsummaryrefslogtreecommitdiff
path: root/gold/sparc.cc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@redhat.com>2011-10-19 00:32:25 +0000
committerDavid S. Miller <davem@redhat.com>2011-10-19 00:32:25 +0000
commitabd242a90836b535b2f98be634e16c70012a3c5d (patch)
treecc8a899c08c32ce0693497c6fc2f96264706d761 /gold/sparc.cc
parent01b701aae6a81fc07a867fc3746587000aaa8c50 (diff)
downloadbinutils-abd242a90836b535b2f98be634e16c70012a3c5d.zip
binutils-abd242a90836b535b2f98be634e16c70012a3c5d.tar.gz
binutils-abd242a90836b535b2f98be634e16c70012a3c5d.tar.bz2
Fix sparc TLS call relaxation when the delay slot sets up %o0.
bfd/ PR binutils/13301 * elfxx-sparc.c (sparc_elf_find_reloc_at_ofs): New function. (_bfd_sparc_elf_relocate_section): Always move the __tls_get_addr call delay slot instruction forward 4 bytes when performing relaxation. gold/ PR binutils/13301 * sparc.cc (Target_sparc::Relocate::reloc_adjust_addr_): New member to track relocation locations that have moved during TLS reloc optimizations. (Target_sparc::Relocate::Relocate): Initialize to NULL. (Target_sparc::Relocate::relocate): Adjust view down by 4 bytes if it matches reloc_adjust_addr_. (Target_sparc::Relocate::relocate_tls): Always move the __tls_get_addr call delay slot instruction forward 4 bytes when performing relaxation. ld/testsuite/ * ld-sparc/tlssunbin32.dd: Update for TLS call relaxation fix for PR 13301. * ld-sparc/tlssunbin64.dd: Likewise. * ld-sparc/tlssunpic32.dd: Likewise. * ld-sparc/tlssunpic64.dd: Likewise.
Diffstat (limited to 'gold/sparc.cc')
-rw-r--r--gold/sparc.cc17
1 files changed, 15 insertions, 2 deletions
diff --git a/gold/sparc.cc b/gold/sparc.cc
index 1d2cbad..12e1dee 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -265,7 +265,7 @@ class Target_sparc : public Sized_target<size, big_endian>
{
public:
Relocate()
- : ignore_gd_add_(false)
+ : ignore_gd_add_(false), reloc_adjust_addr_(NULL)
{ }
~Relocate()
@@ -302,6 +302,9 @@ class Target_sparc : public Sized_target<size, big_endian>
// Ignore the next relocation which should be R_SPARC_TLS_GD_ADD
bool ignore_gd_add_;
+
+ // If we hit a reloc at this view address, adjust it back by 4 bytes.
+ unsigned char *reloc_adjust_addr_;
};
// A class which returns the size required for a relocation type,
@@ -2622,6 +2625,8 @@ Target_sparc<size, big_endian>::Relocate::relocate(
return false;
}
}
+ if (this->reloc_adjust_addr_ == view)
+ view -= 4;
typedef Sparc_relocate_functions<size, big_endian> Reloc;
@@ -3101,7 +3106,15 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
wv += 1;
this->ignore_gd_add_ = true;
}
-
+ else
+ {
+ // Even if the delay slot isn't the TLS_GD_ADD
+ // instruction, we still have to handle the case
+ // where it sets up %o0 in some other way.
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ wv += 1;
+ this->reloc_adjust_addr_ = view + 4;
+ }
// call __tls_get_addr --> add %g7, %o0, %o0
elfcpp::Swap<32, true>::writeval(wv, 0x9001c008);
break;