diff options
author | David S. Miller <davem@redhat.com> | 2011-10-19 00:32:25 +0000 |
---|---|---|
committer | David S. Miller <davem@redhat.com> | 2011-10-19 00:32:25 +0000 |
commit | abd242a90836b535b2f98be634e16c70012a3c5d (patch) | |
tree | cc8a899c08c32ce0693497c6fc2f96264706d761 /gold/sparc.cc | |
parent | 01b701aae6a81fc07a867fc3746587000aaa8c50 (diff) | |
download | gdb-abd242a90836b535b2f98be634e16c70012a3c5d.zip gdb-abd242a90836b535b2f98be634e16c70012a3c5d.tar.gz gdb-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.cc | 17 |
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; |