diff options
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 59 |
1 files changed, 40 insertions, 19 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 71a5d45..e095709 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -1531,7 +1531,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* Phony reloc to handle branch stubs. */ + /* Phony relocs to handle branch stubs. */ HOWTO (R_PPC_RELAX32, /* type */ 0, /* rightshift */ 0, /* size */ @@ -1546,6 +1546,20 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0, /* dst_mask */ FALSE), /* pcrel_offset */ + HOWTO (R_PPC_RELAX32PC, /* type */ + 0, /* rightshift */ + 0, /* size */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_RELAX32PC", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ 0, /* rightshift */ @@ -1627,7 +1641,7 @@ ppc_elf_install_value (bfd *abfd, switch (r_type) { case R_PPC_RELAX32: - /* Do stuff here. */ + case R_PPC_RELAX32PC: t0 = bfd_get_32 (abfd, hit_addr); t1 = bfd_get_32 (abfd, hit_addr + 4); @@ -1645,6 +1659,8 @@ ppc_elf_install_value (bfd *abfd, break; case R_PPC_REL24: + case R_PPC_LOCAL24PC: + case R_PPC_PLTREL24: t0 = bfd_get_32 (abfd, hit_addr); t0 &= ~0x3fffffc; t0 |= val & 0x3fffffc; @@ -1660,14 +1676,6 @@ ppc_elf_install_value (bfd *abfd, bfd_put_32 (abfd, t0, hit_addr); break; - case R_PPC_LOCAL24PC: - case R_PPC_PLTREL24: - t0 = bfd_get_32 (abfd, hit_addr); - t0 &= ~0x3fffffc; - t0 |= val & 0x3fffffc; - bfd_put_32 (abfd, t0, hit_addr); - break; - default: return bfd_reloc_notsupported; } @@ -1681,7 +1689,7 @@ static const bfd_byte shared_stub_entry[] = 0x7c, 0x08, 0x02, 0xa6, /* mflr 0 */ 0x42, 0x9f, 0x00, 0x05, /* bcl 20, 31, .Lxxx */ 0x7d, 0x68, 0x02, 0xa6, /* mflr 11 */ - 0x3d, 0x60, 0x00, 0x00, /* addis 11, 11, (xxx-.Lxxx)@ha */ + 0x3d, 0x6b, 0x00, 0x00, /* addis 11, 11, (xxx-.Lxxx)@ha */ 0x39, 0x6b, 0x00, 0x18, /* addi 11, 11, (xxx-.Lxxx)@l */ 0x7c, 0x08, 0x03, 0xa6, /* mtlr 0 */ 0x7d, 0x69, 0x03, 0xa6, /* mtctr 11 */ @@ -1908,26 +1916,39 @@ ppc_elf_relax_section (bfd *abfd, if (tsec == isec) continue; - /* Look for an existing fixup to this address. */ + /* Look for an existing fixup to this address. + ??? What if the existing fixup is for a non-pic stub, and the + new one requires a pic stub? This presumably could happen with + a static link and a mix of R_PPC_LOCAL24PC and R_PPC_REL24 + relocs to a symbol needing long branch stubs. + ??? Why do we require R_PPC_LOCAL24PC and branches to the plt + to have a shared branch stub? Shared branch stubs should only + be needed when info->shared. */ for (f = fixups; f ; f = f->next) if (f->tsec == tsec && f->toff == toff) break; if (f == NULL) { + const bfd_byte *stub; size_t size; + unsigned long stub_rtype; if (link_info->shared || tsec == ppc_info->plt || r_type == R_PPC_LOCAL24PC) { + stub = shared_stub_entry; size = sizeof (shared_stub_entry); insn_offset = 16; + stub_rtype = R_PPC_RELAX32PC; } else { + stub = stub_entry; size = sizeof (stub_entry); insn_offset = 4; + stub_rtype = R_PPC_RELAX32; } /* Resize the current section to make room for the new branch. */ @@ -1939,17 +1960,12 @@ ppc_elf_relax_section (bfd *abfd, isec->_cooked_size = amt; - if (link_info->shared - || tsec == ppc_info->plt - || r_type == R_PPC_LOCAL24PC) - memcpy (contents + trampoff, shared_stub_entry, size); - else - memcpy (contents + trampoff, stub_entry, size); + memcpy (contents + trampoff, stub, size); /* Hijack the old relocation. Since we need two relocations for this use a "composite" reloc. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_PPC_RELAX32); + stub_rtype); irel->r_offset = trampoff + insn_offset; /* Record the fixup so we don't do it again this section. */ @@ -5440,6 +5456,11 @@ ppc_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC_RELAX32PC: + relocation -= (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset - 4); + /* Fall thru */ case R_PPC_RELAX32: ppc_elf_install_value (output_bfd, contents + rel->r_offset, relocation + addend, r_type); |