+2018-04-09 Alan Modra <amodra@gmail.com>
+
+ * elf32-ppc.c (ppc_elf_howto_raw): Add PLTSEQ and PLTCALL howtos.
+ (is_plt_seq_reloc): New function.
+ (ppc_elf_check_relocs): Handle PLTSEQ and PLTCALL relocs.
+ (ppc_elf_tls_optimize): Handle inline plt call sequence.
+ (ppc_elf_relax_section): Handle PLTCALL reloc.
+ (ppc_elf_relocate_section): Nop out inline plt call sequence when
+ resolving locally.
+ * elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_PLTSEQ and
+ R_PPC64_PLTCALL entries. Comment R_PPC64_TOCSAVE.
+ (has_tls_get_addr_call): Correct comment.
+ (is_branch_reloc): Add PLTCALL.
+ (is_plt_seq_reloc): New function.
+ (ppc64_elf_check_relocs): Handle PLT16_LO_DS reloc. Set
+ has_tls_reloc for R_PPC64_TLSGD and R_PPC64_TLSLD. Create plt
+ entry for R_PPC64_PLTCALL.
+ (ppc64_elf_tls_optimize): Handle inline plt call sequence.
+ (ppc_type_of_stub): Handle PLTCALL reloc.
+ (toc_adjusting_stub_needed): Likewise.
+ (ppc64_elf_relocate_section): Set "can_plt_call" for PLTCALL
+ reloc insn. Nop out inline plt call sequence when resolving
+ locally. Handle __tls_get_addr inline plt call optimization.
+
2018-04-09 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define.
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,
|| 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)
{
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:
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:
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;
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
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);
case R_PPC_REL24:
case R_PPC_LOCAL24PC:
case R_PPC_PLTREL24:
+ case R_PPC_PLTCALL:
max_branch_offset = 1 << 25;
break;
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;
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 */
{
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++)
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;
}
addend = rel->r_addend;
+ save_unresolved_reloc = unresolved_reloc;
howto = NULL;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
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:
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)
{
0, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* Marker reloc for optimizing r2 save in prologue rather than on
+ each plt call stub. */
HOWTO (R_PPC64_TOCSAVE,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
0, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* Marker relocs on inline plt call instructions. */
+ HOWTO (R_PPC64_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_PPC64_PLTSEQ", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PPC64_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_PPC64_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_PPC64_DTPMOD64,
/* Nonzero if this section has TLS related relocations. */
#define has_tls_reloc sec_flg0
-/* Nonzero if this section has a call to __tls_get_addr. */
+/* Nonzero if this section has an old-style call to __tls_get_addr. */
#define has_tls_get_addr_call sec_flg1
/* Nonzero if this section has any toc or got relocs. */
|| r_type == R_PPC64_ADDR24
|| r_type == R_PPC64_ADDR14
|| r_type == R_PPC64_ADDR14_BRTAKEN
- || r_type == R_PPC64_ADDR14_BRNTAKEN);
+ || r_type == R_PPC64_ADDR14_BRNTAKEN
+ || r_type == R_PPC64_PLTCALL);
+}
+
+/* Relocs on inline plt call sequence insns prior to the call. */
+
+static bfd_boolean
+is_plt_seq_reloc (enum elf_ppc64_reloc_type r_type)
+{
+ return (r_type == R_PPC64_PLT16_HA
+ || r_type == R_PPC64_PLT16_HI
+ || r_type == R_PPC64_PLT16_LO
+ || r_type == R_PPC64_PLT16_LO_DS
+ || r_type == R_PPC64_PLTSEQ);
}
/* Look through the relocs for a section during the first phase, and
/* Fall through. */
case R_PPC64_REL24:
+ case R_PPC64_PLTCALL:
plt_list = ifunc;
if (h != NULL)
{
case R_PPC64_TLSGD:
case R_PPC64_TLSLD:
+ if (rel + 1 < relend
+ && is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+ {
+ if (pass != 0
+ && ELF64_R_TYPE (rel[1].r_info) != R_PPC64_PLTSEQ)
+ {
+ r_symndx = ELF64_R_SYM (rel[1].r_info);
+ if (!get_sym_h (&h, NULL, NULL, NULL, &locsyms,
+ r_symndx, ibfd))
+ goto err_free_rel;
+ if (h != NULL)
+ {
+ struct plt_entry *ent = NULL;
+
+ for (ent = h->plt.plist;
+ ent != NULL;
+ ent = ent->next)
+ if (ent->addend == rel[1].r_addend)
+ break;
+
+ if (ent != NULL
+ && ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
+ }
+ }
+ continue;
+ }
found_tls_get_addr_arg = 1;
/* Fall through. */
!= (TLS_TLS | TLS_MARK)))
continue;
- if (expecting_tls_get_addr && htab->tls_get_addr != NULL)
+ if (expecting_tls_get_addr)
{
- struct plt_entry *ent;
- for (ent = htab->tls_get_addr->elf.plt.plist;
- ent != NULL;
- ent = ent->next)
- if (ent->addend == 0)
- {
- if (ent->plt.refcount > 0)
- {
- ent->plt.refcount -= 1;
- expecting_tls_get_addr = 0;
- }
+ struct plt_entry *ent = NULL;
+
+ if (htab->tls_get_addr != NULL)
+ for (ent = htab->tls_get_addr->elf.plt.plist;
+ ent != NULL;
+ ent = ent->next)
+ if (ent->addend == 0)
break;
- }
- }
- if (expecting_tls_get_addr && htab->tls_get_addr_fd != NULL)
- {
- struct plt_entry *ent;
- for (ent = htab->tls_get_addr_fd->elf.plt.plist;
- ent != NULL;
- ent = ent->next)
- if (ent->addend == 0)
- {
- if (ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
+ if (ent == NULL && htab->tls_get_addr_fd != NULL)
+ for (ent = htab->tls_get_addr_fd->elf.plt.plist;
+ ent != NULL;
+ ent = ent->next)
+ if (ent->addend == 0)
break;
- }
+
+ if (ent != NULL
+ && ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
}
if (tls_clear == 0)
/* Determine if a long branch stub is needed. */
max_branch_offset = 1 << 25;
- if (r_type != R_PPC64_REL24)
+ if (r_type == R_PPC64_REL14
+ || r_type == R_PPC64_REL14_BRTAKEN
+ || r_type == R_PPC64_REL14_BRNTAKEN)
max_branch_offset = 1 << 15;
if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off)
if (r_type != R_PPC64_REL24
&& r_type != R_PPC64_REL14
&& r_type != R_PPC64_REL14_BRTAKEN
- && r_type != R_PPC64_REL14_BRNTAKEN)
+ && r_type != R_PPC64_REL14_BRNTAKEN
+ && r_type != R_PPC64_PLTCALL)
continue;
r_symndx = ELF64_R_SYM (rel->r_info);
unsigned char tls_mask, tls_gd, tls_type;
unsigned char sym_type;
bfd_vma relocation;
- bfd_boolean unresolved_reloc;
+ bfd_boolean unresolved_reloc, save_unresolved_reloc;
bfd_boolean warned;
enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest;
unsigned int insn;
unsigned int insn2;
bfd_vma offset = rel->r_offset;
+ if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+ {
+ bfd_put_32 (output_bfd, NOP, contents + offset);
+ rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+ break;
+ }
+
+ if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
+ bfd_put_32 (output_bfd, NOP, contents + offset + 4);
+
if ((tls_mask & TLS_TPRELGD) != 0)
{
/* IE */
unsigned int insn2;
bfd_vma offset = rel->r_offset;
+ if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+ {
+ bfd_put_32 (output_bfd, NOP, contents + offset);
+ rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+ break;
+ }
+
+ if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
+ bfd_put_32 (output_bfd, NOP, contents + offset + 4);
+
if (toc_symndx)
sec = local_sections[toc_symndx];
for (r_symndx = 0;
/* Fall through. */
case R_PPC64_REL24:
+ case R_PPC64_PLTCALL:
/* Calls to functions with a different TOC, such as calls to
shared objects, need to alter the TOC pointer. This is
done using a linkage stub. A REL24 branching to these
fdh = ppc_follow_link (h->oh);
stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel,
htab);
+ if (r_type == R_PPC64_PLTCALL
+ && stub_entry != NULL
+ && (stub_entry->stub_type == ppc_stub_plt_call
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save))
+ stub_entry = NULL;
+
if (stub_entry != NULL
&& (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save
nop = bfd_get_32 (input_bfd,
contents + rel->r_offset + 4);
- if (nop == NOP
- || nop == CROR_151515 || nop == CROR_313131)
+ if (nop == LD_R2_0R1 + STK_TOC (htab))
+ can_plt_call = TRUE;
+ else if (nop == NOP
+ || nop == CROR_151515
+ || nop == CROR_313131)
{
if (h != NULL
&& (h == htab->tls_get_addr_fd
/* Set `addend'. */
tls_type = 0;
+ save_unresolved_reloc = unresolved_reloc;
switch (r_type)
{
default:
case R_PPC64_PLT16_LO_DS:
case R_PPC64_PLT32:
case R_PPC64_PLT64:
+ case R_PPC64_PLTSEQ:
+ case R_PPC64_PLTCALL:
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
+ unresolved_reloc = TRUE;
{
struct plt_entry **plt_list = NULL;
if (h != NULL)
insn. */
break;
+ case R_PPC64_PLTCALL:
+ if (unresolved_reloc)
+ {
+ /* No plt entry. Make this into a direct call. */
+ bfd_byte *p = contents + rel->r_offset;
+ insn = bfd_get_32 (input_bfd, p);
+ insn &= 1;
+ bfd_put_32 (input_bfd, B_DOT | insn, p);
+ bfd_put_32 (input_bfd, NOP, p + 4);
+ unresolved_reloc = save_unresolved_reloc;
+ r_type = R_PPC64_REL24;
+ }
+ break;
+
+ case R_PPC64_PLTSEQ:
+ if (unresolved_reloc)
+ {
+ unresolved_reloc = FALSE;
+ goto nop_it;
+ }
+ break;
+
+ case R_PPC64_PLT16_HA:
+ if (unresolved_reloc)
+ {
+ unresolved_reloc = FALSE;
+ goto nop_it;
+ }
+ /* Fall through. */
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TLSGD16_HA:
case R_PPC64_GOT_TPREL16_HA:
if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
&& !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
{
- bfd_byte *p = contents + (rel->r_offset & ~3);
+ bfd_byte *p;
+ nop_it:
+ p = contents + (rel->r_offset & ~3);
bfd_put_32 (input_bfd, NOP, p);
goto copy_reloc;
}
break;
+ case R_PPC64_PLT16_LO:
+ case R_PPC64_PLT16_LO_DS:
+ if (unresolved_reloc)
+ {
+ unresolved_reloc = FALSE;
+ goto nop_it;
+ }
+ /* Fall through. */
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TPREL16_LO_DS:
+2018-04-09 Alan Modra <amodra@gmail.com>
+
+ * powerpc.h (R_POWERPC_PLTSEQ, R_POWERPC_PLTCALL): Define.
+
2018-03-28 Cary Coutant <ccoutant@gmail.com>
PR gold/22969
R_PPC64_REL24_NOTOC = 116,
R_PPC64_ADDR64_LOCAL = 117,
R_PPC64_ENTRY = 118,
+ R_POWERPC_PLTSEQ = 119,
+ R_POWERPC_PLTCALL = 120,
R_PPC_VLE_REL8 = 216,
R_PPC_VLE_REL15 = 217,
+2018-04-09 Alan Modra <amodra@gmail.com>
+
+ * powerpc.cc (Target_powerpc::Track_tls::maybe_skip_tls_get_addr_call):
+ Handle inline plt sequence relocs.
+ (Stub_table::Plt_stub_key::Plt_stub_key): Likewise.
+ (Target_powerpc::Scan::reloc_needs_plt_for_ifunc): Likewise.
+ (Target_powerpc::Relocate::relocate): Likewise.
+
2018-04-09 Alan Modra <amodra@gmail.com>
* powerpc.cc (Target_powerpc::lplt_): New variable.
const Output_section::Input_section* owner;
};
-inline bool
-is_branch_reloc(unsigned int r_type);
+inline bool is_branch_reloc(unsigned int);
+
+template<int size>
+inline bool is_plt16_reloc(unsigned int);
// Counter incremented on every Powerpc_relobj constructed.
static uint32_t object_id = 0;
unsigned int r_type, const Symbol* gsym)
{
bool is_tls_call = ((r_type == elfcpp::R_POWERPC_REL24
- || r_type == elfcpp::R_PPC_PLTREL24)
+ || r_type == elfcpp::R_PPC_PLTREL24
+ || is_plt16_reloc<size>(r_type)
+ || r_type == elfcpp::R_POWERPC_PLTSEQ
+ || r_type == elfcpp::R_POWERPC_PLTCALL)
&& gsym != NULL
&& (gsym == target->tls_get_addr()
|| gsym == target->tls_get_addr_opt()));
if (size != 32)
this->addend_ = addend;
else if (parameters->options().output_is_position_independent()
- && r_type == elfcpp::R_PPC_PLTREL24)
+ && (r_type == elfcpp::R_PPC_PLTREL24
+ || r_type == elfcpp::R_POWERPC_PLTCALL))
{
this->addend_ = addend;
if (this->addend_ >= 32768)
if (size != 32)
this->addend_ = addend;
else if (parameters->options().output_is_position_independent()
- && r_type == elfcpp::R_PPC_PLTREL24)
+ && (r_type == elfcpp::R_PPC_PLTREL24
+ || r_type == elfcpp::R_POWERPC_PLTCALL))
this->addend_ = addend;
}
case elfcpp::R_POWERPC_PLT16_HI:
case elfcpp::R_POWERPC_PLT16_HA:
case elfcpp::R_PPC64_PLT16_LO_DS:
+ case elfcpp::R_POWERPC_PLTSEQ:
+ case elfcpp::R_POWERPC_PLTCALL:
return true;
break;
case elfcpp::R_POWERPC_GNU_VTENTRY:
case elfcpp::R_POWERPC_TLS:
case elfcpp::R_PPC64_ENTRY:
+ case elfcpp::R_POWERPC_PLTSEQ:
+ case elfcpp::R_POWERPC_PLTCALL:
break;
case elfcpp::R_PPC64_TOC:
case elfcpp::R_PPC_LOCAL24PC:
case elfcpp::R_POWERPC_TLS:
case elfcpp::R_PPC64_ENTRY:
+ case elfcpp::R_POWERPC_PLTSEQ:
+ case elfcpp::R_POWERPC_PLTCALL:
break;
case elfcpp::R_PPC64_TOC:
Address address,
section_size_type view_size)
{
+ typedef Powerpc_relocate_functions<size, big_endian> Reloc;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn;
+ typedef typename elfcpp::Rela<size, big_endian> Reltype;
+
if (view == NULL)
return true;
// We have already complained.
break;
case Track_tls::SKIP:
+ if (is_plt16_reloc<size>(r_type)
+ || r_type == elfcpp::R_POWERPC_PLTSEQ)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+ }
+ else if (size == 64 && r_type == elfcpp::R_POWERPC_PLTCALL)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ elfcpp::Swap<32, big_endian>::writeval(iview + 1, nop);
+ }
return true;
case Track_tls::NORMAL:
break;
}
- typedef Powerpc_relocate_functions<size, big_endian> Reloc;
- typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn;
- typedef typename elfcpp::Rela<size, big_endian> Reltype;
// Offset from start of insn to d-field reloc.
const int d_offset = big_endian ? 2 : 0;
: object->local_has_plt_offset(r_sym));
if (has_plt_offset
&& !is_plt16_reloc<size>(r_type)
+ && r_type != elfcpp::R_POWERPC_PLTSEQ
+ && r_type != elfcpp::R_POWERPC_PLTCALL
&& (!psymval->is_ifunc_symbol()
|| Scan::reloc_needs_plt_for_ifunc(target, object, r_type, false)))
{
+ target->got_section()->g_o_t());
}
}
+ else if (!has_plt_offset
+ && (is_plt16_reloc<size>(r_type)
+ || r_type == elfcpp::R_POWERPC_PLTSEQ))
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
else if (r_type == elfcpp::R_POWERPC_GOT16
|| r_type == elfcpp::R_POWERPC_GOT16_LO
|| r_type == elfcpp::R_POWERPC_GOT16_HI
}
else if (!has_stub_value)
{
+ if (!has_plt_offset && r_type == elfcpp::R_POWERPC_PLTCALL)
+ {
+ // PLTCALL without plt entry => convert to direct call
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ insn = (insn & 1) | b;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ if (size == 32)
+ r_type = elfcpp::R_PPC_PLTREL24;
+ else
+ r_type = elfcpp::R_POWERPC_REL24;
+ }
Address addend = 0;
if (!(size == 32
&& (r_type == elfcpp::R_PPC_PLTREL24
case elfcpp::R_POWERPC_TLS:
case elfcpp::R_POWERPC_GNU_VTINHERIT:
case elfcpp::R_POWERPC_GNU_VTENTRY:
+ case elfcpp::R_POWERPC_PLTSEQ:
+ case elfcpp::R_POWERPC_PLTCALL:
break;
case elfcpp::R_PPC64_ADDR64:
+2018-04-09 Alan Modra <amodra@gmail.com>
+
+ * elf/ppc.h (R_PPC_PLTSEQ, R_PPC_PLTCALL): Define.
+ * elf/ppc64.h (R_PPC64_PLTSEQ, R_PPC64_PLTCALL): Define.
+
2018-03-28 Renlin Li <renlin.li@arm.com>
PR ld/22970
RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115)
RELOC_NUMBER (R_PPC_EMB_RELSDA, 116)
+/* Marker reloc for inline plt call insns. */
+ RELOC_NUMBER (R_PPC_PLTSEQ, 119)
+ RELOC_NUMBER (R_PPC_PLTCALL, 120)
+
/* PowerPC VLE relocations. */
RELOC_NUMBER (R_PPC_VLE_REL8, 216)
RELOC_NUMBER (R_PPC_VLE_REL15, 217)
RELOC_NUMBER (R_PPC64_ADDR64_LOCAL, 117)
RELOC_NUMBER (R_PPC64_ENTRY, 118)
+/* Marker reloc for inline plt call insns. */
+ RELOC_NUMBER (R_PPC64_PLTSEQ, 119)
+ RELOC_NUMBER (R_PPC64_PLTCALL, 120)
+
#ifndef RELOC_MACROS_GEN_FUNC
/* Relocation only used internally by ld. If you need to use these
reloc numbers, you can change them to some other unused value