diff options
author | Alan Modra <amodra@gmail.com> | 2018-12-06 20:51:27 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2018-12-06 23:01:03 +1030 |
commit | bb6bf75e7a1f9aaf0283895705710f415b81b6b1 (patch) | |
tree | 4322e262020b93bbb0cf0c940737bd9a6dd71df7 /gas/config/tc-ppc.c | |
parent | 23ebf37881dda7fcf9dd86125705a30b6e2084ce (diff) | |
download | gdb-bb6bf75e7a1f9aaf0283895705710f415b81b6b1.zip gdb-bb6bf75e7a1f9aaf0283895705710f415b81b6b1.tar.gz gdb-bb6bf75e7a1f9aaf0283895705710f415b81b6b1.tar.bz2 |
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/config/tc-ppc.c')
-rw-r--r-- | gas/config/tc-ppc.c | 88 |
1 files changed, 55 insertions, 33 deletions
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index a8eda5d..cebbd42 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 */ |