aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elf32-ppc.c53
-rw-r--r--ld/ChangeLog5
-rw-r--r--ld/emultempl/ppc32elf.em2
4 files changed, 62 insertions, 4 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 39d9def..86f9d84 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index d8e6108..1c8724f 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -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);
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 9ab809e..38d81b0 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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.
diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
index 8de230a..f5a3a70 100644
--- a/ld/emultempl/ppc32elf.em
+++ b/ld/emultempl/ppc32elf.em
@@ -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);
}