summaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2018-12-06 20:51:27 +1030
committerAlan Modra <amodra@gmail.com>2018-12-06 23:01:03 +1030
commitbb6bf75e7a1f9aaf0283895705710f415b81b6b1 (patch)
tree4322e262020b93bbb0cf0c940737bd9a6dd71df7 /gas
parent23ebf37881dda7fcf9dd86125705a30b6e2084ce (diff)
downloadbinutils-gdb-bb6bf75e7a1f9aaf0283895705710f415b81b6b1.tar.gz
PowerPC @l, @h and @ha warnings, plus VLE e_li
This patch started off just adding the warnings in tc-ppc.c about incorrect usage of @l, @h and @ha in instructions that don't have 16-bit D-form fields. That unfortunately showed up three warnings in ld/testsuite/ld-powerpc/vle-multiseg.s on instructions like e_li r3, IV_table@l+0x00 which was being assembled to 8: 70 60 00 00 e_li r3,0 a: R_PPC_ADDR16_LO IV_table The ADDR16_LO reloc is of course completely bogus on e_li, which has a split 20-bit signed integer field in bits 0x1f7fff, the low 11 bit in 0x7ff, the next 5 bits in 0x1f0000, and the high 4 bits in 0x7800. Applying an ADDR16_LO reloc to the instruction potentially changes the e_li instruction to e_add2i., e_add2is, e_cmp16i, e_mull2i, e_cmpl16i, e_cmph16i, e_cmphl16i, e_or2i, e_and2i., e_or2is, e_lis, e_and2is, or some invalid encodings. Now there is a relocation that suits e_li, R_PPC_VLE_ADDR20, which was added 2017-09-05 but I can't see code in gas to generate the relocation. In any case, VLE_ADDR20 probably doesn't have the correct semantics for @l since ideally you'd want an @l to pair with @h or @ha to generate a 32-bit constant. Thus @l should only produce a 16-bit value, I think. So we need some more relocations to handle e_li it seems, or as I do in this patch, modify the behaviour of existing relocations when applied to e_li instructions. include/ * opcode/ppc.h (E_OPCODE_MASK, E_LI_MASK, E_LI_INSN): Define. bfd/ * elf32-ppc.c (ppc_elf_howto_raw <R_PPC_VLE_ADDR20>): Correct mask and shift value. (ppc_elf_vle_split16): Use E_OPCODE_MASK. Handle e_li specially. gas/ * config/tc-ppc.c (md_assemble): Adjust relocs for VLE before TLS tweaks. Handle e_li. Warn on unexpected operand field for lo16/hi16/ha16 relocs.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog6
-rw-r--r--gas/config/tc-ppc.c88
2 files changed, 61 insertions, 33 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index a4e0767f5ca..72ae3bcd2f6 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,9 @@
+2018-12-06 Alan Modra <amodra@gmail.com>
+
+ * config/tc-ppc.c (md_assemble): Adjust relocs for VLE before
+ TLS tweaks. Handle e_li. Warn on unexpected operand field
+ for lo16/hi16/ha16 relocs.
+
2018-12-06 Andrew Burgess <andrew.burgess@embecosm.com>
* config/tc-riscv.h (FAKE_LABEL_NAME): Define as
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index a8eda5d9037..cebbd4298c7 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -3433,39 +3433,6 @@ md_assemble (char *str)
if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE)
{
- /* Some TLS tweaks. */
- switch (reloc)
- {
- default:
- break;
-
- case BFD_RELOC_PPC_TLS:
- if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0))
- as_bad (_("@tls may not be used with \"%s\" operands"),
- opcode->name);
- else if (operand->shift != 11)
- as_bad (_("@tls may only be used in last operand"));
- else
- insn = ppc_insert_operand (insn, operand,
- ppc_obj64 ? 13 : 2,
- ppc_cpu, (char *) NULL, 0);
- break;
-
- /* We'll only use the 32 (or 64) bit form of these relocations
- in constants. Instructions get the 16 bit form. */
- case BFD_RELOC_PPC_DTPREL:
- reloc = BFD_RELOC_PPC_DTPREL16;
- break;
- case BFD_RELOC_PPC_TPREL:
- reloc = BFD_RELOC_PPC_TPREL16;
- break;
- }
-
- /* addpcis. */
- if (opcode->opcode == (19 << 26) + (2 << 1)
- && reloc == BFD_RELOC_HI16_S)
- reloc = BFD_RELOC_PPC_16DX_HA;
-
/* If VLE-mode convert LO/HI/HA relocations. */
if (opcode->flags & PPC_OPCODE_VLE)
{
@@ -3474,6 +3441,7 @@ md_assemble (char *str)
int use_a_reloc = (tmp_insn == E_OR2I_INSN
|| tmp_insn == E_AND2I_DOT_INSN
|| tmp_insn == E_OR2IS_INSN
+ || tmp_insn == E_LI_INSN
|| tmp_insn == E_LIS_INSN
|| tmp_insn == E_AND2IS_DOT_INSN);
@@ -3532,6 +3500,60 @@ md_assemble (char *str)
break;
}
}
+
+ /* TLS and other tweaks. */
+ switch (reloc)
+ {
+ default:
+ break;
+
+ case BFD_RELOC_PPC_TLS:
+ if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0))
+ as_bad (_("@tls may not be used with \"%s\" operands"),
+ opcode->name);
+ else if (operand->shift != 11)
+ as_bad (_("@tls may only be used in last operand"));
+ else
+ insn = ppc_insert_operand (insn, operand,
+ ppc_obj64 ? 13 : 2,
+ ppc_cpu, (char *) NULL, 0);
+ break;
+
+ /* We'll only use the 32 (or 64) bit form of these relocations
+ in constants. Instructions get the 16 bit form. */
+ case BFD_RELOC_PPC_DTPREL:
+ reloc = BFD_RELOC_PPC_DTPREL16;
+ break;
+
+ case BFD_RELOC_PPC_TPREL:
+ reloc = BFD_RELOC_PPC_TPREL16;
+ break;
+
+ case BFD_RELOC_LO16:
+ 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)
+ 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))
+ /* addpcis. */
+ reloc = BFD_RELOC_PPC_16DX_HA;
+ else if (operand->bitm != 0xffff
+ || operand->shift != 0
+ || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
+ as_warn (_("%s unsupported on this instruction"), "@ha");
+ }
}
#endif /* OBJ_ELF */