aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorPeter Bergner <bergner@vnet.ibm.com>2015-11-11 19:52:52 -0600
committerPeter Bergner <bergner@vnet.ibm.com>2015-11-11 19:52:52 -0600
commita680de9a980e9d268846e8605af14ba1e7f3a39b (patch)
treee341fa2892cd8bac6b4cebf16b3082070e81144c /bfd
parent3604307d2f39ddd0b7f640148338b7ecc0ea4b45 (diff)
downloadgdb-a680de9a980e9d268846e8605af14ba1e7f3a39b.zip
gdb-a680de9a980e9d268846e8605af14ba1e7f3a39b.tar.gz
gdb-a680de9a980e9d268846e8605af14ba1e7f3a39b.tar.bz2
Add assembler, disassembler and linker support for power9.
include/opcode/ * ppc.h (PPC_OPCODE_POWER9): New define. (PPC_OPCODE_VSX3): Likewise. opcodes/ * ppc-dis.c (ppc_opts): Add "power9" and "pwr9" entries. Add PPC_OPCODE_VSX3 to the vsx entry. (powerpc_init_dialect): Set default dialect to power9. * ppc-opc.c (insert_dcmxs, extract_dcmxs, insert_dxd, extract_dxd, insert_dxdn, extract_dxdn, insert_l0, extract_l0, insert_l1, extract_l1 insert_xtq6, extract_xtq6): New static functions. (insert_esync): Test for illegal L operand value. (DCMX, DCMXS, DXD, NDXD, L0, L1, RC, FC, UIM6, X_R, RIC, PRS, XSQ6, XTQ6, LRAND, IMM8, DQX, DQX_MASK, DX, DX_MASK, VXVAPS_MASK, VXVA,XVA, XX2VA, XVARC, XBF_MASK, XX2UIM4_MASK, XX2BFD_MASK, XX2DCMXS_MASK, XVA_MASK, XRLA_MASK, XBFRARB_MASK, XLRAND_MASK, POWER9, PPCVEC3, PPCVSX3): New defines. (powerpc_opcodes) <ps_cmpu0, ps_cmpo0, ps_cmpu1, ps_cmpo1, fcmpu, fcmpo, ftdiv, ftsqrt>: Use XBF_MASK. <mcrxr>: Use XBFRARB_MASK. <addpcis, bcdcfn., bcdcfsq., bcdcfz., bcdcpsgn., bcdctn., bcdctsq., bcdctz., bcds., bcdsetsgn., bcdsr., bcdtrunc., bcdus., bcdutrunc., cmpeqb, cmprb, cnttzd, cnttzd., cnttzw, cnttzw., copy, copy_first, cp_abort, darn, dtstsfi, dtstsfiq, extswsli, extswsli., ldat, ldmx, lwat, lxsd, lxsibzx, lxsihzx, lxssp, lxv, lxvb16x, lxvh8x, lxvl, lxvll, lxvwsx, lxvx, maddhd, maddhdu, maddld, mcrxrx, mfvsrld, modsd, modsw, modud, moduw, msgsync, mtvsrdd, mtvsrws, paste, paste., paste_last, rmieg, setb, slbieg, slbsync, stdat, stop, stwat, stxsd, stxsibx, stxsihx, stxssp, stxv, stxvb16x, stxvh8x, stxvl, stxvll, stxvx, subpcis, urfid, vbpermd, vclzlsbb, vcmpneb, vcmpneb., vcmpneh, vcmpneh., vcmpnew, vcmpnew., vcmpnezb, vcmpnezb., vcmpnezh, vcmpnezh., vcmpnezw, vcmpnezw., vctzb, vctzd, vctzh, vctzlsbb, vctzw, vextractd, vextractub, vextractuh, vextractuw, vextsb2d, vextsb2w, vextsh2d, vextsh2w, vextsw2d, vextublx, vextubrx, vextuhlx, vextuhrx, vextuwlx, vextuwrx, vinsertb, vinsertd, vinserth, vinsertw, vmul10cuq, vmul10ecuq, vmul10euq, vmul10uq, vnegd, vnegw, vpermr, vprtybd, vprtybq, vprtybw, vrldmi, vrldnm, vrlwmi, vrlwnm, vslv, vsrv, wait, xsabsqp, xsaddqp, xsaddqpo, xscmpeqdp, xscmpexpdp, xscmpexpqp, xscmpgedp, xscmpgtdp, xscmpnedp, xscmpoqp, xscmpuqp, xscpsgnqp, xscvdphp, xscvdpqp, xscvhpdp, xscvqpdp, xscvqpdpo, xscvqpsdz, xscvqpswz, xscvqpudz, xscvqpuwz, xscvsdqp, xscvudqp, xsdivqp, xsdivqpo, xsiexpdp, xsiexpqp, xsmaddqp, xsmaddqpo, xsmaxcdp, xsmaxjdp, xsmincdp, xsminjdp, xsmsubqp, xsmsubqpo, xsmulqp, xsmulqpo, xsnabsqp, xsnegqp, xsnmaddqp, xsnmaddqpo, xsnmsubqp, xsnmsubqpo, xsrqpi, xsrqpix, xsrqpxp, xssqrtqp, xssqrtqpo, xssubqp, xssubqpo, xststdcdp, xststdcqp, xststdcsp, xsxexpdp, xsxexpqp, xsxsigdp, xsxsigqp, xvcmpnedp, xvcmpnedp., xvcmpnesp, xvcmpnesp., xvcvhpsp, xvcvsphp, xviexpdp, xviexpsp, xvtstdcdp, xvtstdcsp, xvxexpdp, xvxexpsp, xvxsigdp, xvxsigsp, xxbrd, xxbrh, xxbrq, xxbrw, xxextractuw, xxinsertw, xxperm, xxpermr, xxspltib>: New instructions. <doze, nap, sleep, rvwinkle, waitasec, lxvx, stxvx>: Disable on POWER9. <tlbiel, tlbie, sync, slbmfev, slbmfee>: Add additional operands. include/elf/ * ppc.h (R_PPC_REL16DX_HA): New reloction. * ppc64.h (R_PPC64_REL16DX_HA): Likewise. bfd/ * elf32-ppc.c (ppc_elf_howto_raw): Add R_PPC_REL16DX_HA. (ppc_elf_reloc_type_lookup): Handle R_PPC_REL16DX_HA. (ppc_elf_addr16_ha_reloc): Likewise. (ppc_elf_check_relocs): Likewise. (ppc_elf_relocate_section): Likewise. (is_insn_dq_form): Handle lxv and stxv instructions. * elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_REL16DX_HA. (ppc64_elf_reloc_type_lookup): Handle R_PPC64_REL16DX_HA. (ppc64_elf_ha_reloc): Likewise. (ppc64_elf_check_relocs): Likewise. (ppc64_elf_relocate_section): Likewise. * bfd-in2.h: Regenerate. * libbfd.h: Likewise. * reloc.c (BFD_RELOC_PPC_REL16DX_HA): New. elfcpp/ * powerpc.h (R_POWERPC_REL16DX_HA): Define. gas/ * doc/as.texinfo (Target PowerPC): Document -mpower9 and -mpwr9. * doc/c-ppc.texi (PowerPC-Opts): Likewise. * config/tc-ppc.c (md_show_usage): Likewise. (md_assemble): Handle BFD_RELOC_PPC_REL16DX_HA. (md_apply_fix): Likewise. (ppc_handle_align): Handle power9's group ending nop. gas/testsuite/ * gas/ppc/altivec3.s: New test. * gas/ppc/altivec3.d: Likewise. * gas/ppc/vsx3.s: Likewise. * gas/ppc/vsx3.d: Likewise. * gas/ppc/power9.s: Likewise. * gas/ppc/power9.d: Likewise. * gas/ppc/ppc.exp: Run them. * gas/ppc/power8.s <lxvx, lxvd2x, stxvx, stxvd2x>: Add new tests. * gas/ppc/power8.d: Likewise. * gas/ppc/vsx.s: <lxvx, stxvx>: Rename invalid mnemonics ... <lxvd2x, stxvd2x>: ...to this. * gas/ppc/vsx.d: Likewise. gold/ * gold/powerpc.cc (Powerpc_relocate_functions::addr16_dq): New function. (Powerpc_relocate_functions::addr16dx_ha): Likewise. (Target_powerpc::Scan::local): Handle R_POWERPC_REL16DX_HA. (Target_powerpc::Scan::global): Likewise. (Target_powerpc::Relocate::relocate): Likewise. ld/testsuite/ * ld-powerpc/addpcis.d: New test. * ld-powerpc/addpcis.s: New test. * ld-powerpc/powerpc.exp: Run it.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog18
-rw-r--r--bfd/bfd-in2.h1
-rw-r--r--bfd/elf32-ppc.c97
-rw-r--r--bfd/elf64-ppc.c95
-rw-r--r--bfd/libbfd.h1
-rw-r--r--bfd/reloc.c2
6 files changed, 182 insertions, 32 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index b746413..bde7118 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,21 @@
+2015-11-11 Alan Modra <amodra@gmail.com>
+ Peter Bergner <bergner@vnet.ibm.com>
+
+ * elf32-ppc.c (ppc_elf_howto_raw): Add R_PPC_REL16DX_HA.
+ (ppc_elf_reloc_type_lookup): Handle R_PPC_REL16DX_HA.
+ (ppc_elf_addr16_ha_reloc): Likewise.
+ (ppc_elf_check_relocs): Likewise.
+ (ppc_elf_relocate_section): Likewise.
+ (is_insn_dq_form): Handle lxv and stxv instructions.
+ * elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_REL16DX_HA.
+ (ppc64_elf_reloc_type_lookup): Handle R_PPC64_REL16DX_HA.
+ (ppc64_elf_ha_reloc): Likewise.
+ (ppc64_elf_check_relocs): Likewise.
+ (ppc64_elf_relocate_section): Likewise.
+ * bfd-in2.h: Regenerate.
+ * libbfd.h: Likewise.
+ * reloc.c (BFD_RELOC_PPC_REL16DX_HA): New.
+
2015-11-10 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_relocate_section): Handle VTINHERIT
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 900b45c..3780ba2 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3303,6 +3303,7 @@ instruction. */
BFD_RELOC_PPC_VLE_SDAREL_HI16D,
BFD_RELOC_PPC_VLE_SDAREL_HA16A,
BFD_RELOC_PPC_VLE_SDAREL_HA16D,
+ BFD_RELOC_PPC_REL16DX_HA,
BFD_RELOC_PPC64_HIGHER,
BFD_RELOC_PPC64_HIGHER_S,
BFD_RELOC_PPC64_HIGHEST,
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 5c26077..017de65 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -1731,6 +1731,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
+ /* Like R_PPC_REL16_HA but for split field in addpcis. */
+ HOWTO (R_PPC_REL16DX_HA, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc_elf_addr16_ha_reloc, /* special_function */
+ "R_PPC_REL16DX_HA", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x1fffc1, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
/* GNU extension to record C++ vtable hierarchy. */
HOWTO (R_PPC_GNU_VTINHERIT, /* type */
0, /* rightshift */
@@ -1989,6 +2004,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break;
case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break;
case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break;
+ case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break;
case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break;
}
@@ -2058,7 +2074,10 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
- bfd_vma relocation;
+ enum elf_ppc_reloc_type r_type;
+ long insn;
+ bfd_size_type octets;
+ bfd_vma value;
if (output_bfd != NULL)
{
@@ -2066,20 +2085,28 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
return bfd_reloc_ok;
}
- if (bfd_is_com_section (symbol->section))
- relocation = 0;
- else
- relocation = symbol->value;
-
- relocation += symbol->section->output_section->vma;
- relocation += symbol->section->output_offset;
- relocation += reloc_entry->addend;
- if (reloc_entry->howto->pc_relative)
- relocation -= reloc_entry->address;
-
- reloc_entry->addend += (relocation & 0x8000) << 1;
-
- return bfd_reloc_continue;
+ reloc_entry->addend += 0x8000;
+ r_type = reloc_entry->howto->type;
+ if (r_type != R_PPC_REL16DX_HA)
+ return bfd_reloc_continue;
+
+ value = 0;
+ if (!bfd_is_com_section (symbol->section))
+ value = symbol->value;
+ value += (reloc_entry->addend
+ + symbol->section->output_offset
+ + symbol->section->output_section->vma);
+ value -= (reloc_entry->address
+ + input_section->output_offset
+ + input_section->output_section->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);
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+ return bfd_reloc_ok;
}
static bfd_reloc_status_type
@@ -4247,6 +4274,7 @@ ppc_elf_check_relocs (bfd *abfd,
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
ppc_elf_tdata (abfd)->has_rel16 = 1;
break;
@@ -7604,7 +7632,9 @@ is_insn_ds_form (unsigned int insn)
static bfd_boolean
is_insn_dq_form (unsigned int insn)
{
- return (insn & (0x3f << 26)) == 56u << 26; /* lq */
+ return ((insn & (0x3f << 26)) == 56u << 26 /* lq */
+ || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */
+ && (insn & 3) == 1));
}
/* The RELOCATE_SECTION function is called by the ELF backend linker
@@ -8605,6 +8635,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
break;
case R_PPC_REL32:
@@ -9311,6 +9342,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_ADDR16_HA:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
case R_PPC_SECTOFF_HA:
case R_PPC_TPREL16_HA:
case R_PPC_DTPREL16_HA:
@@ -9369,10 +9401,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
mask = 15;
else
break;
- lobit = mask & (relocation + addend);
+ relocation += addend;
+ addend = insn & mask;
+ lobit = mask & relocation;
if (lobit != 0)
{
- addend -= lobit;
+ relocation ^= lobit;
info->callbacks->einfo
(_("%P: %H: error: %s against `%s' not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
@@ -9380,7 +9414,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
}
- addend += insn & mask;
}
break;
}
@@ -9439,8 +9472,30 @@ ppc_elf_relocate_section (bfd *output_bfd,
}
}
- r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
- rel->r_offset, relocation, addend);
+ if (r_type == R_PPC_REL16DX_HA)
+ {
+ /* Split field reloc isn't handled by _bfd_final_link_relocate. */
+ if (rel->r_offset + 4 > input_section->size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ unsigned int insn;
+
+ relocation += addend;
+ relocation -= (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ relocation >>= 16;
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn &= ~0x1fffc1;
+ insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ r = bfd_reloc_ok;
+ }
+ }
+ else
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index f491a09..42356d8 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -2022,6 +2022,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
+ /* Like R_PPC64_REL16_HA but for split field in addpcis. */
+ HOWTO (R_PPC64_REL16DX_HA, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc64_elf_ha_reloc, /* special_function */
+ "R_PPC64_REL16DX_HA", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x1fffc1, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
/* Like R_PPC64_ADDR16_HI, but no overflow. */
HOWTO (R_PPC64_ADDR16_HIGH, /* type */
16, /* rightshift */
@@ -2412,6 +2427,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_REL16DX_HA: r = R_PPC64_REL16DX_HA;
+ break;
case BFD_RELOC_PPC64_ADDR64_LOCAL: r = R_PPC64_ADDR64_LOCAL;
break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT;
@@ -2466,6 +2483,11 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section,
bfd *output_bfd, char **error_message)
{
+ enum elf_ppc64_reloc_type r_type;
+ long insn;
+ bfd_size_type octets;
+ bfd_vma value;
+
/* If this is a relocatable link (output_bfd test tells us), just
call the generic function. Any adjustment will be done at final
link time. */
@@ -2477,7 +2499,29 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
We won't actually be using the low 16 bits, so trashing them
doesn't matter. */
reloc_entry->addend += 0x8000;
- return bfd_reloc_continue;
+ r_type = reloc_entry->howto->type;
+ if (r_type != R_PPC64_REL16DX_HA)
+ return bfd_reloc_continue;
+
+ value = 0;
+ if (!bfd_is_com_section (symbol->section))
+ value = symbol->value;
+ value += (reloc_entry->addend
+ + symbol->section->output_offset
+ + symbol->section->output_section->vma);
+ value -= (reloc_entry->address
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ value = (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);
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+ if (value + 0x8000 > 0xffff)
+ return bfd_reloc_overflow;
+ return bfd_reloc_ok;
}
static bfd_reloc_status_type
@@ -5502,6 +5546,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_REL16_LO:
case R_PPC64_REL16_HI:
case R_PPC64_REL16_HA:
+ case R_PPC64_REL16DX_HA:
break;
/* Not supported as a dynamic relocation. */
@@ -14430,6 +14475,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_REL16_LO:
case R_PPC64_REL16_HI:
case R_PPC64_REL16_HA:
+ case R_PPC64_REL16DX_HA:
break;
case R_PPC64_REL14:
@@ -14842,6 +14888,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
break;
case R_PPC64_REL16_HA:
+ case R_PPC64_REL16DX_HA:
case R_PPC64_ADDR16_HA:
case R_PPC64_ADDR16_HIGHA:
case R_PPC64_ADDR16_HIGHERA:
@@ -14897,16 +14944,20 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_DTPREL16_LO_DS:
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
mask = 3;
- /* If this reloc is against an lq insn, then the value must be
- a multiple of 16. This is somewhat of a hack, but the
- "correct" way to do this by defining _DQ forms of all the
- _DS relocs bloats all reloc switches in this file. It
- doesn't seem to make much sense to use any of these relocs
- in data, so testing the insn should be safe. */
- if ((insn & (0x3f << 26)) == (56u << 26))
+ /* If this reloc is against an lq, lxv, or stxv insn, then
+ the value must be a multiple of 16. This is somewhat of
+ a hack, but the "correct" way to do this by defining _DQ
+ forms of all the _DS relocs bloats all reloc switches in
+ this file. It doesn't make much sense to use these
+ relocs in data, so testing the insn should be safe. */
+ if ((insn & (0x3f << 26)) == (56u << 26)
+ || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1))
mask = 15;
- if (((relocation + addend) & mask) != 0)
+ relocation += addend;
+ addend = insn & (mask ^ 3);
+ if ((relocation & mask) != 0)
{
+ relocation ^= relocation & mask;
info->callbacks->einfo
(_("%P: %H: error: %s not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
@@ -14964,8 +15015,30 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
}
- r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
- rel->r_offset, relocation, addend);
+ if (r_type == R_PPC64_REL16DX_HA)
+ {
+ /* Split field reloc isn't handled by _bfd_final_link_relocate. */
+ if (rel->r_offset + 4 > input_section->size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ relocation += addend;
+ relocation -= (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ relocation = (bfd_signed_vma) relocation >> 16;
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn &= ~0x1fffc1;
+ insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ r = bfd_reloc_ok;
+ if (relocation + 0x8000 > 0xffff)
+ r = bfd_reloc_overflow;
+ }
+ }
+ else
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index eef13c5..a095d7c 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1391,6 +1391,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC_VLE_SDAREL_HI16D",
"BFD_RELOC_PPC_VLE_SDAREL_HA16A",
"BFD_RELOC_PPC_VLE_SDAREL_HA16D",
+ "BFD_RELOC_PPC_REL16DX_HA",
"BFD_RELOC_PPC64_HIGHER",
"BFD_RELOC_PPC64_HIGHER_S",
"BFD_RELOC_PPC64_HIGHEST",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index fad9d21..bbc376e 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2890,6 +2890,8 @@ ENUMX
ENUMX
BFD_RELOC_PPC_VLE_SDAREL_HA16D
ENUMX
+ BFD_RELOC_PPC_REL16DX_HA
+ENUMX
BFD_RELOC_PPC64_HIGHER
ENUMX
BFD_RELOC_PPC64_HIGHER_S