From a0593ad95626fddd6777a418feb3dd3722e1ef66 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 5 Mar 2014 19:31:45 +1030 Subject: [PATCH] Support more relocs on 16-bit insn fields This patch allows gas to assemble a testcase like li 3,ext_sym which oddly was not accepted while the following is OK: li 3,ext_sym@l * config/tc-ppc.c (md_assemble): Move code adjusting reloc types later. Merge absolute and relative branch reloc selection. Generate 16-bit relocs for most 16-bit insn fields given a non-constant expression. --- gas/ChangeLog | 7 ++ gas/config/tc-ppc.c | 225 +++++++++++++++++++++++++--------------------------- 2 files changed, 116 insertions(+), 116 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index e3ebd67..dae0368 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,12 @@ 2014-03-05 Alan Modra + * config/tc-ppc.c (md_assemble): Move code adjusting reloc types + later. Merge absolute and relative branch reloc selection. + Generate 16-bit relocs for most 16-bit insn fields given a + non-constant expression. + +2014-03-05 Alan Modra + * config/tc-ppc.c (ppc_is_toc_sym): Remove OBJ_ELF support. (md_assemble): Don't call ppc_is_toc_sym for ELF. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 176b13c..6ffbe13 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -3133,103 +3133,6 @@ md_assemble (char *str) break; } } - - /* For the absolute forms of branches, convert the PC - relative form back into the absolute. */ - if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) - { - switch (reloc) - { - case BFD_RELOC_PPC_B26: - reloc = BFD_RELOC_PPC_BA26; - break; - case BFD_RELOC_PPC_B16: - reloc = BFD_RELOC_PPC_BA16; - break; - case BFD_RELOC_PPC_B16_BRTAKEN: - reloc = BFD_RELOC_PPC_BA16_BRTAKEN; - break; - case BFD_RELOC_PPC_B16_BRNTAKEN: - reloc = BFD_RELOC_PPC_BA16_BRNTAKEN; - break; - default: - break; - } - } - - switch (reloc) - { - case BFD_RELOC_PPC_TOC16: - toc_reloc_types |= has_small_toc_reloc; - break; - case BFD_RELOC_PPC64_TOC16_LO: - case BFD_RELOC_PPC64_TOC16_HI: - case BFD_RELOC_PPC64_TOC16_HA: - toc_reloc_types |= has_large_toc_reloc; - break; - default: - break; - } - - if ((operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0) - { - switch (reloc) - { - 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; - } - } } #endif /* OBJ_ELF */ @@ -3238,11 +3141,13 @@ md_assemble (char *str) /* Determine a BFD reloc value based on the operand information. We are only prepared to turn a few of the operands into relocs. */ - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 + else if ((operand->flags & (PPC_OPERAND_RELATIVE + | PPC_OPERAND_ABSOLUTE)) != 0 && operand->bitm == 0x3fffffc && operand->shift == 0) reloc = BFD_RELOC_PPC_B26; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 + else if ((operand->flags & (PPC_OPERAND_RELATIVE + | PPC_OPERAND_ABSOLUTE)) != 0 && operand->bitm == 0xfffc && operand->shift == 0) reloc = BFD_RELOC_PPC_B16; @@ -3258,32 +3163,120 @@ md_assemble (char *str) && operand->bitm == 0x1fffffe && operand->shift == 0) reloc = BFD_RELOC_PPC_VLE_REL24; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bitm == 0x3fffffc - && operand->shift == 0) - reloc = BFD_RELOC_PPC_BA26; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bitm == 0xfffc - && operand->shift == 0) - reloc = BFD_RELOC_PPC_BA16; -#if defined (OBJ_XCOFF) || defined (OBJ_ELF) - else if ((operand->flags & PPC_OPERAND_PARENS) != 0 + else if ((operand->flags & PPC_OPERAND_NEGATIVE) == 0 && (operand->bitm & 0xfff0) == 0xfff0 && operand->shift == 0) { reloc = BFD_RELOC_16; -#ifdef OBJ_ELF - if (ppc_obj64 - && (operand->flags & PPC_OPERAND_DS) != 0) - reloc = BFD_RELOC_PPC64_ADDR16_DS; -#endif #ifdef OBJ_XCOFF /* Note: the symbol may be not yet defined. */ - if (ppc_is_toc_sym (ex.X_add_symbol)) + if ((operand->flags & PPC_OPERAND_PARENS) != 0 + && ppc_is_toc_sym (ex.X_add_symbol)) reloc = BFD_RELOC_PPC_TOC16; #endif } -#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ + + /* For the absolute forms of branches, convert the PC + relative form back into the absolute. */ + if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) + { + switch (reloc) + { + case BFD_RELOC_PPC_B26: + reloc = BFD_RELOC_PPC_BA26; + break; + case BFD_RELOC_PPC_B16: + reloc = BFD_RELOC_PPC_BA16; + break; +#ifdef OBJ_ELF + case BFD_RELOC_PPC_B16_BRTAKEN: + reloc = BFD_RELOC_PPC_BA16_BRTAKEN; + break; + case BFD_RELOC_PPC_B16_BRNTAKEN: + reloc = BFD_RELOC_PPC_BA16_BRNTAKEN; + break; +#endif + default: + break; + } + } + +#ifdef OBJ_ELF + switch (reloc) + { + case BFD_RELOC_PPC_TOC16: + toc_reloc_types |= has_small_toc_reloc; + break; + case BFD_RELOC_PPC64_TOC16_LO: + case BFD_RELOC_PPC64_TOC16_HI: + case BFD_RELOC_PPC64_TOC16_HA: + toc_reloc_types |= has_large_toc_reloc; + break; + default: + break; + } + + if (ppc_obj64 + && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0) + { + switch (reloc) + { + 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; + } + } +#endif /* We need to generate a fixup for this expression. */ if (fc >= MAX_INSN_FIXUPS) -- 2.7.4