ppc476 workaround for ld -r fixes

This fixes the glaring error that the ppc476 workaround wasn't
actually enabled for ld -r, and adjusts relocations to match moved
code.

bfd/
	* elf32-ppc.c (ppc_elf_relocate_section): Move relocs on insns
	patched for ppc476 workaround.  Reapply branch taken/not taken
	relocs.
ld/
	* emultempl/ppc32elf.em (ppc_after_open_output): Really enable
	ppc476 workaround for ld -r.
This commit is contained in:
Alan Modra
2014-02-17 16:51:25 +10:30
parent 98dc0167d6
commit 668e22e51b
4 changed files with 62 additions and 4 deletions

View File

@ -1,3 +1,9 @@
2014-02-17 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (ppc_elf_relocate_section): Move relocs on insns
patched for ppc476 workaround. Reapply branch taken/not taken
relocs.
2014-02-12 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (ppc_elf_relax_section): Don't build long-branch

View File

@ -9230,13 +9230,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
the word alone. */
is_data = FALSE;
lo = relocs;
hi = lo + input_section->reloc_count;
hi = relend;
rel = NULL;
while (lo < hi)
{
rel = lo + (hi - lo) / 2;
if (rel->r_offset < offset)
lo = rel + 1;
else if (rel->r_offset > offset)
else if (rel->r_offset > offset + 3)
hi = rel;
else
{
@ -9285,12 +9286,53 @@ ppc_elf_relocate_section (bfd *output_bfd,
patch_addr = (patch_addr + 15) & -16;
patch_off = patch_addr - start_addr;
bfd_put_32 (input_bfd, B + patch_off - offset, contents + offset);
if (rel != NULL
&& rel->r_offset >= offset
&& rel->r_offset < offset + 4)
{
/* If the insn we are patching had a reloc, adjust the
reloc r_offset so that the reloc applies to the moved
location. This matters for -r and --emit-relocs. */
if (rel + 1 != relend)
{
Elf_Internal_Rela tmp = *rel;
/* Keep the relocs sorted by r_offset. */
memmove (rel, rel + 1, (relend - (rel + 1)) * sizeof (*rel));
relend[-1] = tmp;
}
relend[-1].r_offset += patch_off - offset;
}
else
rel = NULL;
if ((insn & (0x3f << 26)) == (16u << 26) /* bc */
&& (insn & 2) == 0 /* relative */)
{
bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
delta += offset - patch_off;
if (info->relocatable && rel != NULL)
delta = 0;
if (!info->relocatable && rel != NULL)
{
enum elf_ppc_reloc_type r_type;
r_type = ELF32_R_TYPE (relend[-1].r_info);
if (r_type == R_PPC_REL14_BRTAKEN)
insn |= BRANCH_PREDICT_BIT;
else if (r_type == R_PPC_REL14_BRNTAKEN)
insn &= ~BRANCH_PREDICT_BIT;
else
BFD_ASSERT (r_type == R_PPC_REL14);
if ((r_type == R_PPC_REL14_BRTAKEN
|| r_type == R_PPC_REL14_BRNTAKEN)
&& delta + 0x8000 < 0x10000
&& (bfd_signed_vma) delta < 0)
insn ^= BRANCH_PREDICT_BIT;
}
if (delta + 0x8000 < 0x10000)
{
bfd_put_32 (input_bfd,
@ -9304,6 +9346,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
}
else
{
if (rel != NULL)
{
unsigned int r_sym = ELF32_R_SYM (relend[-1].r_info);
relend[-1].r_offset += 8;
relend[-1].r_info = ELF32_R_INFO (r_sym, R_PPC_REL24);
}
bfd_put_32 (input_bfd,
(insn & ~0xfffc) | 8,
contents + patch_off);

View File

@ -1,3 +1,8 @@
2014-02-17 Alan Modra <amodra@gmail.com>
* emultempl/ppc32elf.em (ppc_after_open_output): Really enable
ppc476 workaround for ld -r.
2014-02-12 Alan Modra <amodra@gmail.com>
* emultempl/ppc32elf.em (pagesize): New static var.

View File

@ -51,8 +51,6 @@ ppc_after_open_output (void)
if (pagesize == 0)
pagesize = config.commonpagesize;
params.pagesize_p2 = bfd_log2 (pagesize);
if (link_info.relocatable)
params.ppc476_workaround = 0;
ppc_elf_link_params (&link_info, &params);
}