aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2016-11-22 18:45:29 +1030
committerAlan Modra <amodra@gmail.com>2016-11-22 20:19:29 +1030
commit08dc996fedde9143cda25720961684087b133640 (patch)
tree9bb48db13193c8e0839bc213eb2fc9ca8a73adb8 /bfd/elf32-ppc.c
parent95f0d0d2338f8eba18d2b3c8cbe15b1d584b885c (diff)
PR20744, Incorrect PowerPC VLE relocs
VLE 16A and 16D relocs were functionally swapped. PR 20744 include/ * opcode/ppc.h: Define VLE insns using 16A and 16D relocs. bfd/ * elf32-ppc.h (struct ppc_elf_params): Add vle_reloc_fixup field. * elf32-ppc.c: Include opcode/ppc.h. (ppc_elf_howto_raw): Correct dst_mask for R_PPC_VLE_LO16A, R_PPC_VLE_LO16D, R_PPC_VLE_HI16A, R_PPC_VLE_HI16D, R_PPC_VLE_HA16A, R_PPC_VLE_HA16D, R_PPC_VLE_SDAREL_LO16A, R_PPC_VLE_SDAREL_LO16D, R_PPC_VLE_SDAREL_HI16A, R_PPC_VLE_SDAREL_HI16D, R_PPC_VLE_SDAREL_HA16A, and R_PPC_VLE_SDAREL_HA16D relocs. (ppc_elf_link_hash_table_create): Update default_params init. (ppc_elf_vle_split16): Correct shift and mask. Add params. Report or fix insn/reloc mismatches. (ppc_elf_relocate_section): Pass input_section, offset and fixup to ppc_elf_vle_split16. binutils/ * NEWS: Mention PowerPC VLE relocation error. gas/ * config/tc-ppc.c: Delete VLE insn defines. (md_assemble): Swap use_a_reloc and use_d_reloc. * testsuite/gas/ppc/vle-reloc.d: Update. ld/ * emultempl/ppc32elf.em (params): Update initializer. Handle --vle-reloc-fixup command line arg.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c141
1 files changed, 100 insertions, 41 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 75b0478d2b..efe7f69b83 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -35,6 +35,7 @@
#include "elf32-ppc.h"
#include "elf-vxworks.h"
#include "dwarf2.h"
+#include "opcode/ppc.h"
typedef enum split16_format_type
{
@@ -1455,7 +1456,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_LO16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f007ff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The 16 LSBS in split16d format. */
@@ -1470,7 +1471,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_LO16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 split16a format. */
@@ -1485,7 +1486,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_HI16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f007ff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 split16d format. */
@@ -1500,7 +1501,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_HI16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (High Adjusted) in split16a format. */
@@ -1515,7 +1516,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_HA16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f007ff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (High Adjusted) in split16d format. */
@@ -1530,7 +1531,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_HA16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
@@ -1577,7 +1578,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_SDAREL_LO16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f007ff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The 16 LSBS relative to _SDA_BASE_ in split16d format. */
@@ -1592,7 +1593,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_SDAREL_LO16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 relative to _SDA_BASE_ in split16a format. */
@@ -1607,7 +1608,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_SDAREL_HI16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f007ff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 relative to _SDA_BASE_ in split16d format. */
@@ -1622,7 +1623,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_SDAREL_HI16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */
@@ -1637,7 +1638,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_SDAREL_HA16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f007ff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */
@@ -1652,7 +1653,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
"R_PPC_VLE_SDAREL_HA16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_PPC_IRELATIVE, /* type */
@@ -3384,7 +3385,7 @@ ppc_elf_link_hash_table_create (bfd *abfd)
{
struct ppc_elf_link_hash_table *ret;
static struct ppc_elf_params default_params
- = { PLT_OLD, 0, 1, 0, 0, 12, 0, 0 };
+ = { PLT_OLD, 0, 1, 0, 0, 12, 0, 0, 0 };
ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
if (ret == NULL)
@@ -4925,16 +4926,56 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
static void
ppc_elf_vle_split16 (bfd *input_bfd,
+ asection *input_section,
+ unsigned long offset,
bfd_byte *loc,
bfd_vma value,
- split16_format_type split16_format)
+ split16_format_type split16_format,
+ bfd_boolean fixup)
{
- unsigned int insn, top5;
+ unsigned int insn, opcode, top5;
insn = bfd_get_32 (input_bfd, loc);
+ opcode = insn & 0xf300f800;
+ if (opcode == E_OR2I_INSN
+ || opcode == E_AND2I_DOT_INSN
+ || opcode == E_OR2IS_INSN
+ || opcode == E_LIS_INSN
+ || opcode == E_AND2IS_DOT_INSN)
+ {
+ if (split16_format != split16a_type)
+ {
+ if (fixup)
+ split16_format = split16a_type;
+ else
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B(%A+0x%lx): expected 16A style relocation on 0x%08x insn"),
+ input_bfd, input_section, offset, opcode);
+ }
+ }
+ else if (opcode == E_ADD2I_DOT_INSN
+ || opcode == E_ADD2IS_INSN
+ || opcode == E_CMP16I_INSN
+ || opcode == E_MULL2I_INSN
+ || opcode == E_CMPL16I_INSN
+ || opcode == E_CMPH16I_INSN
+ || opcode == E_CMPHL16I_INSN)
+ {
+ if (split16_format != split16d_type)
+ {
+ if (fixup)
+ split16_format = split16d_type;
+ else
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B(%A+0x%lx): expected 16D style relocation on 0x%08x insn"),
+ input_bfd, input_section, offset, opcode);
+ }
+ }
top5 = value & 0xf800;
- top5 = top5 << (split16_format == split16a_type ? 9 : 5);
- insn &= (split16_format == split16a_type ? ~0x1f007ff : ~0x1f07ff);
+ top5 = top5 << (split16_format == split16a_type ? 5 : 9);
+ insn &= (split16_format == split16a_type ? ~0x1f07ff : ~0x1f007ff);
insn |= top5;
insn |= value & 0x7ff;
bfd_put_32 (input_bfd, insn, loc);
@@ -9220,38 +9261,44 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_VLE_LO16A:
relocation = relocation + addend;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- relocation, split16a_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type, htab->params->vle_reloc_fixup);
goto copy_reloc;
case R_PPC_VLE_LO16D:
relocation = relocation + addend;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- relocation, split16d_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type, htab->params->vle_reloc_fixup);
goto copy_reloc;
case R_PPC_VLE_HI16A:
relocation = (relocation + addend) >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- relocation, split16a_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type, htab->params->vle_reloc_fixup);
goto copy_reloc;
case R_PPC_VLE_HI16D:
relocation = (relocation + addend) >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- relocation, split16d_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type, htab->params->vle_reloc_fixup);
goto copy_reloc;
case R_PPC_VLE_HA16A:
relocation = (relocation + addend + 0x8000) >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- relocation, split16a_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type, htab->params->vle_reloc_fixup);
goto copy_reloc;
case R_PPC_VLE_HA16D:
relocation = (relocation + addend + 0x8000) >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- relocation, split16d_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type, htab->params->vle_reloc_fixup);
goto copy_reloc;
/* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */
@@ -9414,34 +9461,46 @@ ppc_elf_relocate_section (bfd *output_bfd,
+ addend);
if (r_type == R_PPC_VLE_SDAREL_LO16A)
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- value, split16a_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
else if (r_type == R_PPC_VLE_SDAREL_LO16D)
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- value, split16d_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
else if (r_type == R_PPC_VLE_SDAREL_HI16A)
{
value = value >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- value, split16a_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
}
else if (r_type == R_PPC_VLE_SDAREL_HI16D)
{
value = value >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- value, split16d_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
}
else if (r_type == R_PPC_VLE_SDAREL_HA16A)
{
value = (value + 0x8000) >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- value, split16a_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
}
else if (r_type == R_PPC_VLE_SDAREL_HA16D)
{
value = (value + 0x8000) >> 16;
- ppc_elf_vle_split16 (input_bfd, contents + rel->r_offset,
- value, split16d_type);
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
}
}
goto copy_reloc;