diff options
author | Alan Modra <amodra@gmail.com> | 2017-02-28 08:32:36 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2017-02-28 11:59:47 +1030 |
commit | 7ba71655a425ac44721f97cc0ad7922ca15bce43 (patch) | |
tree | 21c74fc0cf464c5ef896b43c385daa8f6f47b0a7 /bfd/elf64-ppc.c | |
parent | afbf7e8e3aa24152ad58e430c8d37d82e5751f1c (diff) | |
download | gdb-7ba71655a425ac44721f97cc0ad7922ca15bce43.zip gdb-7ba71655a425ac44721f97cc0ad7922ca15bce43.tar.gz gdb-7ba71655a425ac44721f97cc0ad7922ca15bce43.tar.bz2 |
PowerPC addpcis fix
This came up because I was looking at ld/tmpdir/addpcis.o and noticed
the odd addends on REL16DX_HA. They ought to both be -4. The error
crept in due REL16DX_HA howto being pc-relative (as indeed it should
be), and code at gas/write.c:1001 after this comment
/* Make it pc-relative. If the back-end code has not
selected a pc-relative reloc, cancel the adjustment
we do later on all pc-relative relocs. */
*not* cancelling the pc-relative adjustment. So I've made a dummy
non-relative split reloc so that the generic code handles this, rather
than attempting to add hacks later in md_apply_fix which would not be
very robust. Having the new internal reloc also makes it easy to
support
addpcis rx,sym@ha
as an equivalent to
addpcis rx,(sym-0f)@ha
0:
The patch also fixes overflow checking, which must test whether the
addi will overflow too since @l relocs don't have any overflow check.
Lastly, since I was poking at md_apply_fix, I arranged to have the
generic gas/write.c code emit errors for subtraction expressions where
we lack reloc support.
include/
* elf/ppc64.h (R_PPC64_16DX_HA): New. Expand fake reloc comment.
* elf/ppc.h (R_PPC_16DX_HA): Likewise.
bfd/
* reloc.c (BFD_RELOC_PPC_16DX_HA): New.
* elf64-ppc.c (ppc64_elf_howto_raw <R_PPC64_16DX_HA>): New howto.
(ppc64_elf_reloc_type_lookup): Translate new bfd reloc.
(ppc64_elf_ha_reloc): Correct overflow test on REL16DX_HA.
(ppc64_elf_relocate_section): Likewise.
* elf32-ppc.c (ppc_elf_howto_raw <R_PPC_16DX_HA>): New howto.
(ppc_elf_reloc_type_lookup): Translate new bfd reloc.
(ppc_elf_check_relocs): Handle R_PPC_16DX_HA to pacify gcc.
* libbfd.h: Regenerate.
* bfd-in2.h: Regenerate.
gas/
* config/tc-ppc.c (md_assemble): Use BFD_RELOC_PPC_16DX_HA for addpcis.
(md_apply_fix): Remove fx_subsy check. Move code converting to
pcrel reloc earlier and handle BFD_RELOC_PPC_16DX_HA. Remove code
emiiting errors on seeing fx_pcrel set on unexpected relocs, as
that is done now by the generic code via..
* config/tc-ppc.h (TC_FORCE_RELOCATION_SUB_LOCAL): ..this. Define.
(TC_VALIDATE_FIX_SUB): Define.
ld/
* testsuite/ld-powerpc/addpcis.d: Define ext1 and ext2 at
limits of addpcis range.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 7b8bacf..661ef26 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -2045,6 +2045,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0x1fffc1, /* dst_mask */ TRUE), /* pcrel_offset */ + /* A split-field reloc for addpcis, non-relative (gas internal use only). */ + HOWTO (R_PPC64_16DX_HA, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc64_elf_ha_reloc, /* special_function */ + "R_PPC64_16DX_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffc1, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Like R_PPC64_ADDR16_HI, but no overflow. */ HOWTO (R_PPC64_ADDR16_HIGH, /* type */ 16, /* rightshift */ @@ -2450,6 +2465,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA; break; + case BFD_RELOC_PPC_16DX_HA: r = R_PPC64_16DX_HA; + break; case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC64_REL16DX_HA; break; case BFD_RELOC_PPC64_ENTRY: r = R_PPC64_ENTRY; @@ -2512,7 +2529,7 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, enum elf_ppc64_reloc_type r_type; long insn; bfd_size_type octets; - bfd_vma value; + bfd_vma value, field; /* If this is a relocatable link (output_bfd test tells us), just call the generic function. Any adjustment will be done at final @@ -2538,14 +2555,14 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, value -= (reloc_entry->address + input_section->output_offset + input_section->output_section->vma); - value = (bfd_signed_vma) value >> 16; + field = (bfd_signed_vma) value >> 16; octets = reloc_entry->address * bfd_octets_per_byte (abfd); insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~0x1fffc1; - insn |= (value & 0xffc1) | ((value & 0x3e) << 15); + insn |= (field & 0xffc1) | ((field & 0x3e) << 15); bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); - if (value + 0x8000 > 0xffff) + if (value + 0x80000000 > 0xffffffff) return bfd_reloc_overflow; return bfd_reloc_ok; } @@ -15238,17 +15255,19 @@ ppc64_elf_relocate_section (bfd *output_bfd, r = bfd_reloc_outofrange; else { + bfd_signed_vma field; + relocation += addend; relocation -= (rel->r_offset + input_section->output_offset + input_section->output_section->vma); - relocation = (bfd_signed_vma) relocation >> 16; + field = (bfd_signed_vma) relocation >> 16; insn = bfd_get_32 (input_bfd, contents + rel->r_offset); insn &= ~0x1fffc1; - insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15); + insn |= (field & 0xffc1) | ((field & 0x3e) << 15); bfd_put_32 (input_bfd, insn, contents + rel->r_offset); r = bfd_reloc_ok; - if (relocation + 0x8000 > 0xffff) + if (relocation + 0x80000000 > 0xffffffff) r = bfd_reloc_overflow; } } |