aboutsummaryrefslogtreecommitdiff
path: root/bfd/coff64-rs6000.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/coff64-rs6000.c')
-rw-r--r--bfd/coff64-rs6000.c66
1 files changed, 63 insertions, 3 deletions
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index 95abbb9..2f8077a 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -778,10 +778,13 @@ xcoff64_reloc_type_br (bfd *input_bfd,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
- bfd_byte *contents)
+ bfd_byte *contents,
+ struct bfd_link_info *info)
{
struct xcoff_link_hash_entry *h;
bfd_vma section_offset;
+ struct xcoff_stub_hash_entry *stub_entry = NULL;
+ enum xcoff_stub_type stub_type;
if (0 > rel->r_symndx)
return false;
@@ -833,6 +836,27 @@ xcoff64_reloc_type_br (bfd *input_bfd,
howto->complain_on_overflow = complain_overflow_dont;
}
+ /* Check if a stub is needed. */
+ stub_type = bfd_xcoff_type_of_stub (input_section, rel, val, h);
+ if (stub_type != xcoff_stub_none)
+ {
+ asection *stub_csect;
+
+ stub_entry = bfd_xcoff_get_stub_entry (input_section, h, info);
+ if (stub_entry == NULL)
+ {
+ _bfd_error_handler (_("Unable to find the stub entry targeting %s"),
+ h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ stub_csect = stub_entry->hcsect->root.u.def.section;
+ val = (stub_entry->stub_offset
+ + stub_csect->output_section->vma
+ + stub_csect->output_offset);
+ }
+
/* 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;
@@ -1645,7 +1669,7 @@ xcoff64_ppc_relocate_section (bfd *output_bfd,
if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
|| !((*xcoff64_calculate_relocation[rel->r_type])
(input_bfd, input_section, output_bfd, rel, sym, &howto, val,
- addend, &relocation, contents)))
+ addend, &relocation, contents, info)))
return false;
/* address */
@@ -2386,12 +2410,32 @@ HOWTO (0, /* type */
MINUS_ONE, /* dst_mask */
false); /* pcrel_offset */
+/* Indirect call stub */
+static const unsigned long xcoff64_stub_indirect_call_code[4] =
+ {
+ 0xe9820000, /* ld r12,0(r2) */
+ 0xe80c0000, /* ld r0,0(r12) */
+ 0x7c0903a6, /* mtctr r0 */
+ 0x4e800420, /* bctr */
+ };
+
+/* Shared call stub */
+static const unsigned long xcoff64_stub_shared_call_code[6] =
+ {
+ 0xe9820000, /* ld r12,0(r2) */
+ 0xf8410028, /* std r2,40(r1) */
+ 0xe80c0000, /* ld r0,0(r12) */
+ 0xe84c0008, /* ld r2,8(r12) */
+ 0x7c0903a6, /* mtctr r0 */
+ 0x4e800420, /* bctr */
+ };
+
static const unsigned long xcoff64_glink_code[10] =
{
0xe9820000, /* ld r12,0(r2) */
0xf8410028, /* std r2,40(r1) */
0xe80c0000, /* ld r0,0(r12) */
- 0xe84c0008, /* ld r0,8(r12) */
+ 0xe84c0008, /* ld r2,8(r12) */
0x7c0903a6, /* mtctr r0 */
0x4e800420, /* bctr */
0x00000000, /* start of traceback table */
@@ -2495,6 +2539,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
/* rtinit. */
88, /* _xcoff_rtinit_size */
xcoff64_generate_rtinit,
+
+ /* Stub indirect call. */
+ &xcoff64_stub_indirect_call_code[0],
+ 16, /* _xcoff_stub_indirect_call_size */
+
+ /* Stub shared call. */
+ &xcoff64_stub_shared_call_code[0],
+ 24, /* _xcoff_stub_shared_call_size */
};
/* The transfer vector that leads the outside world to all of the above. */
@@ -2759,6 +2811,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_aix5_backend_data =
/* rtinit. */
88, /* _xcoff_rtinit_size */
xcoff64_generate_rtinit,
+
+ /* Stub indirect call. */
+ &xcoff64_stub_indirect_call_code[0],
+ 16, /* _xcoff_stub_indirect_call_size */
+
+ /* Stub shared call. */
+ &xcoff64_stub_shared_call_code[0],
+ 24, /* _xcoff_stub_shared_call_size */
};
/* The transfer vector that leads the outside world to all of the above. */