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 /bfd | |
parent | 23ebf37881dda7fcf9dd86125705a30b6e2084ce (diff) | |
download | binutils-bb6bf75e7a1f9aaf0283895705710f415b81b6b1.zip binutils-bb6bf75e7a1f9aaf0283895705710f415b81b6b1.tar.gz binutils-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 'bfd')
-rw-r--r-- | bfd/ChangeLog | 7 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 28 |
2 files changed, 27 insertions, 8 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index de468a4..8a37271 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2018-12-06 Alan Modra <amodra@gmail.com> + + * 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. + 2018-12-05 Sam Tebbs <sam.tebbs@arm.com> * elf-eh-frame.c (_bfd_elf_parse_eh_frame): Add check for 'B'. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index c31e26e..6b6043a 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -649,8 +649,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { ppc_elf_unhandled_reloc), /* e_li split20 format. */ - HOW (R_PPC_VLE_ADDR20, 2, 20, 0x1f07ff, 16, FALSE, dont, - bfd_elf_generic_reloc), + HOW (R_PPC_VLE_ADDR20, 2, 20, 0x1f7fff, 0, FALSE, dont, + ppc_elf_unhandled_reloc), HOW (R_PPC_IRELATIVE, 2, 32, 0xffffffff, 0, FALSE, dont, ppc_elf_unhandled_reloc), @@ -3886,10 +3886,10 @@ ppc_elf_vle_split16 (bfd *input_bfd, split16_format_type split16_format, bfd_boolean fixup) { - unsigned int insn, opcode, top5; + unsigned int insn, opcode; insn = bfd_get_32 (input_bfd, loc); - opcode = insn & 0xfc00f800; + opcode = insn & E_OPCODE_MASK; if (opcode == E_OR2I_INSN || opcode == E_AND2I_DOT_INSN || opcode == E_OR2IS_INSN @@ -3926,10 +3926,22 @@ ppc_elf_vle_split16 (bfd *input_bfd, input_bfd, input_section, offset, opcode); } } - top5 = value & 0xf800; - top5 = top5 << (split16_format == split16a_type ? 5 : 10); - insn &= (split16_format == split16a_type ? ~0x1f07ff : ~0x3e007ff); - insn |= top5; + if (split16_format == split16a_type) + { + insn &= ~((0xf800 << 5) | 0x7ff); + insn |= (value & 0xf800) << 5; + if ((insn & E_LI_MASK) == E_LI_INSN) + { + /* Hack for e_li. Extend sign. */ + insn &= ~(0xf0000 >> 5); + insn |= (-(value & 0x8000) & 0xf0000) >> 5; + } + } + else + { + insn &= ~((0xf800 << 10) | 0x7ff); + insn |= (value & 0xf800) << 10; + } insn |= value & 0x7ff; bfd_put_32 (input_bfd, insn, loc); } |