diff options
author | Alan Modra <amodra@gmail.com> | 2018-08-29 14:22:34 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2019-05-24 10:27:49 +0930 |
commit | 5663e321848545857a690f30a780187e3366bd2d (patch) | |
tree | c9b730b7593a41e9927039f6fa277610b468d260 /gas/config | |
parent | 8acf14351c818d956babe50e61711740f378c941 (diff) | |
download | gdb-5663e321848545857a690f30a780187e3366bd2d.zip gdb-5663e321848545857a690f30a780187e3366bd2d.tar.gz gdb-5663e321848545857a690f30a780187e3366bd2d.tar.bz2 |
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.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-ppc.c | 164 | ||||
-rw-r--r-- | gas/config/tc-ppc.h | 8 |
2 files changed, 149 insertions, 23 deletions
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 |