From 0e2779e98dc1251b469db690458d14262c72e303 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 7 Nov 2018 16:12:36 +1030 Subject: [PATCH] PowerPC, don't use bfd reloc howto in md_assemble We support source like the following .data .quad x-. .space 8 x: where at the time the .quad line is assembled, x is unknown so a fixup is emitted for later evaluation. This is supported for data even when the target may not have relocations for the expression, for example, 32-bit powerpc targets lack a 64-bit reloc. As long as the fixup resolves at assembly time, gas is happy. The idea of this patch is to support fixups that resolve at assembly time for instructions too, even when the target might lack the necessary relocations (and thus no howto). * config/tc-ppc.c (fixup_size): New function. (md_assemble): Use it to derive size and pcrel directly from fixup reloc type. --- gas/ChangeLog | 6 + gas/config/tc-ppc.c | 260 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 255 insertions(+), 11 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 51b3d5c6c0a..aafc95cb807 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2018-11-09 Alan Modra + + * config/tc-ppc.c (fixup_size): New function. + (md_assemble): Use it to derive size and pcrel directly + from fixup reloc type. + 2018-11-07 Nick Clifton * po/fr.po: Updated French translation. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 9a066682ab7..a8eda5d9037 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -2754,6 +2754,251 @@ struct ppc_fixup #define MAX_INSN_FIXUPS (5) +/* Return the field size operated on by RELOC, and whether it is + pc-relative in PC_RELATIVE. */ + +static unsigned int +fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) +{ + unsigned int size = 0; + bfd_boolean pcrel = FALSE; + + switch (reloc) + { + /* This switch statement must handle all BFD_RELOC values + possible in instruction fixups. As is, it handles all + BFD_RELOC values used in bfd/elf64-ppc.c, bfd/elf32-ppc.c, + bfd/coff-ppc, bfd/coff-rs6000.c and bfd/coff64-rs6000.c. + Overkill since data and marker relocs need not be handled + here, but this way we can be sure a needed fixup reloc isn't + accidentally omitted. */ + case BFD_RELOC_PPC_EMB_MRKREF: + case BFD_RELOC_VTABLE_ENTRY: + case BFD_RELOC_VTABLE_INHERIT: + break; + + case BFD_RELOC_8: + size = 1; + break; + + case BFD_RELOC_16: + case BFD_RELOC_16_BASEREL: + case BFD_RELOC_16_GOTOFF: + case BFD_RELOC_GPREL16: + case BFD_RELOC_HI16: + case BFD_RELOC_HI16_BASEREL: + case BFD_RELOC_HI16_GOTOFF: + case BFD_RELOC_HI16_PLTOFF: + case BFD_RELOC_HI16_S: + case BFD_RELOC_HI16_S_BASEREL: + case BFD_RELOC_HI16_S_GOTOFF: + case BFD_RELOC_HI16_S_PLTOFF: + case BFD_RELOC_LO16: + case BFD_RELOC_LO16_BASEREL: + case BFD_RELOC_LO16_GOTOFF: + case BFD_RELOC_LO16_PLTOFF: + case BFD_RELOC_PPC64_ADDR16_DS: + case BFD_RELOC_PPC64_ADDR16_HIGH: + case BFD_RELOC_PPC64_ADDR16_HIGHA: + case BFD_RELOC_PPC64_ADDR16_LO_DS: + case BFD_RELOC_PPC64_DTPREL16_DS: + case BFD_RELOC_PPC64_DTPREL16_HIGH: + case BFD_RELOC_PPC64_DTPREL16_HIGHA: + case BFD_RELOC_PPC64_DTPREL16_HIGHER: + case BFD_RELOC_PPC64_DTPREL16_HIGHERA: + case BFD_RELOC_PPC64_DTPREL16_HIGHEST: + case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: + case BFD_RELOC_PPC64_DTPREL16_LO_DS: + case BFD_RELOC_PPC64_GOT16_DS: + case BFD_RELOC_PPC64_GOT16_LO_DS: + case BFD_RELOC_PPC64_HIGHER: + case BFD_RELOC_PPC64_HIGHER_S: + case BFD_RELOC_PPC64_HIGHEST: + case BFD_RELOC_PPC64_HIGHEST_S: + case BFD_RELOC_PPC64_PLT16_LO_DS: + case BFD_RELOC_PPC64_PLTGOT16: + case BFD_RELOC_PPC64_PLTGOT16_DS: + case BFD_RELOC_PPC64_PLTGOT16_HA: + case BFD_RELOC_PPC64_PLTGOT16_HI: + case BFD_RELOC_PPC64_PLTGOT16_LO: + case BFD_RELOC_PPC64_PLTGOT16_LO_DS: + case BFD_RELOC_PPC64_SECTOFF_DS: + case BFD_RELOC_PPC64_SECTOFF_LO_DS: + case BFD_RELOC_PPC64_TOC16_DS: + case BFD_RELOC_PPC64_TOC16_HA: + case BFD_RELOC_PPC64_TOC16_HI: + case BFD_RELOC_PPC64_TOC16_LO: + case BFD_RELOC_PPC64_TOC16_LO_DS: + case BFD_RELOC_PPC64_TPREL16_DS: + case BFD_RELOC_PPC64_TPREL16_HIGH: + case BFD_RELOC_PPC64_TPREL16_HIGHA: + case BFD_RELOC_PPC64_TPREL16_HIGHER: + case BFD_RELOC_PPC64_TPREL16_HIGHERA: + case BFD_RELOC_PPC64_TPREL16_HIGHEST: + case BFD_RELOC_PPC64_TPREL16_HIGHESTA: + case BFD_RELOC_PPC64_TPREL16_LO_DS: +#ifdef OBJ_XCOFF + case BFD_RELOC_PPC_BA16: +#endif + case BFD_RELOC_PPC_DTPREL16: + case BFD_RELOC_PPC_DTPREL16_HA: + case BFD_RELOC_PPC_DTPREL16_HI: + case BFD_RELOC_PPC_DTPREL16_LO: + case BFD_RELOC_PPC_EMB_NADDR16: + case BFD_RELOC_PPC_EMB_NADDR16_HA: + case BFD_RELOC_PPC_EMB_NADDR16_HI: + case BFD_RELOC_PPC_EMB_NADDR16_LO: + case BFD_RELOC_PPC_EMB_RELSDA: + case BFD_RELOC_PPC_EMB_RELSEC16: + case BFD_RELOC_PPC_EMB_RELST_LO: + case BFD_RELOC_PPC_EMB_RELST_HI: + case BFD_RELOC_PPC_EMB_RELST_HA: + case BFD_RELOC_PPC_EMB_SDA2I16: + case BFD_RELOC_PPC_EMB_SDA2REL: + case BFD_RELOC_PPC_EMB_SDAI16: + case BFD_RELOC_PPC_GOT_DTPREL16: + case BFD_RELOC_PPC_GOT_DTPREL16_HA: + case BFD_RELOC_PPC_GOT_DTPREL16_HI: + case BFD_RELOC_PPC_GOT_DTPREL16_LO: + case BFD_RELOC_PPC_GOT_TLSGD16: + case BFD_RELOC_PPC_GOT_TLSGD16_HA: + case BFD_RELOC_PPC_GOT_TLSGD16_HI: + case BFD_RELOC_PPC_GOT_TLSGD16_LO: + case BFD_RELOC_PPC_GOT_TLSLD16: + case BFD_RELOC_PPC_GOT_TLSLD16_HA: + case BFD_RELOC_PPC_GOT_TLSLD16_HI: + case BFD_RELOC_PPC_GOT_TLSLD16_LO: + case BFD_RELOC_PPC_GOT_TPREL16: + case BFD_RELOC_PPC_GOT_TPREL16_HA: + case BFD_RELOC_PPC_GOT_TPREL16_HI: + case BFD_RELOC_PPC_GOT_TPREL16_LO: + case BFD_RELOC_PPC_TOC16: + case BFD_RELOC_PPC_TPREL16: + case BFD_RELOC_PPC_TPREL16_HA: + case BFD_RELOC_PPC_TPREL16_HI: + case BFD_RELOC_PPC_TPREL16_LO: + size = 2; + break; + + case BFD_RELOC_16_PCREL: + case BFD_RELOC_HI16_PCREL: + case BFD_RELOC_HI16_S_PCREL: + case BFD_RELOC_LO16_PCREL: + case BFD_RELOC_PPC64_REL16_HIGH: + case BFD_RELOC_PPC64_REL16_HIGHA: + case BFD_RELOC_PPC64_REL16_HIGHER: + case BFD_RELOC_PPC64_REL16_HIGHERA: + case BFD_RELOC_PPC64_REL16_HIGHEST: + case BFD_RELOC_PPC64_REL16_HIGHESTA: +#ifdef OBJ_XCOFF + case BFD_RELOC_PPC_B16: +#endif + case BFD_RELOC_PPC_VLE_REL8: + size = 2; + pcrel = TRUE; + break; + + case BFD_RELOC_16_GOT_PCREL: /* coff reloc, bad name re size. */ + case BFD_RELOC_32: + case BFD_RELOC_32_GOTOFF: + case BFD_RELOC_32_PLTOFF: +#ifdef OBJ_XCOFF + case BFD_RELOC_CTOR: +#endif + case BFD_RELOC_PPC64_ENTRY: + case BFD_RELOC_PPC_16DX_HA: +#ifndef OBJ_XCOFF + case BFD_RELOC_PPC_BA16: +#endif + case BFD_RELOC_PPC_BA16_BRNTAKEN: + case BFD_RELOC_PPC_BA16_BRTAKEN: + case BFD_RELOC_PPC_BA26: + case BFD_RELOC_PPC_EMB_BIT_FLD: + case BFD_RELOC_PPC_EMB_NADDR32: + case BFD_RELOC_PPC_EMB_SDA21: + case BFD_RELOC_PPC_TLS: + case BFD_RELOC_PPC_TLSGD: + case BFD_RELOC_PPC_TLSLD: + case BFD_RELOC_PPC_VLE_HA16A: + case BFD_RELOC_PPC_VLE_HA16D: + case BFD_RELOC_PPC_VLE_HI16A: + case BFD_RELOC_PPC_VLE_HI16D: + case BFD_RELOC_PPC_VLE_LO16A: + case BFD_RELOC_PPC_VLE_LO16D: + case BFD_RELOC_PPC_VLE_SDA21: + case BFD_RELOC_PPC_VLE_SDA21_LO: + case BFD_RELOC_PPC_VLE_SDAREL_HA16A: + case BFD_RELOC_PPC_VLE_SDAREL_HA16D: + case BFD_RELOC_PPC_VLE_SDAREL_HI16A: + case BFD_RELOC_PPC_VLE_SDAREL_HI16D: + case BFD_RELOC_PPC_VLE_SDAREL_LO16A: + case BFD_RELOC_PPC_VLE_SDAREL_LO16D: + case BFD_RELOC_RVA: + size = 4; + break; + + case BFD_RELOC_24_PLT_PCREL: + case BFD_RELOC_32_PCREL: + case BFD_RELOC_32_PLT_PCREL: + case BFD_RELOC_PPC64_REL24_NOTOC: +#ifndef OBJ_XCOFF + case BFD_RELOC_PPC_B16: +#endif + case BFD_RELOC_PPC_B16_BRNTAKEN: + case BFD_RELOC_PPC_B16_BRTAKEN: + case BFD_RELOC_PPC_B26: + case BFD_RELOC_PPC_LOCAL24PC: + case BFD_RELOC_PPC_REL16DX_HA: + case BFD_RELOC_PPC_VLE_REL15: + case BFD_RELOC_PPC_VLE_REL24: + size = 4; + pcrel = TRUE; + break; + +#ifndef OBJ_XCOFF + case BFD_RELOC_CTOR: +#endif + case BFD_RELOC_PPC_COPY: + case BFD_RELOC_PPC_DTPMOD: + case BFD_RELOC_PPC_DTPREL: + case BFD_RELOC_PPC_GLOB_DAT: + case BFD_RELOC_PPC_TPREL: + size = ppc_obj64 ? 8 : 4; + break; + + case BFD_RELOC_64: + case BFD_RELOC_64_PLTOFF: + case BFD_RELOC_PPC64_ADDR64_LOCAL: + case BFD_RELOC_PPC64_TOC: + size = 8; + break; + + case BFD_RELOC_64_PCREL: + case BFD_RELOC_64_PLT_PCREL: + size = 8; + pcrel = TRUE; + break; + + default: + abort (); + } + + if (ENABLE_CHECKING) + { + reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); + if (reloc_howto != NULL + && (size != bfd_get_reloc_size (reloc_howto) + || pcrel != reloc_howto->pc_relative)) + { + as_bad (_("%s howto doesn't match size/pcrel in gas"), + reloc_howto->name); + abort (); + } + } + *pc_relative = pcrel; + return size; +} + /* This routine is called for each instruction to be assembled. */ void @@ -3569,22 +3814,15 @@ md_assemble (char *str) fixS *fixP; if (fixups[i].reloc != BFD_RELOC_NONE) { - reloc_howto_type *reloc_howto; - int size; - int offset; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - offset = target_big_endian ? (insn_length - size) : 0; + bfd_boolean pcrel; + unsigned int size = fixup_size (fixups[i].reloc, &pcrel); + int offset = target_big_endian ? (insn_length - size) : 0; fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size, &fixups[i].exp, - reloc_howto->pc_relative, + pcrel, fixups[i].reloc); } else -- 2.30.2