aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c148
1 files changed, 143 insertions, 5 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 5da7230da38..36a01ee6f92 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -818,6 +818,35 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
0, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* Marker relocs on inline plt call instructions. */
+ HOWTO (R_PPC_PLTSEQ,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC_PLTSEQ", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PPC_PLTCALL,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC_PLTCALL", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* Computes the load module index of the load module that contains the
definition of its TLS sym. */
HOWTO (R_PPC_DTPMOD32,
@@ -3956,6 +3985,17 @@ is_branch_reloc (enum elf_ppc_reloc_type r_type)
|| r_type == R_PPC_VLE_REL24);
}
+/* Relocs on inline plt call sequence insns prior to the call. */
+
+static bfd_boolean
+is_plt_seq_reloc (enum elf_ppc_reloc_type r_type)
+{
+ return (r_type == R_PPC_PLT16_HA
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLTSEQ);
+}
+
static void
bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
{
@@ -4131,6 +4171,9 @@ ppc_elf_check_relocs (bfd *abfd,
return FALSE;
break;
+ case R_PPC_PLTSEQ:
+ break;
+
case R_PPC_GOT_TLSLD16:
case R_PPC_GOT_TLSLD16_LO:
case R_PPC_GOT_TLSLD16_HI:
@@ -4310,6 +4353,7 @@ ppc_elf_check_relocs (bfd *abfd,
ppc_elf_tdata (abfd)->makes_plt_call = 1;
/* Fall through */
+ case R_PPC_PLTCALL:
case R_PPC_PLT32:
case R_PPC_PLTREL32:
case R_PPC_PLT16_LO:
@@ -5437,6 +5481,40 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
case R_PPC_TLSGD:
case R_PPC_TLSLD:
+ if (rel + 1 < relend
+ && is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+ {
+ if (pass != 0
+ && ELF32_R_TYPE (rel[1].r_info) != R_PPC_PLTSEQ)
+ {
+ r_type = ELF32_R_TYPE (rel[1].r_info);
+ r_symndx = ELF32_R_SYM (rel[1].r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ struct elf_link_hash_entry **sym_hashes;
+
+ sym_hashes = elf_sym_hashes (ibfd);
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ if (h != NULL)
+ {
+ struct plt_entry *ent = NULL;
+ bfd_vma addend = 0;
+
+ if (bfd_link_pic (info))
+ addend = rel->r_addend;
+ ent = find_plt_ent (&h->plt.plist,
+ got2, addend);
+ if (ent != NULL
+ && ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
+ }
+ }
+ }
+ continue;
+ }
expecting_tls_get_addr = 2;
tls_set = 0;
tls_clear = 0;
@@ -5449,8 +5527,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
if (pass == 0)
{
if (!expecting_tls_get_addr
- || (expecting_tls_get_addr == 1
- && !sec->has_tls_get_addr_call))
+ || !sec->has_tls_get_addr_call)
continue;
if (rel + 1 < relend
@@ -5511,7 +5588,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
bfd_vma addend = 0;
if (bfd_link_pic (info)
- && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
+ && (ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24
+ || ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTCALL))
addend = rel[1].r_addend;
ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
got2, addend);
@@ -7062,6 +7140,7 @@ ppc_elf_relax_section (bfd *abfd,
case R_PPC_REL24:
case R_PPC_LOCAL24PC:
case R_PPC_PLTREL24:
+ case R_PPC_PLTCALL:
max_branch_offset = 1 << 25;
break;
@@ -7890,7 +7969,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
unsigned long r_symndx;
bfd_vma relocation;
bfd_vma branch_bit, from;
- bfd_boolean unresolved_reloc;
+ bfd_boolean unresolved_reloc, save_unresolved_reloc;
bfd_boolean warned;
unsigned int tls_type, tls_mask, tls_gd;
struct plt_entry **ifunc, **plt_list;
@@ -8160,6 +8239,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
unsigned int insn2;
bfd_vma offset = rel->r_offset;
+ if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+ {
+ bfd_put_32 (input_bfd, NOP, contents + offset);
+ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
+ break;
+ }
+
if ((tls_mask & TLS_TPRELGD) != 0)
{
/* IE */
@@ -8187,6 +8273,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
{
unsigned int insn2;
+ if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+ {
+ bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
+ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
+ break;
+ }
+
for (r_symndx = 0;
r_symndx < symtab_hdr->sh_info;
r_symndx++)
@@ -8230,7 +8323,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_REL14_BRNTAKEN:
{
- bfd_vma insn;
+ unsigned int insn;
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
insn &= ~BRANCH_PREDICT_BIT;
@@ -8464,6 +8557,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
}
addend = rel->r_addend;
+ save_unresolved_reloc = unresolved_reloc;
howto = NULL;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
@@ -9244,6 +9338,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
addend = 0;
break;
+ case R_PPC_PLTSEQ:
+ case R_PPC_PLTCALL:
case R_PPC_PLT16_LO:
case R_PPC_PLT16_HI:
case R_PPC_PLT16_HA:
@@ -9644,6 +9740,48 @@ ppc_elf_relocate_section (bfd *output_bfd,
goto copy_reloc;
}
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC_PLTCALL:
+ if (unresolved_reloc)
+ {
+ bfd_byte *p = contents + rel->r_offset;
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= 1;
+ bfd_put_32 (input_bfd, B | insn, p);
+ unresolved_reloc = save_unresolved_reloc;
+ r_type = R_PPC_REL24;
+ howto = ppc_elf_howto_table[r_type];
+ }
+ else if (htab->plt_type != PLT_NEW)
+ info->callbacks->einfo
+ (_("%P: %H: %s relocation unsupported for bss-plt\n"),
+ input_bfd, input_section, rel->r_offset,
+ howto->name);
+ break;
+
+ case R_PPC_PLTSEQ:
+ case R_PPC_PLT16_HA:
+ case R_PPC_PLT16_LO:
+ if (unresolved_reloc)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ bfd_put_32 (input_bfd, NOP, p);
+ unresolved_reloc = FALSE;
+ r_type = R_PPC_NONE;
+ howto = ppc_elf_howto_table[r_type];
+ }
+ else if (htab->plt_type != PLT_NEW)
+ info->callbacks->einfo
+ (_("%P: %H: %s relocation unsupported for bss-plt\n"),
+ input_bfd, input_section, rel->r_offset,
+ howto->name);
+ break;
+ }
+
/* Do any further special processing. */
switch (r_type)
{