aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c59
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);