summaryrefslogtreecommitdiff
path: root/bfd/coff64-rs6000.c
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@nildram.co.uk>2009-03-14 09:16:01 +0000
committerRichard Sandiford <rsandifo@nildram.co.uk>2009-03-14 09:16:01 +0000
commit7418827dfa922b359450db773635f402581451e4 (patch)
tree6f464f555b1c1ca311687418ec7903a6f96b8173 /bfd/coff64-rs6000.c
parent3ea66a83f25c40a8bd1d4afa36a9219a1757cd35 (diff)
downloadbinutils-redhat-7418827dfa922b359450db773635f402581451e4.tar.gz
bfd/
* coff-rs6000.c (xcoff_reloc_type_br): Make the branch absolute if the target is absolute. Fix comment typo. (xcoff_ppc_relocate_section): Remove FIXME. * coff64-rs6000.c (xcoff64_reloc_type_br): Make the branch absolute if the target is absolute. ld/testsuite/ * ld-powerpc/aix-abs-branch-1.im, ld-powerpc/aix-abs-branch-1.ex, ld-powerpc/aix-abs-branch-1.s, ld-powerpc/aix-abs-branch-1.dd: New test. * ld-powerpc/aix52.exp: Run it.
Diffstat (limited to 'bfd/coff64-rs6000.c')
-rw-r--r--bfd/coff64-rs6000.c45
1 files changed, 36 insertions, 9 deletions
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index 14489176e6..71a02c237b 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -1117,11 +1117,13 @@ xcoff64_reloc_type_br (input_bfd, input_section, output_bfd, rel, sym, howto,
bfd_byte *contents;
{
struct xcoff_link_hash_entry *h;
+ bfd_vma section_offset;
if (0 > rel->r_symndx)
return FALSE;
h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+ section_offset = rel->r_vaddr - input_section->vma;
/* If we see an R_BR or R_RBR reloc which is jumping to global
linkage code, and it is followed by an appropriate cror nop
@@ -1132,12 +1134,12 @@ xcoff64_reloc_type_br (input_bfd, input_section, output_bfd, rel, sym, howto,
cror. */
if (NULL != h
&& bfd_link_hash_defined == h->root.type
- && rel->r_vaddr - input_section->vma + 8 <= input_section->size)
+ && section_offset + 8 <= input_section->size)
{
bfd_byte *pnext;
unsigned long next;
- pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
+ pnext = contents + section_offset + 4;
next = bfd_get_32 (input_bfd, pnext);
/* The _ptrgl function is magic. It is used by the AIX compiler to call
@@ -1166,16 +1168,41 @@ xcoff64_reloc_type_br (input_bfd, input_section, output_bfd, rel, sym, howto,
howto->complain_on_overflow = complain_overflow_dont;
}
- howto->pc_relative = TRUE;
+ /* The original PC-relative relocation is biased by -r_vaddr, so adding
+ the value below will give the absolute target address. */
+ *relocation = val + addend + rel->r_vaddr;
+
howto->src_mask &= ~3;
howto->dst_mask = howto->src_mask;
- /* A PC relative reloc includes the section address. */
- addend += input_section->vma;
-
- *relocation = val + addend;
- *relocation -= (input_section->output_section->vma
- + input_section->output_offset);
+ if (h != NULL
+ && h->root.type == bfd_link_hash_defined
+ && bfd_is_abs_section (h->root.u.def.section)
+ && section_offset + 4 <= input_section->size)
+ {
+ bfd_byte *ptr;
+ bfd_vma insn;
+
+ /* Turn the relative branch into an absolute one by setting the
+ AA bit. */
+ ptr = contents + section_offset;
+ insn = bfd_get_32 (input_bfd, ptr);
+ insn |= 2;
+ bfd_put_32 (input_bfd, insn, ptr);
+
+ /* Make the howto absolute too. */
+ howto->pc_relative = FALSE;
+ howto->complain_on_overflow = complain_overflow_bitfield;
+ }
+ else
+ {
+ /* Use a PC-relative howto and subtract the instruction's address
+ from the target address we calculated above. */
+ howto->pc_relative = TRUE;
+ *relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + section_offset);
+ }
return TRUE;
}