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.
This commit is contained in:
David S. Miller
2011-10-19 00:32:25 +00:00
parent 01b701aae6
commit abd242a908
9 changed files with 103 additions and 27 deletions

View File

@@ -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

View File

@@ -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;
}