From abd242a90836b535b2f98be634e16c70012a3c5d Mon Sep 17 00:00:00 2001 From: "David S. Miller" <davem@redhat.com> Date: Wed, 19 Oct 2011 00:32:25 +0000 Subject: 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. --- bfd/ChangeLog | 8 ++++++++ bfd/elfxx-sparc.c | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'bfd') diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8f9b9be..3a0c0eb 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2011-10-18 David S. Miller <davem@davemloft.net> + + 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. + 2011-10-17 Alan Modra <amodra@gmail.com> PR ld/12975 diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c index 438b7f5..9a15124 100644 --- a/bfd/elfxx-sparc.c +++ b/bfd/elfxx-sparc.c @@ -1830,6 +1830,20 @@ _bfd_sparc_elf_gc_mark_hook (asection *sec, return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } +static Elf_Internal_Rela * +sparc_elf_find_reloc_at_ofs (Elf_Internal_Rela *rel, + Elf_Internal_Rela *relend, + bfd_vma offset) +{ + while (rel < relend) + { + if (rel->r_offset == offset) + return rel; + rel++; + } + return NULL; +} + /* Update the got entry reference counts for the section being removed. */ bfd_boolean _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, @@ -3676,6 +3690,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, if (! info->shared || (r_type == R_SPARC_TLS_GD_CALL && tls_type == GOT_TLS_IE)) { + Elf_Internal_Rela *rel2; bfd_vma insn; if (!info->shared && (h == NULL || h->dynindx == -1)) @@ -3711,7 +3726,26 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, continue; } - bfd_put_32 (output_bfd, 0x9001c008, contents + rel->r_offset); + /* We cannot just overwrite the delay slot instruction, + as it might be what puts the %o0 argument to + __tls_get_addr into place. So we have to transpose + the delay slot with the add we patch in. */ + insn = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + bfd_put_32 (output_bfd, insn, + contents + rel->r_offset); + bfd_put_32 (output_bfd, 0x9001c008, + contents + rel->r_offset + 4); + + rel2 = rel; + while ((rel2 = sparc_elf_find_reloc_at_ofs (rel2 + 1, relend, + rel->r_offset + 4)) + != NULL) + { + /* If the instruction we moved has a relocation attached to + it, adjust the offset so that it will apply to the correct + instruction. */ + rel2->r_offset -= 4; + } continue; } -- cgit v1.1