aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog24
-rw-r--r--bfd/elf32-ppc.c148
-rw-r--r--bfd/elf64-ppc.c206
-rw-r--r--elfcpp/ChangeLog4
-rw-r--r--elfcpp/powerpc.h2
-rw-r--r--gold/ChangeLog8
-rw-r--r--gold/powerpc.cc65
-rw-r--r--include/ChangeLog5
-rw-r--r--include/elf/ppc.h4
-rw-r--r--include/elf/ppc64.h4
10 files changed, 424 insertions, 46 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 099d106..445eff0 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,29 @@
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.
(struct ppc_stub_hash_entry): Add symtype field.
(PLT_KEEP): Define.
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 5da7230..36a01ee 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)
{
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4ea6a9e..9472f7b 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -1336,6 +1336,8 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
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) */
@@ -1350,6 +1352,35 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
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,
@@ -4187,7 +4218,7 @@ struct ppc_link_hash_table
/* 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. */
@@ -5430,7 +5461,20 @@ is_branch_reloc (enum elf_ppc64_reloc_type r_type)
|| 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
@@ -5777,6 +5821,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* Fall through. */
case R_PPC64_REL24:
+ case R_PPC64_PLTCALL:
plt_list = ifunc;
if (h != NULL)
{
@@ -8583,6 +8628,33 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
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. */
@@ -8736,35 +8808,27 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
!= (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)
@@ -10504,7 +10568,9 @@ ppc_type_of_stub (asection *input_sec,
/* 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)
@@ -11911,7 +11977,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
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);
@@ -13721,7 +13788,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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;
@@ -14190,6 +14257,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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 */
@@ -14225,6 +14302,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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;
@@ -14416,6 +14503,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* 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
@@ -14429,6 +14517,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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
@@ -14461,8 +14555,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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
@@ -14656,6 +14753,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Set `addend'. */
tls_type = 0;
+ save_unresolved_reloc = unresolved_reloc;
switch (r_type)
{
default:
@@ -14914,8 +15012,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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)
@@ -15368,6 +15469,35 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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:
@@ -15377,12 +15507,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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:
diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog
index 776908f..7c4a514 100644
--- a/elfcpp/ChangeLog
+++ b/elfcpp/ChangeLog
@@ -1,3 +1,7 @@
+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
diff --git a/elfcpp/powerpc.h b/elfcpp/powerpc.h
index c4e993e..71de459 100644
--- a/elfcpp/powerpc.h
+++ b/elfcpp/powerpc.h
@@ -179,6 +179,8 @@ enum
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,
diff --git a/gold/ChangeLog b/gold/ChangeLog
index bb30237..4ae7f7c 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,13 @@
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.
(Target_powerpc::lplt_section): Associated accessor.
(Target_powerpc::plt_off): Handle local non-ifunc symbols.
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index c3f1b23..314eaa7 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -78,8 +78,10 @@ struct Stub_table_owner
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;
@@ -1211,7 +1213,10 @@ class Target_powerpc : public Sized_target<size, big_endian>
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()));
@@ -4651,7 +4656,8 @@ class Stub_table : public Output_relaxed_input_section
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)
@@ -4668,7 +4674,8 @@ class Stub_table : public Output_relaxed_input_section
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;
}
@@ -6569,6 +6576,8 @@ Target_powerpc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
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;
@@ -6706,6 +6715,8 @@ Target_powerpc<size, big_endian>::Scan::local(
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:
@@ -7266,6 +7277,8 @@ Target_powerpc<size, big_endian>::Scan::global(
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:
@@ -8495,6 +8508,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
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;
@@ -8513,14 +8530,22 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
// 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;
@@ -8536,6 +8561,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
: 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)))
{
@@ -8633,6 +8660,14 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
+ 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
@@ -8969,6 +9004,18 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
}
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
@@ -9498,6 +9545,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
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:
diff --git a/include/ChangeLog b/include/ChangeLog
index 167ba03..74e6a53 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+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
diff --git a/include/elf/ppc.h b/include/elf/ppc.h
index 3de200c..c48733e 100644
--- a/include/elf/ppc.h
+++ b/include/elf/ppc.h
@@ -134,6 +134,10 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
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)
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index 04a7432..501aebc 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -154,6 +154,10 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
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