From 5663e321848545857a690f30a780187e3366bd2d Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 29 Aug 2018 14:22:34 +0930 Subject: 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. --- gas/config/tc-ppc.c | 164 +++++++++++++++++++++++++++++++++++++++++++++------- gas/config/tc-ppc.h | 8 ++- 2 files changed, 149 insertions(+), 23 deletions(-) (limited to 'gas/config') diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 4026c72..64ff149 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 08e381e..9de5c08 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 -- cgit v1.1