From 5663e321848545857a690f30a780187e3366bd2d Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 29 Aug 2018 14:22:34 +0930 Subject: [PATCH] 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. --- bfd/ChangeLog | 32 +++ bfd/bfd-in2.h | 17 ++ bfd/elf64-ppc.c | 409 ++++++++++++++++++++++++--- bfd/libbfd.h | 17 ++ bfd/reloc.c | 34 +++ gas/ChangeLog | 20 ++ gas/config/tc-ppc.c | 164 +++++++++-- gas/config/tc-ppc.h | 8 +- gas/testsuite/gas/ppc/ppc.exp | 1 + gas/testsuite/gas/ppc/prefix-reloc.d | 35 +++ gas/testsuite/gas/ppc/prefix-reloc.s | 13 + include/ChangeLog | 12 + include/elf/ppc64.h | 24 ++ 13 files changed, 722 insertions(+), 64 deletions(-) create mode 100644 gas/testsuite/gas/ppc/prefix-reloc.d create mode 100644 gas/testsuite/gas/ppc/prefix-reloc.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index aa0a38db3a..9091df0294 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,35 @@ +2019-05-24 Alan Modra + + * 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 * config.bfd (targ_cpu): Process bpf-*-none only if BFD64. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 03d644c61e..450c7b7fb1 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 4eb0153dfb..ad47bed372 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; @@ -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; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index da52a2b098..ff6e0eaef4 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 8f0263e354..266e775fa4 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 2d05746753..1caa4785da 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,23 @@ +2019-05-24 Alan Modra + + * 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 Alan Modra diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 4026c72293..64ff149b21 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 08e381e293..9de5c08441 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 aa199d5e85..1660d530f0 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 0000000000..9f554ac388 --- /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 0000000000..a2f23075db --- /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 c02b33aa30..2e8408402f 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,15 @@ +2019-05-24 Alan Modra + + * 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 Alan Modra diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h index 6dd29cdf8a..e90c7fd2ef 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 -- 2.34.1