PowerPC relocations for prefix insns

include/
	* 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.
bfd/
	* 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.
gas/
	* 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.
This commit is contained in:
Alan Modra 2018-08-29 14:22:34 +09:30
parent 8acf14351c
commit 5663e32184
13 changed files with 722 additions and 64 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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;
@ -1492,6 +1598,48 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
return bfd_reloc_ok;
}
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,
@ -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;

View File

@ -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",

View File

@ -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.

View File

@ -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>

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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