diff options
Diffstat (limited to 'bfd/coff64-rs6000.c')
-rw-r--r-- | bfd/coff64-rs6000.c | 66 |
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. */ |