summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog32
-rw-r--r--bfd/bfd-in2.h17
-rw-r--r--bfd/elf64-ppc.c409
-rw-r--r--bfd/libbfd.h17
-rw-r--r--bfd/reloc.c34
-rw-r--r--gas/ChangeLog20
-rw-r--r--gas/config/tc-ppc.c164
-rw-r--r--gas/config/tc-ppc.h8
-rw-r--r--gas/testsuite/gas/ppc/ppc.exp1
-rw-r--r--gas/testsuite/gas/ppc/prefix-reloc.d35
-rw-r--r--gas/testsuite/gas/ppc/prefix-reloc.s13
-rw-r--r--include/ChangeLog12
-rw-r--r--include/elf/ppc64.h24
13 files changed, 722 insertions, 64 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index aa0a38db3aa..9091df02942 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,35 @@
+2019-05-24 Alan Modra <amodra@gmail.com>
+
+ * reloc.c (BFD_RELOC_PPC64_D34, BFD_RELOC_PPC64_D34_LO),
+ (BFD_RELOC_PPC64_D34_HI30, BFD_RELOC_PPC64_D34_HA30),
+ (BFD_RELOC_PPC64_PCREL34, BFD_RELOC_PPC64_GOT_PCREL34),
+ (BFD_RELOC_PPC64_PLT_PCREL34),
+ (BFD_RELOC_PPC64_ADDR16_HIGHER34, BFD_RELOC_PPC64_ADDR16_HIGHERA34),
+ (BFD_RELOC_PPC64_ADDR16_HIGHEST34, BFD_RELOC_PPC64_ADDR16_HIGHESTA34),
+ (BFD_RELOC_PPC64_REL16_HIGHER34, BFD_RELOC_PPC64_REL16_HIGHERA34),
+ (BFD_RELOC_PPC64_REL16_HIGHEST34, BFD_RELOC_PPC64_REL16_HIGHESTA34),
+ (BFD_RELOC_PPC64_D28, BFD_RELOC_PPC64_PCREL28): New reloc enums.
+ * elf64-ppc.c (PNOP): Define.
+ (ppc64_elf_howto_raw): Add reloc howtos for new relocations.
+ (ppc64_elf_reloc_type_lookup): Translate new bfd reloc numbers.
+ (ppc64_elf_ha_reloc): Adjust addend for highera34 and highesta34
+ relocs.
+ (ppc64_elf_prefix_reloc): New function.
+ (struct ppc_link_hash_table): Add notoc_plt.
+ (is_branch_reloc): Add R_PPC64_PLTCALL_NOTOC.
+ (is_plt_seq_reloc): Add R_PPC64_PLT_PCREL34,
+ R_PPC64_PLT_PCREL34_NOTOC, and R_PPC64_PLTSEQ_NOTOC.
+ (ppc64_elf_check_relocs): Handle pcrel got and plt relocs. Set
+ has_pltcall for section on seeing R_PPC64_PLTCALL_NOTOC. Handle
+ possible need for dynamic relocs on non-pcrel powerxx relocs.
+ (dec_dynrel_count): Handle non-pcrel powerxx relocs.
+ (ppc64_elf_inline_plt): Handle R_PPC64_PLTCALL_NOTOC.
+ (toc_adjusting_stub_needed): Likewise.
+ (ppc64_elf_tls_optimize): Handle R_PPC64_PLTSEQ_NOTOC.
+ (ppc64_elf_relocate_section): Handle new powerxx relocs.
+ * bfd-in2.h: Regenerate.
+ * libbfd.h: Regenerate.
+
2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com>
* config.bfd (targ_cpu): Process bpf-*-none only if BFD64.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 03d644c61e2..450c7b7fb18 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3498,6 +3498,23 @@ instruction. */
BFD_RELOC_PPC64_ADDR64_LOCAL,
BFD_RELOC_PPC64_ENTRY,
BFD_RELOC_PPC64_REL24_NOTOC,
+ BFD_RELOC_PPC64_D34,
+ BFD_RELOC_PPC64_D34_LO,
+ BFD_RELOC_PPC64_D34_HI30,
+ BFD_RELOC_PPC64_D34_HA30,
+ BFD_RELOC_PPC64_PCREL34,
+ BFD_RELOC_PPC64_GOT_PCREL34,
+ BFD_RELOC_PPC64_PLT_PCREL34,
+ BFD_RELOC_PPC64_ADDR16_HIGHER34,
+ BFD_RELOC_PPC64_ADDR16_HIGHERA34,
+ BFD_RELOC_PPC64_ADDR16_HIGHEST34,
+ BFD_RELOC_PPC64_ADDR16_HIGHESTA34,
+ BFD_RELOC_PPC64_REL16_HIGHER34,
+ BFD_RELOC_PPC64_REL16_HIGHERA34,
+ BFD_RELOC_PPC64_REL16_HIGHEST34,
+ BFD_RELOC_PPC64_REL16_HIGHESTA34,
+ BFD_RELOC_PPC64_D28,
+ BFD_RELOC_PPC64_PCREL28,
/* PowerPC and PowerPC64 thread-local storage relocations. */
BFD_RELOC_PPC_TLS,
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4eb0153dfba..ad47bed372d 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -51,6 +51,8 @@ static bfd_reloc_status_type ppc64_elf_toc_ha_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type ppc64_elf_toc64_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type ppc64_elf_prefix_reloc
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type ppc64_elf_unhandled_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_vma opd_entry_value
@@ -197,6 +199,7 @@ static bfd_vma opd_entry_value
#define SLDI_R12_R12_32 0x799c07c6 /* sldi %r12,%r12,32 */
#define LDX_R12_R11_R12 0x7d8b602a /* ldx %r12,%r11,%r12 */
#define ADD_R12_R11_R12 0x7d8b6214 /* add %r12,%r11,%r12 */
+#define PNOP 0x0700000000000000ULL
/* __glink_PLTresolve stub instructions. We enter with the index in R0. */
#define GLINK_PLTRESOLVE_SIZE(htab) \
@@ -878,6 +881,69 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
HOW (R_PPC64_ADDR64_LOCAL, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
bfd_elf_generic_reloc),
+ HOW (R_PPC64_PLTSEQ_NOTOC, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC64_PLTCALL_NOTOC, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC64_PCREL_OPT, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC64_D34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+ ppc64_elf_prefix_reloc),
+
+ HOW (R_PPC64_D34_LO, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, dont,
+ ppc64_elf_prefix_reloc),
+
+ HOW (R_PPC64_D34_HI30, 4, 34, 0x3ffff0000ffffULL, 34, FALSE, dont,
+ ppc64_elf_prefix_reloc),
+
+ HOW (R_PPC64_D34_HA30, 4, 34, 0x3ffff0000ffffULL, 34, FALSE, dont,
+ ppc64_elf_prefix_reloc),
+
+ HOW (R_PPC64_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_prefix_reloc),
+
+ HOW (R_PPC64_GOT_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_PLT_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_PLT_PCREL34_NOTOC, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_ADDR16_HIGHER34, 1, 16, 0xffff, 34, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC64_ADDR16_HIGHERA34, 1, 16, 0xffff, 34, FALSE, dont,
+ ppc64_elf_ha_reloc),
+
+ HOW (R_PPC64_ADDR16_HIGHEST34, 1, 16, 0xffff, 50, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC64_ADDR16_HIGHESTA34, 1, 16, 0xffff, 50, FALSE, dont,
+ ppc64_elf_ha_reloc),
+
+ HOW (R_PPC64_REL16_HIGHER34, 1, 16, 0xffff, 34, TRUE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC64_REL16_HIGHERA34, 1, 16, 0xffff, 34, TRUE, dont,
+ ppc64_elf_ha_reloc),
+
+ HOW (R_PPC64_REL16_HIGHEST34, 1, 16, 0xffff, 50, TRUE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC64_REL16_HIGHESTA34, 1, 16, 0xffff, 50, TRUE, dont,
+ ppc64_elf_ha_reloc),
+
+ HOW (R_PPC64_D28, 4, 28, 0xfff0000ffffULL, 0, FALSE, signed,
+ ppc64_elf_prefix_reloc),
+
+ HOW (R_PPC64_PCREL28, 4, 28, 0xfff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_prefix_reloc),
+
/* GNU extension to record C++ vtable hierarchy. */
HOW (R_PPC64_GNU_VTINHERIT, 0, 0, 0, 0, FALSE, dont,
NULL),
@@ -1167,6 +1233,40 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
break;
case BFD_RELOC_PPC64_ADDR64_LOCAL: r = R_PPC64_ADDR64_LOCAL;
break;
+ case BFD_RELOC_PPC64_D34: r = R_PPC64_D34;
+ break;
+ case BFD_RELOC_PPC64_D34_LO: r = R_PPC64_D34_LO;
+ break;
+ case BFD_RELOC_PPC64_D34_HI30: r = R_PPC64_D34_HI30;
+ break;
+ case BFD_RELOC_PPC64_D34_HA30: r = R_PPC64_D34_HA30;
+ break;
+ case BFD_RELOC_PPC64_PCREL34: r = R_PPC64_PCREL34;
+ break;
+ case BFD_RELOC_PPC64_GOT_PCREL34: r = R_PPC64_GOT_PCREL34;
+ break;
+ case BFD_RELOC_PPC64_PLT_PCREL34: r = R_PPC64_PLT_PCREL34;
+ break;
+ case BFD_RELOC_PPC64_ADDR16_HIGHER34: r = R_PPC64_ADDR16_HIGHER34;
+ break;
+ case BFD_RELOC_PPC64_ADDR16_HIGHERA34: r = R_PPC64_ADDR16_HIGHERA34;
+ break;
+ case BFD_RELOC_PPC64_ADDR16_HIGHEST34: r = R_PPC64_ADDR16_HIGHEST34;
+ break;
+ case BFD_RELOC_PPC64_ADDR16_HIGHESTA34: r = R_PPC64_ADDR16_HIGHESTA34;
+ break;
+ case BFD_RELOC_PPC64_REL16_HIGHER34: r = R_PPC64_REL16_HIGHER34;
+ break;
+ case BFD_RELOC_PPC64_REL16_HIGHERA34: r = R_PPC64_REL16_HIGHERA34;
+ break;
+ case BFD_RELOC_PPC64_REL16_HIGHEST34: r = R_PPC64_REL16_HIGHEST34;
+ break;
+ case BFD_RELOC_PPC64_REL16_HIGHESTA34: r = R_PPC64_REL16_HIGHESTA34;
+ break;
+ case BFD_RELOC_PPC64_D28: r = R_PPC64_D28;
+ break;
+ case BFD_RELOC_PPC64_PCREL28: r = R_PPC64_PCREL28;
+ break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT;
break;
case BFD_RELOC_VTABLE_ENTRY: r = R_PPC64_GNU_VTENTRY;
@@ -1243,11 +1343,17 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
- /* Adjust the addend for sign extension of the low 16 bits.
- We won't actually be using the low 16 bits, so trashing them
+ /* Adjust the addend for sign extension of the low 16 (or 34) bits.
+ We won't actually be using the low bits, so trashing them
doesn't matter. */
- reloc_entry->addend += 0x8000;
r_type = reloc_entry->howto->type;
+ if (r_type == R_PPC64_ADDR16_HIGHERA34
+ || r_type == R_PPC64_ADDR16_HIGHESTA34
+ || r_type == R_PPC64_REL16_HIGHERA34
+ || r_type == R_PPC64_REL16_HIGHESTA34)
+ reloc_entry->addend += 1ULL << 33;
+ else
+ reloc_entry->addend += 1U << 15;
if (r_type != R_PPC64_REL16DX_HA)
return bfd_reloc_continue;
@@ -1493,6 +1599,48 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
}
static bfd_reloc_status_type
+ppc64_elf_prefix_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+ void *data, asection *input_section,
+ bfd *output_bfd, char **error_message)
+{
+ uint64_t insn;
+ bfd_vma targ;
+
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+ insn <<= 32;
+ insn |= bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address + 4);
+
+ targ = (symbol->section->output_section->vma
+ + symbol->section->output_offset
+ + reloc_entry->addend);
+ if (!bfd_is_com_section (symbol->section))
+ targ += symbol->value;
+ if (reloc_entry->howto->type == R_PPC64_D34_HA30)
+ targ += 1ULL << 33;
+ if (reloc_entry->howto->pc_relative)
+ {
+ bfd_vma from = (reloc_entry->address
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ targ -=from;
+ }
+ targ >>= reloc_entry->howto->rightshift;
+ insn &= ~reloc_entry->howto->dst_mask;
+ insn |= ((targ << 16) | (targ & 0xffff)) & reloc_entry->howto->dst_mask;
+ bfd_put_32 (abfd, insn >> 32, (bfd_byte *) data + reloc_entry->address);
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address + 4);
+ if (reloc_entry->howto->complain_on_overflow == complain_overflow_signed
+ && (targ + (1ULL << (reloc_entry->howto->bitsize - 1))
+ >= 1ULL << reloc_entry->howto->bitsize))
+ return bfd_reloc_overflow;
+ return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section,
bfd *output_bfd, char **error_message)
@@ -2981,6 +3129,9 @@ struct ppc_link_hash_table
/* Whether plt calls for ELFv2 localentry:0 funcs have been optimized. */
unsigned int has_plt_localentry0:1;
+ /* Whether calls are made via the PLT from NOTOC functions. */
+ unsigned int notoc_plt:1;
+
/* Incremented every time we size stubs. */
unsigned int stub_iteration;
@@ -4235,7 +4386,8 @@ is_branch_reloc (enum elf_ppc64_reloc_type r_type)
|| r_type == R_PPC64_ADDR14
|| r_type == R_PPC64_ADDR14_BRTAKEN
|| r_type == R_PPC64_ADDR14_BRNTAKEN
- || r_type == R_PPC64_PLTCALL);
+ || r_type == R_PPC64_PLTCALL
+ || r_type == R_PPC64_PLTCALL_NOTOC);
}
/* Relocs on inline plt call sequence insns prior to the call. */
@@ -4247,7 +4399,10 @@ is_plt_seq_reloc (enum elf_ppc64_reloc_type r_type)
|| r_type == R_PPC64_PLT16_HI
|| r_type == R_PPC64_PLT16_LO
|| r_type == R_PPC64_PLT16_LO_DS
- || r_type == R_PPC64_PLTSEQ);
+ || r_type == R_PPC64_PLT_PCREL34
+ || r_type == R_PPC64_PLT_PCREL34_NOTOC
+ || r_type == R_PPC64_PLTSEQ
+ || r_type == R_PPC64_PLTSEQ_NOTOC);
}
/* Look through the relocs for a section during the first phase, and
@@ -4302,6 +4457,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
struct plt_entry **ifunc, **plt_list;
+ bfd_vma sym_addend;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
@@ -4317,6 +4473,24 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
tls_type = 0;
ifunc = NULL;
+ r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ default:
+ /* Somewhat foolishly, because the ABIs don't specifically
+ allow it, ppc64 gas and ld support GOT and PLT relocs
+ with non-zero addends where the addend results in
+ sym+addend being stored in the GOT or PLT entry. This
+ can't be supported for pcrel relocs because the addend is
+ used to specify the pcrel offset. */
+ sym_addend = rel->r_addend;
+ break;
+ case R_PPC64_GOT_PCREL34:
+ case R_PPC64_PLT_PCREL34:
+ case R_PPC64_PLT_PCREL34_NOTOC:
+ sym_addend = 0;
+ break;
+ }
if (h != NULL)
{
if (h->type == STT_GNU_IFUNC)
@@ -4335,14 +4509,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- rel->r_addend,
+ sym_addend,
NON_GOT | PLT_IFUNC);
if (ifunc == NULL)
return FALSE;
}
}
- r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
case R_PPC64_TLSGD:
@@ -4353,7 +4526,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK;
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- rel->r_addend,
+ sym_addend,
NON_GOT | TLS_TLS | TLS_MARK))
return FALSE;
sec->has_tls_reloc = 1;
@@ -4401,6 +4574,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT16:
case R_PPC64_GOT16_HI:
case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT_PCREL34:
dogot:
/* This symbol requires a global offset table entry. */
sec->has_toc_reloc = 1;
@@ -4426,7 +4600,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
eh = (struct ppc_link_hash_entry *) h;
for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend
+ if (ent->addend == sym_addend
&& ent->owner == abfd
&& ent->tls_type == tls_type)
break;
@@ -4437,7 +4611,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (ent == NULL)
return FALSE;
ent->next = eh->elf.got.glist;
- ent->addend = rel->r_addend;
+ ent->addend = sym_addend;
ent->owner = abfd;
ent->tls_type = tls_type;
ent->is_indirect = FALSE;
@@ -4450,14 +4624,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
else
/* This is a global offset table entry for a local symbol. */
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- rel->r_addend, tls_type))
+ sym_addend, tls_type))
return FALSE;
/* We may also need a plt entry if the symbol turns out to be
an ifunc. */
if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
{
- if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
+ if (!update_plt_info (abfd, &h->plt.plist, sym_addend))
return FALSE;
}
break;
@@ -4466,6 +4640,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_PLT16_HI:
case R_PPC64_PLT16_LO:
case R_PPC64_PLT16_LO_DS:
+ case R_PPC64_PLT_PCREL34:
+ case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PLT32:
case R_PPC64_PLT64:
/* This symbol requires a procedure linkage table entry. */
@@ -4481,9 +4657,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
if (plt_list == NULL)
plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- rel->r_addend,
+ sym_addend,
NON_GOT | PLT_KEEP);
- if (!update_plt_info (abfd, plt_list, rel->r_addend))
+ if (!update_plt_info (abfd, plt_list, sym_addend))
return FALSE;
break;
@@ -4521,6 +4697,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_REL16_HIGHERA:
case R_PPC64_REL16_HIGHEST:
case R_PPC64_REL16_HIGHESTA:
+ case R_PPC64_REL16_HIGHER34:
+ case R_PPC64_REL16_HIGHERA34:
+ case R_PPC64_REL16_HIGHEST34:
+ case R_PPC64_REL16_HIGHESTA34:
case R_PPC64_REL16DX_HA:
break;
@@ -4603,6 +4783,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
goto rel24;
case R_PPC64_PLTCALL:
+ case R_PPC64_PLTCALL_NOTOC:
ppc64_elf_section_data (sec)->has_pltcall = 1;
/* Fall through. */
@@ -4636,7 +4817,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* We may need a .plt entry if the function this reloc
refers to is in a shared lib. */
if (plt_list
- && !update_plt_info (abfd, plt_list, rel->r_addend))
+ && !update_plt_info (abfd, plt_list, sym_addend))
return FALSE;
break;
@@ -4680,7 +4861,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- rel->r_addend, tls_type))
+ sym_addend, tls_type))
return FALSE;
ppc64_sec = ppc64_elf_section_data (sec);
@@ -4702,7 +4883,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
BFD_ASSERT (rel->r_offset % 8 == 0);
ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
- ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
+ ppc64_sec->u.toc.add[rel->r_offset / 8] = sym_addend;
/* Mark the second slot of a GD or LD entry.
-1 to indicate GD and -2 to indicate LD. */
@@ -4750,12 +4931,21 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_ADDR16_HIGHESTA:
case R_PPC64_ADDR16_LO:
case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_D34:
+ case R_PPC64_D34_LO:
+ case R_PPC64_D34_HI30:
+ case R_PPC64_D34_HA30:
+ case R_PPC64_ADDR16_HIGHER34:
+ case R_PPC64_ADDR16_HIGHERA34:
+ case R_PPC64_ADDR16_HIGHEST34:
+ case R_PPC64_ADDR16_HIGHESTA34:
+ case R_PPC64_D28:
if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
&& rel->r_addend == 0)
{
/* We may need a .plt entry if this reloc refers to a
function in a shared lib. */
- if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
+ if (!update_plt_info (abfd, &h->plt.plist, 0))
return FALSE;
h->pointer_equality_needed = 1;
}
@@ -6562,6 +6752,15 @@ dec_dynrel_count (bfd_vma r_info,
case R_PPC64_UADDR32:
case R_PPC64_UADDR64:
case R_PPC64_TOC:
+ case R_PPC64_D34:
+ case R_PPC64_D34_LO:
+ case R_PPC64_D34_HI30:
+ case R_PPC64_D34_HA30:
+ case R_PPC64_ADDR16_HIGHER34:
+ case R_PPC64_ADDR16_HIGHERA34:
+ case R_PPC64_ADDR16_HIGHEST34:
+ case R_PPC64_ADDR16_HIGHESTA34:
+ case R_PPC64_D28:
break;
}
@@ -7167,7 +7366,8 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
unsigned char *tls_maskp;
r_type = ELF64_R_TYPE (rel->r_info);
- if (r_type != R_PPC64_PLTCALL)
+ if (r_type != R_PPC64_PLTCALL
+ && r_type != R_PPC64_PLTCALL_NOTOC)
continue;
r_symndx = ELF64_R_SYM (rel->r_info);
@@ -7195,7 +7395,11 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
from = (rel->r_offset
+ sec->output_offset
+ sec->output_section->vma);
- if (to - from + limit < 2 * limit)
+ if (to - from + limit < 2 * limit
+ && !(r_type == R_PPC64_PLTCALL_NOTOC
+ && (((h ? h->other : sym->st_other)
+ & STO_PPC64_LOCAL_MASK)
+ != 1 << STO_PPC64_LOCAL_BIT)))
*tls_maskp &= ~PLT_KEEP;
}
}
@@ -7574,7 +7778,9 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
{
if (pass != 0
&& (ELF64_R_TYPE (rel[1].r_info)
- != R_PPC64_PLTSEQ))
+ != R_PPC64_PLTSEQ)
+ && (ELF64_R_TYPE (rel[1].r_info)
+ != R_PPC64_PLTSEQ_NOTOC))
{
r_symndx = ELF64_R_SYM (rel[1].r_info);
if (!get_sym_h (&h, NULL, NULL, NULL, &locsyms,
@@ -11631,7 +11837,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
&& r_type != R_PPC64_REL14
&& r_type != R_PPC64_REL14_BRTAKEN
&& r_type != R_PPC64_REL14_BRNTAKEN
- && r_type != R_PPC64_PLTCALL)
+ && r_type != R_PPC64_PLTCALL
+ && r_type != R_PPC64_PLTCALL_NOTOC)
continue;
r_symndx = ELF64_R_SYM (rel->r_info);
@@ -14030,10 +14237,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
{
unsigned int insn2;
bfd_vma offset = rel->r_offset;
+ enum elf_ppc64_reloc_type r_type1 = ELF64_R_TYPE (rel[1].r_info);
- if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+ if (is_plt_seq_reloc (r_type1))
{
bfd_put_32 (output_bfd, NOP, contents + offset);
+ if (r_type1 == R_PPC64_PLT_PCREL34
+ || r_type1 == R_PPC64_PLT_PCREL34_NOTOC)
+ bfd_put_32 (output_bfd, NOP, contents + offset + 4);
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
break;
}
@@ -14075,10 +14286,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
{
unsigned int insn2;
bfd_vma offset = rel->r_offset;
+ enum elf_ppc64_reloc_type r_type1 = ELF64_R_TYPE (rel[1].r_info);
- if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+ if (is_plt_seq_reloc (r_type1))
{
bfd_put_32 (output_bfd, NOP, contents + offset);
+ if (r_type1 == R_PPC64_PLT_PCREL34
+ || r_type1 == R_PPC64_PLT_PCREL34_NOTOC)
+ bfd_put_32 (output_bfd, NOP, contents + offset + 4);
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
break;
}
@@ -14279,6 +14494,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
case R_PPC64_PLTCALL:
+ case R_PPC64_PLTCALL_NOTOC:
/* 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
@@ -14292,7 +14508,8 @@ 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
+ if ((r_type == R_PPC64_PLTCALL
+ || r_type == R_PPC64_PLTCALL_NOTOC)
&& stub_entry != NULL
&& stub_entry->stub_type >= ppc_stub_plt_call
&& stub_entry->stub_type <= ppc_stub_plt_call_both)
@@ -14522,6 +14739,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|| stub_entry->stub_type == ppc_stub_plt_call_both)
&& r_type == R_PPC64_REL24_NOTOC)
relocation += 4;
+
+ if (r_type == R_PPC64_REL24_NOTOC
+ && (stub_entry->stub_type == ppc_stub_plt_call_notoc
+ || stub_entry->stub_type == ppc_stub_plt_call_both))
+ htab->notoc_plt = 1;
}
if (insn != 0)
@@ -14665,6 +14887,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT16_HA:
case R_PPC64_GOT16_DS:
case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_GOT_PCREL34:
dogot:
{
/* Relocation is to the entry for this symbol in the global
@@ -14674,6 +14897,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
bfd_vma off;
unsigned long indx = 0;
struct got_entry *ent;
+ bfd_vma sym_addend = orig_rel.r_addend;
+
+ if (r_type == R_PPC64_GOT_PCREL34)
+ sym_addend = 0;
if (tls_type == (TLS_TLS | TLS_LD)
&& (h == NULL
@@ -14707,7 +14934,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == orig_rel.r_addend
+ if (ent->addend == sym_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
@@ -14764,7 +14991,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
outrel.r_offset = (got->output_section->vma
+ got->output_offset
+ off);
- outrel.r_addend = addend;
+ outrel.r_addend = sym_addend;
if (tls_type & (TLS_LD | TLS_GD))
{
outrel.r_addend = 0;
@@ -14777,7 +15004,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
outrel.r_offset += 8;
- outrel.r_addend = addend;
+ outrel.r_addend = sym_addend;
outrel.r_info
= ELF64_R_INFO (indx, R_PPC64_DTPREL64);
}
@@ -14823,7 +15050,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
emitting a reloc. */
else
{
- relocation += addend;
+ relocation += sym_addend;
if (tls_type != 0)
{
if (htab->elf.tls_sec == NULL)
@@ -14854,7 +15081,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
abort ();
relocation = got->output_section->vma + got->output_offset + off;
- addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
+ if (r_type != R_PPC64_GOT_PCREL34)
+ addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
}
break;
@@ -14862,10 +15090,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_PLT16_HI:
case R_PPC64_PLT16_LO:
case R_PPC64_PLT16_LO_DS:
+ case R_PPC64_PLT_PCREL34:
+ case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PLT32:
case R_PPC64_PLT64:
case R_PPC64_PLTSEQ:
+ case R_PPC64_PLTSEQ_NOTOC:
case R_PPC64_PLTCALL:
+ case R_PPC64_PLTCALL_NOTOC:
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
unresolved_reloc = TRUE;
@@ -14882,10 +15114,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (plt_list)
{
struct plt_entry *ent;
+ bfd_vma sym_addend = orig_rel.r_addend;
+
+ if (r_type == R_PPC64_PLT_PCREL34
+ || r_type == R_PPC64_PLT_PCREL34_NOTOC)
+ sym_addend = 0;
for (ent = *plt_list; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1
- && ent->addend == orig_rel.r_addend)
+ && ent->addend == sym_addend)
{
asection *plt;
bfd_vma got;
@@ -14914,7 +15151,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
+ htab->sec_info[input_section->id].toc_off);
relocation -= got;
}
- addend = 0;
+ if (r_type != R_PPC64_PLT_PCREL34
+ && r_type != R_PPC64_PLT_PCREL34_NOTOC)
+ addend = 0;
unresolved_reloc = FALSE;
break;
}
@@ -14969,14 +15208,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_REL16_HIGHERA:
case R_PPC64_REL16_HIGHEST:
case R_PPC64_REL16_HIGHESTA:
+ case R_PPC64_REL16_HIGHER34:
+ case R_PPC64_REL16_HIGHERA34:
+ case R_PPC64_REL16_HIGHEST34:
+ case R_PPC64_REL16_HIGHESTA34:
case R_PPC64_REL16DX_HA:
- break;
-
case R_PPC64_REL14:
case R_PPC64_REL14_BRNTAKEN:
case R_PPC64_REL14_BRTAKEN:
case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
+ case R_PPC64_PCREL34:
+ case R_PPC64_PCREL28:
break;
case R_PPC64_TPREL16:
@@ -15071,12 +15314,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_ADDR16_HIGHESTA:
case R_PPC64_ADDR16_LO:
case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_HIGHER34:
+ case R_PPC64_ADDR16_HIGHERA34:
+ case R_PPC64_ADDR16_HIGHEST34:
+ case R_PPC64_ADDR16_HIGHESTA34:
case R_PPC64_ADDR24:
case R_PPC64_ADDR32:
case R_PPC64_ADDR64:
case R_PPC64_UADDR16:
case R_PPC64_UADDR32:
case R_PPC64_UADDR64:
+ case R_PPC64_D34:
+ case R_PPC64_D34_LO:
+ case R_PPC64_D34_HI30:
+ case R_PPC64_D34_HA30:
+ case R_PPC64_D28:
dodyn:
if ((input_section->flags & SEC_ALLOC) == 0)
break;
@@ -15328,6 +15580,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
insn. */
break;
+ case R_PPC64_PLTCALL_NOTOC:
+ if (!unresolved_reloc)
+ htab->notoc_plt = 1;
+ /* Fall through. */
case R_PPC64_PLTCALL:
if (unresolved_reloc)
{
@@ -15336,12 +15592,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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);
+ if (r_type == R_PPC64_PLTCALL)
+ bfd_put_32 (input_bfd, NOP, p + 4);
unresolved_reloc = save_unresolved_reloc;
r_type = R_PPC64_REL24;
}
break;
+ case R_PPC64_PLTSEQ_NOTOC:
case R_PPC64_PLTSEQ:
if (unresolved_reloc)
{
@@ -15350,6 +15608,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
break;
+ case R_PPC64_PLT_PCREL34_NOTOC:
+ if (!unresolved_reloc)
+ htab->notoc_plt = 1;
+ /* Fall through. */
+ case R_PPC64_PLT_PCREL34:
+ if (unresolved_reloc)
+ {
+ bfd_byte *p = contents + rel->r_offset;
+ bfd_put_32 (input_bfd, PNOP >> 32, p);
+ bfd_put_32 (input_bfd, PNOP, p + 4);
+ unresolved_reloc = FALSE;
+ goto copy_reloc;
+ }
+ break;
+
case R_PPC64_PLT16_HA:
if (unresolved_reloc)
{
@@ -15488,6 +15761,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
addend += 0x8000;
break;
+ case R_PPC64_D34_HA30:
+ case R_PPC64_ADDR16_HIGHERA34:
+ case R_PPC64_ADDR16_HIGHESTA34:
+ case R_PPC64_REL16_HIGHERA34:
+ case R_PPC64_REL16_HIGHESTA34:
+ if (sec != NULL)
+ addend += 1ULL << 33;
+ break;
+
case R_PPC64_ADDR16_DS:
case R_PPC64_ADDR16_LO_DS:
case R_PPC64_GOT16_DS:
@@ -15583,9 +15865,50 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
}
- if (r_type == R_PPC64_REL16DX_HA)
+ switch (r_type)
{
- /* Split field reloc isn't handled by _bfd_final_link_relocate. */
+ /* Split field relocs aren't handled by _bfd_final_link_relocate. */
+ case R_PPC64_D34:
+ case R_PPC64_D34_LO:
+ case R_PPC64_D34_HI30:
+ case R_PPC64_D34_HA30:
+ case R_PPC64_PCREL34:
+ case R_PPC64_GOT_PCREL34:
+ case R_PPC64_PLT_PCREL34:
+ case R_PPC64_PLT_PCREL34_NOTOC:
+ case R_PPC64_D28:
+ case R_PPC64_PCREL28:
+ if (rel->r_offset + 8 > input_section->size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ uint64_t pinsn;
+
+ relocation += addend;
+ if (howto->pc_relative)
+ relocation -= (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ relocation >>= howto->rightshift;
+
+ pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+
+ pinsn &= ~howto->dst_mask;
+ pinsn |= (((relocation << 16) | (relocation & 0xffff))
+ & howto->dst_mask);
+ bfd_put_32 (input_bfd, pinsn >> 32, contents + rel->r_offset);
+ bfd_put_32 (input_bfd, pinsn, contents + rel->r_offset + 4);
+ r = bfd_reloc_ok;
+ if (howto->complain_on_overflow == complain_overflow_signed
+ && (relocation + (1ULL << (howto->bitsize - 1))
+ >= 1ULL << howto->bitsize))
+ r = bfd_reloc_overflow;
+ }
+ break;
+
+ case R_PPC64_REL16DX_HA:
if (rel->r_offset + 4 > input_section->size)
r = bfd_reloc_outofrange;
else
@@ -15603,10 +15926,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (relocation + 0x8000 > 0xffff)
r = bfd_reloc_overflow;
}
+ break;
+
+ default:
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, addend);
}
- else
- r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
- rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
@@ -15884,7 +16210,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
break;
case DT_PPC64_OPT:
- if (htab->do_multi_toc && htab->multi_toc_needed)
+ if ((htab->do_multi_toc && htab->multi_toc_needed)
+ || htab->notoc_plt)
dyn.d_un.d_val |= PPC64_OPT_MULTI_TOC;
if (htab->has_plt_localentry0)
dyn.d_un.d_val |= PPC64_OPT_LOCALENTRY;
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index da52a2b0982..ff6e0eaef44 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1476,6 +1476,23 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC64_ADDR64_LOCAL",
"BFD_RELOC_PPC64_ENTRY",
"BFD_RELOC_PPC64_REL24_NOTOC",
+ "BFD_RELOC_PPC64_D34",
+ "BFD_RELOC_PPC64_D34_LO",
+ "BFD_RELOC_PPC64_D34_HI30",
+ "BFD_RELOC_PPC64_D34_HA30",
+ "BFD_RELOC_PPC64_PCREL34",
+ "BFD_RELOC_PPC64_GOT_PCREL34",
+ "BFD_RELOC_PPC64_PLT_PCREL34",
+ "BFD_RELOC_PPC64_ADDR16_HIGHER34",
+ "BFD_RELOC_PPC64_ADDR16_HIGHERA34",
+ "BFD_RELOC_PPC64_ADDR16_HIGHEST34",
+ "BFD_RELOC_PPC64_ADDR16_HIGHESTA34",
+ "BFD_RELOC_PPC64_REL16_HIGHER34",
+ "BFD_RELOC_PPC64_REL16_HIGHERA34",
+ "BFD_RELOC_PPC64_REL16_HIGHEST34",
+ "BFD_RELOC_PPC64_REL16_HIGHESTA34",
+ "BFD_RELOC_PPC64_D28",
+ "BFD_RELOC_PPC64_PCREL28",
"BFD_RELOC_PPC_TLS",
"BFD_RELOC_PPC_TLSGD",
"BFD_RELOC_PPC_TLSLD",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 8f0263e3549..266e775fa4e 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2878,6 +2878,40 @@ ENUMX
BFD_RELOC_PPC64_ENTRY
ENUMX
BFD_RELOC_PPC64_REL24_NOTOC
+ENUMX
+ BFD_RELOC_PPC64_D34
+ENUMX
+ BFD_RELOC_PPC64_D34_LO
+ENUMX
+ BFD_RELOC_PPC64_D34_HI30
+ENUMX
+ BFD_RELOC_PPC64_D34_HA30
+ENUMX
+ BFD_RELOC_PPC64_PCREL34
+ENUMX
+ BFD_RELOC_PPC64_GOT_PCREL34
+ENUMX
+ BFD_RELOC_PPC64_PLT_PCREL34
+ENUMX
+ BFD_RELOC_PPC64_ADDR16_HIGHER34
+ENUMX
+ BFD_RELOC_PPC64_ADDR16_HIGHERA34
+ENUMX
+ BFD_RELOC_PPC64_ADDR16_HIGHEST34
+ENUMX
+ BFD_RELOC_PPC64_ADDR16_HIGHESTA34
+ENUMX
+ BFD_RELOC_PPC64_REL16_HIGHER34
+ENUMX
+ BFD_RELOC_PPC64_REL16_HIGHERA34
+ENUMX
+ BFD_RELOC_PPC64_REL16_HIGHEST34
+ENUMX
+ BFD_RELOC_PPC64_REL16_HIGHESTA34
+ENUMX
+ BFD_RELOC_PPC64_D28
+ENUMX
+ BFD_RELOC_PPC64_PCREL28
ENUMDOC
Power(rs6000) and PowerPC relocations.
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 2d05746753f..1caa4785dac 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,23 @@
+2019-05-24 Alan Modra <amodra@gmail.com>
+
+ * config/tc-ppc.c (ppc_elf_suffix): Support @pcrel, @got@pcrel,
+ @plt@pcrel, @higher34, @highera34, @highest34, and @highesta34.
+ (fixup_size): Handle new powerxx relocs.
+ (md_assemble): Warn for @pcrel on non-prefix insns.
+ Accept @l, @h and @ha on prefix insns, and infer reloc without
+ any @ suffix. Translate powerxx relocs to suit DQ and DS field
+ instructions. Include operand tests as well as opcode test to
+ translate BFD_RELOC_HI16_S to BFD_RELOC_PPC_16DX_HA.
+ (ppc_fix_adjustable): Return false for pcrel GOT and PLT relocs.
+ (md_apply_fix): Handle new powerxx relocs.
+ * config/tc-ppc.h (TC_FORCE_RELOCATION_SUB_LOCAL): Accept
+ BFD_RELOC_PPC64_ADDR16_HIGHER34, BFD_RELOC_PPC64_ADDR16_HIGHERA34,
+ BFD_RELOC_PPC64_ADDR16_HIGHEST34, BFD_RELOC_PPC64_ADDR16_HIGHESTA34,
+ BFD_RELOC_PPC64_D34, and BFD_RELOC_PPC64_D28.
+ * testsuite/gas/ppc/prefix-reloc.d,
+ * testsuite/gas/ppc/prefix-reloc.s: New test.
+ * testsuite/gas/ppc/ppc.exp: Run it.
+
2019-05-24 Peter Bergner <bergner@linux.ibm.com>
Alan Modra <amodra@gmail.com>
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 4026c722939..64ff149b215 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -2151,6 +2151,13 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST),
MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA),
MAP64 ("notoc", BFD_RELOC_PPC64_REL24_NOTOC),
+ MAP64 ("pcrel", BFD_RELOC_PPC64_PCREL34),
+ MAP64 ("got@pcrel", BFD_RELOC_PPC64_GOT_PCREL34),
+ MAP64 ("plt@pcrel", BFD_RELOC_PPC64_PLT_PCREL34),
+ MAP64 ("higher34", BFD_RELOC_PPC64_ADDR16_HIGHER34),
+ MAP64 ("highera34", BFD_RELOC_PPC64_ADDR16_HIGHERA34),
+ MAP64 ("highest34", BFD_RELOC_PPC64_ADDR16_HIGHEST34),
+ MAP64 ("highesta34", BFD_RELOC_PPC64_ADDR16_HIGHESTA34),
{ (char *) 0, 0, 0, 0, BFD_RELOC_NONE }
};
@@ -2931,6 +2938,10 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_PPC64_ADDR16_DS:
case BFD_RELOC_PPC64_ADDR16_HIGH:
case BFD_RELOC_PPC64_ADDR16_HIGHA:
+ case BFD_RELOC_PPC64_ADDR16_HIGHER34:
+ case BFD_RELOC_PPC64_ADDR16_HIGHERA34:
+ case BFD_RELOC_PPC64_ADDR16_HIGHEST34:
+ case BFD_RELOC_PPC64_ADDR16_HIGHESTA34:
case BFD_RELOC_PPC64_ADDR16_LO_DS:
case BFD_RELOC_PPC64_DTPREL16_DS:
case BFD_RELOC_PPC64_DTPREL16_HIGH:
@@ -3018,9 +3029,13 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_PPC64_REL16_HIGH:
case BFD_RELOC_PPC64_REL16_HIGHA:
case BFD_RELOC_PPC64_REL16_HIGHER:
+ case BFD_RELOC_PPC64_REL16_HIGHER34:
case BFD_RELOC_PPC64_REL16_HIGHERA:
+ case BFD_RELOC_PPC64_REL16_HIGHERA34:
case BFD_RELOC_PPC64_REL16_HIGHEST:
+ case BFD_RELOC_PPC64_REL16_HIGHEST34:
case BFD_RELOC_PPC64_REL16_HIGHESTA:
+ case BFD_RELOC_PPC64_REL16_HIGHESTA34:
#ifdef OBJ_XCOFF
case BFD_RELOC_PPC_B16:
#endif
@@ -3100,12 +3115,21 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_64:
case BFD_RELOC_64_PLTOFF:
case BFD_RELOC_PPC64_ADDR64_LOCAL:
+ case BFD_RELOC_PPC64_D28:
+ case BFD_RELOC_PPC64_D34:
+ case BFD_RELOC_PPC64_D34_LO:
+ case BFD_RELOC_PPC64_D34_HI30:
+ case BFD_RELOC_PPC64_D34_HA30:
case BFD_RELOC_PPC64_TOC:
size = 8;
break;
case BFD_RELOC_64_PCREL:
case BFD_RELOC_64_PLT_PCREL:
+ case BFD_RELOC_PPC64_GOT_PCREL34:
+ case BFD_RELOC_PPC64_PCREL28:
+ case BFD_RELOC_PPC64_PCREL34:
+ case BFD_RELOC_PPC64_PLT_PCREL34:
size = 8;
pcrel = TRUE;
break;
@@ -3665,24 +3689,47 @@ md_assemble (char *str)
reloc = BFD_RELOC_PPC_TPREL16;
break;
- case BFD_RELOC_LO16:
- if ((operand->bitm | 0xf) != 0xffff
- || operand->shift != 0
+ case BFD_RELOC_PPC64_PCREL34:
+ if (operand->bitm == 0xfffffffULL)
+ {
+ reloc = BFD_RELOC_PPC64_PCREL28;
+ break;
+ }
+ /* Fall through. */
+ case BFD_RELOC_PPC64_GOT_PCREL34:
+ case BFD_RELOC_PPC64_PLT_PCREL34:
+ if (operand->bitm != 0x3ffffffffULL
|| (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
+ as_warn (_("%s unsupported on this instruction"), "@pcrel");
+ break;
+
+ case BFD_RELOC_LO16:
+ if (operand->bitm == 0x3ffffffffULL
+ && (operand->flags & PPC_OPERAND_NEGATIVE) == 0)
+ reloc = BFD_RELOC_PPC64_D34_LO;
+ else if ((operand->bitm | 0xf) != 0xffff
+ || operand->shift != 0
+ || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
as_warn (_("%s unsupported on this instruction"), "@l");
break;
case BFD_RELOC_HI16:
- if (operand->bitm != 0xffff
- || operand->shift != 0
- || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
+ if (operand->bitm == 0x3ffffffffULL
+ && (operand->flags & PPC_OPERAND_NEGATIVE) == 0)
+ reloc = BFD_RELOC_PPC64_D34_HI30;
+ else if (operand->bitm != 0xffff
+ || operand->shift != 0
+ || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
as_warn (_("%s unsupported on this instruction"), "@h");
break;
case BFD_RELOC_HI16_S:
- if (operand->bitm == 0xffff
- && operand->shift == (int) PPC_OPSHIFT_INV
- && opcode->opcode == (19 << 26) + (2 << 1))
+ if (operand->bitm == 0x3ffffffffULL
+ && (operand->flags & PPC_OPERAND_NEGATIVE) == 0)
+ reloc = BFD_RELOC_PPC64_D34_HA30;
+ else if (operand->bitm == 0xffff
+ && operand->shift == (int) PPC_OPSHIFT_INV
+ && opcode->opcode == (19 << 26) + (2 << 1))
/* addpcis. */
reloc = BFD_RELOC_PPC_16DX_HA;
else if (operand->bitm != 0xffff
@@ -3738,6 +3785,10 @@ md_assemble (char *str)
}
#endif
}
+ else if (operand->bitm == 0x3ffffffffULL)
+ reloc = BFD_RELOC_PPC64_D34;
+ else if (operand->bitm == 0xfffffffULL)
+ reloc = BFD_RELOC_PPC64_D28;
/* For the absolute forms of branches, convert the PC
relative form back into the absolute. */
@@ -3787,53 +3838,69 @@ md_assemble (char *str)
case BFD_RELOC_16:
reloc = BFD_RELOC_PPC64_ADDR16_DS;
break;
+
case BFD_RELOC_LO16:
reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
break;
+
case BFD_RELOC_16_GOTOFF:
reloc = BFD_RELOC_PPC64_GOT16_DS;
break;
+
case BFD_RELOC_LO16_GOTOFF:
reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
break;
+
case BFD_RELOC_LO16_PLTOFF:
reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
break;
+
case BFD_RELOC_16_BASEREL:
reloc = BFD_RELOC_PPC64_SECTOFF_DS;
break;
+
case BFD_RELOC_LO16_BASEREL:
reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
break;
+
case BFD_RELOC_PPC_TOC16:
reloc = BFD_RELOC_PPC64_TOC16_DS;
break;
+
case BFD_RELOC_PPC64_TOC16_LO:
reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
break;
+
case BFD_RELOC_PPC64_PLTGOT16:
reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
break;
+
case BFD_RELOC_PPC64_PLTGOT16_LO:
reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
break;
+
case BFD_RELOC_PPC_DTPREL16:
reloc = BFD_RELOC_PPC64_DTPREL16_DS;
break;
+
case BFD_RELOC_PPC_DTPREL16_LO:
reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
break;
+
case BFD_RELOC_PPC_TPREL16:
reloc = BFD_RELOC_PPC64_TPREL16_DS;
break;
+
case BFD_RELOC_PPC_TPREL16_LO:
reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
break;
+
case BFD_RELOC_PPC_GOT_DTPREL16:
case BFD_RELOC_PPC_GOT_DTPREL16_LO:
case BFD_RELOC_PPC_GOT_TPREL16:
case BFD_RELOC_PPC_GOT_TPREL16_LO:
break;
+
default:
as_bad (_("unsupported relocation for DS offset field"));
break;
@@ -6903,6 +6970,7 @@ ppc_fix_adjustable (fixS *fix)
&& fix->fx_r_type != BFD_RELOC_PPC64_GOT16_LO_DS
&& fix->fx_r_type != BFD_RELOC_16_GOT_PCREL
&& fix->fx_r_type != BFD_RELOC_32_GOTOFF
+ && fix->fx_r_type != BFD_RELOC_PPC64_GOT_PCREL34
&& fix->fx_r_type != BFD_RELOC_24_PLT_PCREL
&& fix->fx_r_type != BFD_RELOC_32_PLTOFF
&& fix->fx_r_type != BFD_RELOC_32_PLT_PCREL
@@ -6912,6 +6980,7 @@ ppc_fix_adjustable (fixS *fix)
&& fix->fx_r_type != BFD_RELOC_64_PLTOFF
&& fix->fx_r_type != BFD_RELOC_64_PLT_PCREL
&& fix->fx_r_type != BFD_RELOC_PPC64_PLT16_LO_DS
+ && fix->fx_r_type != BFD_RELOC_PPC64_PLT_PCREL34
&& fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16
&& fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_LO
&& fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_HI
@@ -7120,10 +7189,34 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHESTA;
break;
+ case BFD_RELOC_PPC64_ADDR16_HIGHER34:
+ fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHER34;
+ break;
+
+ case BFD_RELOC_PPC64_ADDR16_HIGHERA34:
+ fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHERA34;
+ break;
+
+ case BFD_RELOC_PPC64_ADDR16_HIGHEST34:
+ fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHEST34;
+ break;
+
+ case BFD_RELOC_PPC64_ADDR16_HIGHESTA34:
+ fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHESTA34;
+ break;
+
case BFD_RELOC_PPC_16DX_HA:
fixP->fx_r_type = BFD_RELOC_PPC_REL16DX_HA;
break;
+ case BFD_RELOC_PPC64_D34:
+ fixP->fx_r_type = BFD_RELOC_PPC64_PCREL34;
+ break;
+
+ case BFD_RELOC_PPC64_D28:
+ fixP->fx_r_type = BFD_RELOC_PPC64_PCREL28;
+ break;
+
default:
break;
}
@@ -7370,6 +7463,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
case BFD_RELOC_PPC_VLE_SDAREL_HI16D:
case BFD_RELOC_PPC_VLE_SDAREL_HA16A:
case BFD_RELOC_PPC_VLE_SDAREL_HA16D:
+ case BFD_RELOC_PPC64_GOT_PCREL34:
+ case BFD_RELOC_PPC64_PLT_PCREL34:
gas_assert (fixP->fx_addsy != NULL);
/* Fallthru */
@@ -7421,9 +7516,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
#else
#define APPLY_RELOC 1
#endif
+ /* We need to call the insert function even when fieldval is
+ zero if the insert function would translate that zero to a
+ bit pattern other than all zeros. */
if ((fieldval != 0 && APPLY_RELOC) || operand->insert != NULL)
{
- unsigned long insn;
+ uint64_t insn;
unsigned char *where;
/* Fetch the instruction, insert the fully resolved operand
@@ -7431,34 +7529,56 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
if (target_big_endian)
{
- if (fixP->fx_size == 4)
- insn = bfd_getb32 (where);
- else
+ if (fixP->fx_size < 4)
insn = bfd_getb16 (where);
+ else
+ {
+ insn = bfd_getb32 (where);
+ if (fixP->fx_size > 4)
+ insn = insn << 32 | bfd_getb32 (where + 4);
+ }
}
else
{
- if (fixP->fx_size == 4)
- insn = bfd_getl32 (where);
- else
+ if (fixP->fx_size < 4)
insn = bfd_getl16 (where);
+ else
+ {
+ insn = bfd_getl32 (where);
+ if (fixP->fx_size > 4)
+ insn = insn << 32 | bfd_getl32 (where + 4);
+ }
}
insn = ppc_insert_operand (insn, operand, fieldval,
fixP->tc_fix_data.ppc_cpu,
fixP->fx_file, fixP->fx_line);
if (target_big_endian)
{
- if (fixP->fx_size == 4)
- bfd_putb32 (insn, where);
- else
+ if (fixP->fx_size < 4)
bfd_putb16 (insn, where);
+ else
+ {
+ if (fixP->fx_size > 4)
+ {
+ bfd_putb32 (insn, where + 4);
+ insn >>= 32;
+ }
+ bfd_putb32 (insn, where);
+ }
}
else
{
- if (fixP->fx_size == 4)
- bfd_putl32 (insn, where);
- else
+ if (fixP->fx_size < 4)
bfd_putl16 (insn, where);
+ else
+ {
+ if (fixP->fx_size > 4)
+ {
+ bfd_putl32 (insn, where + 4);
+ insn >>= 32;
+ }
+ bfd_putl32 (insn, where);
+ }
}
}
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 08e381e293c..9de5c08441b 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -273,7 +273,13 @@ extern int ppc_force_relocation (struct fix *);
|| (FIX)->fx_r_type == BFD_RELOC_PPC64_HIGHER_S \
|| (FIX)->fx_r_type == BFD_RELOC_PPC64_HIGHEST \
|| (FIX)->fx_r_type == BFD_RELOC_PPC64_HIGHEST_S \
- || (FIX)->fx_r_type == BFD_RELOC_PPC_16DX_HA))
+ || (FIX)->fx_r_type == BFD_RELOC_PPC64_ADDR16_HIGHER34 \
+ || (FIX)->fx_r_type == BFD_RELOC_PPC64_ADDR16_HIGHERA34 \
+ || (FIX)->fx_r_type == BFD_RELOC_PPC64_ADDR16_HIGHEST34 \
+ || (FIX)->fx_r_type == BFD_RELOC_PPC64_ADDR16_HIGHESTA34 \
+ || (FIX)->fx_r_type == BFD_RELOC_PPC_16DX_HA \
+ || (FIX)->fx_r_type == BFD_RELOC_PPC64_D34 \
+ || (FIX)->fx_r_type == BFD_RELOC_PPC64_D28))
#endif
#define TC_VALIDATE_FIX_SUB(FIX, SEG) 0
diff --git a/gas/testsuite/gas/ppc/ppc.exp b/gas/testsuite/gas/ppc/ppc.exp
index aa199d5e85e..1660d530f0a 100644
--- a/gas/testsuite/gas/ppc/ppc.exp
+++ b/gas/testsuite/gas/ppc/ppc.exp
@@ -116,3 +116,4 @@ run_dump_test "htm"
run_dump_test "titan"
run_dump_test "prefix-align"
run_dump_test "prefix-pcrel"
+run_dump_test "prefix-reloc"
diff --git a/gas/testsuite/gas/ppc/prefix-reloc.d b/gas/testsuite/gas/ppc/prefix-reloc.d
new file mode 100644
index 00000000000..9f554ac388d
--- /dev/null
+++ b/gas/testsuite/gas/ppc/prefix-reloc.d
@@ -0,0 +1,35 @@
+#as: -a64 -mfuture
+#objdump: -dr -Mfuture
+#name: Prefix insn relocations
+
+.*
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+ 0: (00 00 00 06|06 00 00 00) pli r9,0
+ 4: (00 00 20 39|39 20 00 00)
+ 0: R_PPC64_D34_HA30 ext
+ 8: (46 17 29 79|79 29 17 46) rldicr r9,r9,34,29
+ c: (00 00 00 06|06 00 00 00) paddi r9,r9,0
+ 10: (00 00 29 39|39 29 00 00)
+ c: R_PPC64_D34_LO ext
+ 14: (00 00 10 04|04 10 00 00) pld r3,0
+ 18: (00 00 60 e4|e4 60 00 00)
+ 14: R_PPC64_PCREL34 ext
+ 1c: (00 00 10 04|04 10 00 00) pld r4,0
+ 20: (00 00 80 e4|e4 80 00 00)
+ 1c: R_PPC64_GOT_PCREL34 ext
+ 24: (00 00 10 04|04 10 00 00) pld r5,0
+ 28: (00 00 a0 e4|e4 a0 00 00)
+ 24: R_PPC64_PLT_PCREL34 ext
+ 2c: (00 00 10 04|04 10 00 00) pld r6,0
+ 30: (00 00 c0 e4|e4 c0 00 00)
+ 2c: R_PPC64_PCREL34 ext
+ 34: (00 00 00 04|04 00 00 00) pld r7,0\(0\)
+ 38: (00 00 e0 e4|e4 e0 00 00)
+ 34: R_PPC64_D34 ext
+ 3c: (00 00 00 60|60 00 00 00) nop
+ 40: (00 00 10 04|04 10 00 00) pld r8,0
+ 44: (00 00 00 e5|e5 00 00 00)
+ 40: R_PPC64_PCREL34 ext
diff --git a/gas/testsuite/gas/ppc/prefix-reloc.s b/gas/testsuite/gas/ppc/prefix-reloc.s
new file mode 100644
index 00000000000..a2f23075dbb
--- /dev/null
+++ b/gas/testsuite/gas/ppc/prefix-reloc.s
@@ -0,0 +1,13 @@
+ .text
+ pli 9,ext@ha
+ sldi 9,9,34
+ paddi 9,9,ext@l
+ pld 3,ext@pcrel
+ pld 4,ext@got@pcrel
+ pld 5,ext@plt@pcrel
+0: pld 6,ext-0b(0),1
+ pld 7,ext(0),0
+# The following insn will need an alignment nop, testing the behaviour
+# of "dot" in the expression. Don't stupidly edit this file and lose
+# the nop.
+ pld 8,ext-.(0),1
diff --git a/include/ChangeLog b/include/ChangeLog
index c02b33aa309..2e8408402fb 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,15 @@
+2019-05-24 Alan Modra <amodra@gmail.com>
+
+ * elf/ppc64.h (R_PPC64_PLTSEQ_NOTOC, R_PPC64_PLTCALL_NOTOC),
+ (R_PPC64_PCREL_OPT, R_PPC64_D34, R_PPC64_D34_LO, R_PPC64_D34_HI30),
+ (R_PPC64_D34_HA30, R_PPC64_PCREL34, R_PPC64_GOT_PCREL34),
+ (R_PPC64_PLT_PCREL34, R_PPC64_PLT_PCREL34_NOTOC),
+ (R_PPC64_ADDR16_HIGHER34, R_PPC64_ADDR16_HIGHERA34),
+ (R_PPC64_ADDR16_HIGHEST34, R_PPC64_ADDR16_HIGHESTA34),
+ (R_PPC64_REL16_HIGHER34, R_PPC64_REL16_HIGHERA34),
+ (R_PPC64_REL16_HIGHEST34, R_PPC64_REL16_HIGHESTA34),
+ (R_PPC64_D28, R_PPC64_PCREL28): Define.
+
2019-05-24 Peter Bergner <bergner@linux.ibm.com>
Alan Modra <amodra@gmail.com>
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index 6dd29cdf8a9..e90c7fd2efc 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -158,6 +158,30 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
RELOC_NUMBER (R_PPC64_PLTSEQ, 119)
RELOC_NUMBER (R_PPC64_PLTCALL, 120)
+/* Powerxx support. */
+ RELOC_NUMBER (R_PPC64_PLTSEQ_NOTOC, 121)
+ RELOC_NUMBER (R_PPC64_PLTCALL_NOTOC, 122)
+ RELOC_NUMBER (R_PPC64_PCREL_OPT, 123)
+
+ RELOC_NUMBER (R_PPC64_D34, 128)
+ RELOC_NUMBER (R_PPC64_D34_LO, 129)
+ RELOC_NUMBER (R_PPC64_D34_HI30, 130)
+ RELOC_NUMBER (R_PPC64_D34_HA30, 131)
+ RELOC_NUMBER (R_PPC64_PCREL34, 132)
+ RELOC_NUMBER (R_PPC64_GOT_PCREL34, 133)
+ RELOC_NUMBER (R_PPC64_PLT_PCREL34, 134)
+ RELOC_NUMBER (R_PPC64_PLT_PCREL34_NOTOC, 135)
+ RELOC_NUMBER (R_PPC64_ADDR16_HIGHER34, 136)
+ RELOC_NUMBER (R_PPC64_ADDR16_HIGHERA34, 137)
+ RELOC_NUMBER (R_PPC64_ADDR16_HIGHEST34, 138)
+ RELOC_NUMBER (R_PPC64_ADDR16_HIGHESTA34, 139)
+ RELOC_NUMBER (R_PPC64_REL16_HIGHER34, 140)
+ RELOC_NUMBER (R_PPC64_REL16_HIGHERA34, 141)
+ RELOC_NUMBER (R_PPC64_REL16_HIGHEST34, 142)
+ RELOC_NUMBER (R_PPC64_REL16_HIGHESTA34, 143)
+ RELOC_NUMBER (R_PPC64_D28, 144)
+ RELOC_NUMBER (R_PPC64_PCREL28, 145)
+
#ifndef RELOC_MACROS_GEN_FUNC
/* Relocation only used internally by gas or ld. If you need to use
these reloc numbers, you can change them to some other unused value