aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-09-09 10:59:24 +0930
committerAlan Modra <amodra@gmail.com>2021-09-10 18:04:18 +0930
commite7776f52fedcafc63619abb2928151cf5bbfcce2 (patch)
tree98dde7dad116279f7940c348ca6ffeb419e67f52 /bfd/elf32-ppc.c
parent9f81b99e2426d19760c20c07f8cd3ae5cd85e8df (diff)
downloadgdb-e7776f52fedcafc63619abb2928151cf5bbfcce2.zip
gdb-e7776f52fedcafc63619abb2928151cf5bbfcce2.tar.gz
gdb-e7776f52fedcafc63619abb2928151cf5bbfcce2.tar.bz2
PowerPC, sanity check r_offset in relocate_section
* elf32-ppc.c (offset_in_range): New function. (ppc_elf_vle_split16): Sanity check r_offset before accessing section contents. Return status. (ppc_elf_relocate_section): Sanity check r_offset before accessing section contents. Don't segfault on NULL howto.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c799
1 files changed, 442 insertions, 357 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index dd45da9..d6b798a 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -2856,6 +2856,15 @@ is_plt_seq_reloc (enum elf_ppc_reloc_type r_type)
|| r_type == R_PPC_PLTSEQ);
}
+/* Like bfd_reloc_offset_in_range but without a howto. Return true
+ iff a field of SIZE bytes at OFFSET is within SEC limits. */
+
+static bool
+offset_in_range (asection *sec, bfd_vma offset, size_t size)
+{
+ return offset <= sec->size && size <= sec->size - offset;
+}
+
static void
bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
{
@@ -3884,7 +3893,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
return true;
}
-static void
+static bfd_reloc_status_type
ppc_elf_vle_split16 (bfd *input_bfd,
asection *input_section,
unsigned long offset,
@@ -3895,6 +3904,8 @@ ppc_elf_vle_split16 (bfd *input_bfd,
{
unsigned int insn, opcode;
+ if (!offset_in_range (input_section, offset, 4))
+ return bfd_reloc_outofrange;
insn = bfd_get_32 (input_bfd, loc);
opcode = insn & E_OPCODE_MASK;
if (opcode == E_OR2I_INSN
@@ -3951,6 +3962,7 @@ ppc_elf_vle_split16 (bfd *input_bfd,
}
insn |= value & 0x7ff;
bfd_put_32 (input_bfd, insn, loc);
+ return bfd_reloc_ok;
}
static void
@@ -7132,7 +7144,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_GOT_TPREL16:
case R_PPC_GOT_TPREL16_LO:
if ((tls_mask & TLS_TLS) != 0
- && (tls_mask & TLS_TPREL) == 0)
+ && (tls_mask & TLS_TPREL) == 0
+ && offset_in_range (input_section, rel->r_offset - d_offset, 4))
{
bfd_vma insn;
@@ -7149,7 +7162,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_TLS:
if ((tls_mask & TLS_TLS) != 0
- && (tls_mask & TLS_TPREL) == 0)
+ && (tls_mask & TLS_TPREL) == 0
+ && offset_in_range (input_section, rel->r_offset, 4))
{
bfd_vma insn;
@@ -7170,13 +7184,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_GOT_TLSGD16_HI:
case R_PPC_GOT_TLSGD16_HA:
tls_gd = TLS_GDIE;
- if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+ && offset_in_range (input_section, rel->r_offset - d_offset, 4))
goto tls_gdld_hi;
break;
case R_PPC_GOT_TLSLD16_HI:
case R_PPC_GOT_TLSLD16_HA:
- if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+ && offset_in_range (input_section, rel->r_offset - d_offset, 4))
{
tls_gdld_hi:
if ((tls_mask & tls_gd) != 0)
@@ -7195,13 +7211,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_GOT_TLSGD16:
case R_PPC_GOT_TLSGD16_LO:
tls_gd = TLS_GDIE;
- if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+ && offset_in_range (input_section, rel->r_offset - d_offset, 4))
goto tls_ldgd_opt;
break;
case R_PPC_GOT_TLSLD16:
case R_PPC_GOT_TLSLD16_LO:
- if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+ && offset_in_range (input_section, rel->r_offset - d_offset, 4))
{
unsigned int insn1, insn2;
bfd_vma offset;
@@ -7229,7 +7247,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
/* IE */
insn1 &= (0x1f << 21) | (0x1f << 16);
insn1 |= 32u << 26; /* lwz */
- if (offset != (bfd_vma) -1)
+ if (offset != (bfd_vma) -1
+ && offset_in_range (input_section, offset, 4))
{
rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
insn2 = 0x7c631214; /* add 3,3,2 */
@@ -7262,7 +7281,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
}
r_type = R_PPC_TPREL16_HA;
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
- if (offset != (bfd_vma) -1)
+ if (offset != (bfd_vma) -1
+ && offset_in_range (input_section, offset, 4))
{
rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
rel[1].r_offset = offset + d_offset;
@@ -7284,7 +7304,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_TLSGD:
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
- && rel + 1 < relend)
+ && rel + 1 < relend
+ && offset_in_range (input_section, rel->r_offset, 4))
{
unsigned int insn2;
bfd_vma offset = rel->r_offset;
@@ -7319,7 +7340,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_TLSLD:
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
- && rel + 1 < relend)
+ && rel + 1 < relend
+ && offset_in_range (input_section, rel->r_offset, 4))
{
unsigned int insn2;
@@ -7372,48 +7394,50 @@ ppc_elf_relocate_section (bfd *output_bfd,
/* Branch not taken prediction relocations. */
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_REL14_BRNTAKEN:
- {
- unsigned int insn;
+ if (offset_in_range (input_section, rel->r_offset, 4))
+ {
+ unsigned int insn;
- insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
- insn &= ~BRANCH_PREDICT_BIT;
- insn |= branch_bit;
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn &= ~BRANCH_PREDICT_BIT;
+ insn |= branch_bit;
- from = (rel->r_offset
- + input_section->output_offset
- + input_section->output_section->vma);
+ from = (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
- /* Invert 'y' bit if not the default. */
- if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
- insn ^= BRANCH_PREDICT_BIT;
+ /* Invert 'y' bit if not the default. */
+ if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
+ insn ^= BRANCH_PREDICT_BIT;
- bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
- }
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ }
break;
case R_PPC_PLT16_HA:
- {
- unsigned int insn;
+ if (offset_in_range (input_section, rel->r_offset - d_offset, 4))
+ {
+ unsigned int insn;
- insn = bfd_get_32 (input_bfd,
- contents + rel->r_offset - d_offset);
- if ((insn & (0x3fu << 26)) == 15u << 26
- && (insn & (0x1f << 16)) != 0)
- {
- if (!bfd_link_pic (info))
- {
- /* Convert addis to lis. */
- insn &= ~(0x1f << 16);
- bfd_put_32 (input_bfd, insn,
- contents + rel->r_offset - d_offset);
- }
- }
- else if (bfd_link_pic (info))
- info->callbacks->einfo
- (_("%P: %H: error: %s with unexpected instruction %x\n"),
- input_bfd, input_section, rel->r_offset,
- "R_PPC_PLT16_HA", insn);
- }
+ insn = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - d_offset);
+ if ((insn & (0x3fu << 26)) == 15u << 26
+ && (insn & (0x1f << 16)) != 0)
+ {
+ if (!bfd_link_pic (info))
+ {
+ /* Convert addis to lis. */
+ insn &= ~(0x1f << 16);
+ bfd_put_32 (input_bfd, insn,
+ contents + rel->r_offset - d_offset);
+ }
+ }
+ else if (bfd_link_pic (info))
+ info->callbacks->einfo
+ (_("%P: %H: error: %s with unexpected instruction %x\n"),
+ input_bfd, input_section, rel->r_offset,
+ "R_PPC_PLT16_HA", insn);
+ }
break;
}
@@ -7429,7 +7453,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
variable defined in a shared library to PIC. */
unsigned int insn;
- if (r_type == R_PPC_ADDR16_HA)
+ if (r_type == R_PPC_ADDR16_HA
+ && offset_in_range (input_section, rel->r_offset - d_offset, 4))
{
insn = bfd_get_32 (input_bfd,
contents + rel->r_offset - d_offset);
@@ -7492,7 +7517,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
input_bfd, input_section, (uint64_t) rel->r_offset,
"R_PPC_ADDR16_HA", insn);
}
- else if (r_type == R_PPC_ADDR16_LO)
+ else if (r_type == R_PPC_ADDR16_LO
+ && offset_in_range (input_section,
+ rel->r_offset - d_offset, 4))
{
insn = bfd_get_32 (input_bfd,
contents + rel->r_offset - d_offset);
@@ -7616,9 +7643,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
switch (r_type)
{
default:
- /* xgettext:c-format */
- _bfd_error_handler (_("%pB: %s unsupported"),
- input_bfd, howto->name);
+ de_fault:
+ if (howto)
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: %s unsupported"),
+ input_bfd, howto->name);
+ else
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: reloc %#x unsupported"),
+ input_bfd, r_type);
bfd_set_error (bfd_error_bad_value);
ret = false;
@@ -7956,7 +7989,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_TPREL16_HA:
if (h != NULL
&& h->root.type == bfd_link_hash_undefweak
- && h->dynindx == -1)
+ && h->dynindx == -1
+ && offset_in_range (input_section, rel->r_offset - d_offset, 4))
{
/* Make this relocation against an undefined weak symbol
resolve to zero. This is really just a tweak, since
@@ -8224,66 +8258,73 @@ ppc_elf_relocate_section (bfd *output_bfd,
/* Fall through. */
case R_PPC_RELAX:
- {
- const int *stub;
- size_t size;
- size_t insn_offset = rel->r_offset;
- unsigned int insn;
-
- if (bfd_link_pic (info))
- {
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + rel->r_offset - 4);
- stub = shared_stub_entry;
- bfd_put_32 (input_bfd, stub[0], contents + insn_offset - 12);
- bfd_put_32 (input_bfd, stub[1], contents + insn_offset - 8);
- bfd_put_32 (input_bfd, stub[2], contents + insn_offset - 4);
- stub += 3;
- size = ARRAY_SIZE (shared_stub_entry) - 3;
- }
- else
- {
- stub = stub_entry;
- size = ARRAY_SIZE (stub_entry);
- }
-
- relocation += addend;
- if (bfd_link_relocatable (info))
- relocation = 0;
-
- /* First insn is HA, second is LO. */
- insn = *stub++;
- insn |= ((relocation + 0x8000) >> 16) & 0xffff;
- bfd_put_32 (input_bfd, insn, contents + insn_offset);
- insn_offset += 4;
+ if (bfd_link_pic (info)
+ ? offset_in_range (input_section, rel->r_offset - 12,
+ ARRAY_SIZE (shared_stub_entry) * 4)
+ : offset_in_range (input_section, rel->r_offset,
+ ARRAY_SIZE (stub_entry) * 4))
+ {
+ const int *stub;
+ size_t size;
+ size_t insn_offset = rel->r_offset;
+ unsigned int insn;
- insn = *stub++;
- insn |= relocation & 0xffff;
- bfd_put_32 (input_bfd, insn, contents + insn_offset);
- insn_offset += 4;
- size -= 2;
+ if (bfd_link_pic (info))
+ {
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset - 4);
+ stub = shared_stub_entry;
+ bfd_put_32 (input_bfd, stub[0], contents + insn_offset - 12);
+ bfd_put_32 (input_bfd, stub[1], contents + insn_offset - 8);
+ bfd_put_32 (input_bfd, stub[2], contents + insn_offset - 4);
+ stub += 3;
+ size = ARRAY_SIZE (shared_stub_entry) - 3;
+ }
+ else
+ {
+ stub = stub_entry;
+ size = ARRAY_SIZE (stub_entry);
+ }
- while (size != 0)
- {
- insn = *stub++;
- --size;
- bfd_put_32 (input_bfd, insn, contents + insn_offset);
- insn_offset += 4;
- }
+ relocation += addend;
+ if (bfd_link_relocatable (info))
+ relocation = 0;
+
+ /* First insn is HA, second is LO. */
+ insn = *stub++;
+ insn |= ((relocation + 0x8000) >> 16) & 0xffff;
+ bfd_put_32 (input_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+
+ insn = *stub++;
+ insn |= relocation & 0xffff;
+ bfd_put_32 (input_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+ size -= 2;
+
+ while (size != 0)
+ {
+ insn = *stub++;
+ --size;
+ bfd_put_32 (input_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+ }
- /* Rewrite the reloc and convert one of the trailing nop
- relocs to describe this relocation. */
- BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
- /* The relocs are at the bottom 2 bytes */
- wrel->r_offset = rel->r_offset + d_offset;
- wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
- wrel->r_addend = rel->r_addend;
- memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel));
- wrel++, rel++;
- wrel->r_offset += 4;
- wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
- }
+ /* Rewrite the reloc and convert one of the trailing nop
+ relocs to describe this relocation. */
+ BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
+ /* The relocs are at the bottom 2 bytes */
+ wrel->r_offset = rel->r_offset + d_offset;
+ wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
+ wrel->r_addend = rel->r_addend;
+ memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel));
+ wrel++, rel++;
+ wrel->r_offset += 4;
+ wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
+ }
+ else
+ goto de_fault;
continue;
/* Indirect .sdata relocation. */
@@ -8487,151 +8528,164 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_VLE_LO16A:
relocation = relocation + addend;
- 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;
+ r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
+ goto report_reloc;
case R_PPC_VLE_LO16D:
relocation = relocation + addend;
- 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;
+ r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
+ goto report_reloc;
case R_PPC_VLE_HI16A:
relocation = (relocation + addend) >> 16;
- 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;
+ r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
+ goto report_reloc;
case R_PPC_VLE_HI16D:
relocation = (relocation + addend) >> 16;
- 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;
+ r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
+ goto report_reloc;
case R_PPC_VLE_HA16A:
relocation = (relocation + addend + 0x8000) >> 16;
- 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;
+ r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
+ goto report_reloc;
case R_PPC_VLE_HA16D:
relocation = (relocation + addend + 0x8000) >> 16;
- 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;
+ r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
+ goto report_reloc;
/* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */
case R_PPC_EMB_SDA21:
case R_PPC_VLE_SDA21:
case R_PPC_EMB_RELSDA:
case R_PPC_VLE_SDA21_LO:
- {
- const char *name;
- int reg;
- unsigned int insn;
- struct elf_link_hash_entry *sda = NULL;
+ if (!offset_in_range (input_section, rel->r_offset, 4))
+ {
+ r = bfd_reloc_outofrange;
+ goto report_reloc;
+ }
+ else
+ {
+ const char *name;
+ int reg;
+ unsigned int insn;
+ struct elf_link_hash_entry *sda = NULL;
- if (sec == NULL || sec->output_section == NULL)
- {
- unresolved_reloc = true;
- break;
- }
+ if (sec == NULL || sec->output_section == NULL)
+ {
+ unresolved_reloc = true;
+ break;
+ }
- name = bfd_section_name (sec->output_section);
- if (strcmp (name, ".sdata") == 0
- || strcmp (name, ".sbss") == 0)
- {
- reg = 13;
- sda = htab->sdata[0].sym;
- }
- else if (strcmp (name, ".sdata2") == 0
- || strcmp (name, ".sbss2") == 0)
- {
- reg = 2;
- sda = htab->sdata[1].sym;
- }
- else if (strcmp (name, ".PPC.EMB.sdata0") == 0
- || strcmp (name, ".PPC.EMB.sbss0") == 0)
- {
- reg = 0;
- }
- else
- {
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: the target (%s) of a %s relocation is "
- "in the wrong output section (%s)"),
- input_bfd,
- sym_name,
- howto->name,
- name);
+ name = bfd_section_name (sec->output_section);
+ if (strcmp (name, ".sdata") == 0
+ || strcmp (name, ".sbss") == 0)
+ {
+ reg = 13;
+ sda = htab->sdata[0].sym;
+ }
+ else if (strcmp (name, ".sdata2") == 0
+ || strcmp (name, ".sbss2") == 0)
+ {
+ reg = 2;
+ sda = htab->sdata[1].sym;
+ }
+ else if (strcmp (name, ".PPC.EMB.sdata0") == 0
+ || strcmp (name, ".PPC.EMB.sbss0") == 0)
+ {
+ reg = 0;
+ }
+ else
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: the target (%s) of a %s relocation is "
+ "in the wrong output section (%s)"),
+ input_bfd,
+ sym_name,
+ howto->name,
+ name);
+
+ bfd_set_error (bfd_error_bad_value);
+ ret = false;
+ goto copy_reloc;
+ }
- bfd_set_error (bfd_error_bad_value);
- ret = false;
- goto copy_reloc;
- }
+ if (sda != NULL)
+ {
+ if (!is_static_defined (sda))
+ {
+ unresolved_reloc = true;
+ break;
+ }
+ addend -= SYM_VAL (sda);
+ }
- if (sda != NULL)
- {
- if (!is_static_defined (sda))
- {
- unresolved_reloc = true;
- break;
- }
- addend -= SYM_VAL (sda);
- }
+ if (r_type == R_PPC_EMB_RELSDA)
+ break;
- if (r_type == R_PPC_EMB_RELSDA)
- break;
+ /* The PowerPC Embedded Application Binary Interface
+ version 1.0 insanely chose to specify R_PPC_EMB_SDA21
+ operating on a 24-bit field at r_offset. GNU as and
+ GNU ld have always assumed R_PPC_EMB_SDA21 operates on
+ a 32-bit bit insn at r_offset. Cope with object file
+ producers that possibly comply with the EABI in
+ generating an odd r_offset for big-endian objects. */
+ if (r_type == R_PPC_EMB_SDA21)
+ rel->r_offset &= ~1;
- /* The PowerPC Embedded Application Binary Interface
- version 1.0 insanely chose to specify R_PPC_EMB_SDA21
- operating on a 24-bit field at r_offset. GNU as and
- GNU ld have always assumed R_PPC_EMB_SDA21 operates on
- a 32-bit bit insn at r_offset. Cope with object file
- producers that possibly comply with the EABI in
- generating an odd r_offset for big-endian objects. */
- if (r_type == R_PPC_EMB_SDA21)
- rel->r_offset &= ~1;
-
- insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
- if (reg == 0
- && (r_type == R_PPC_VLE_SDA21
- || r_type == R_PPC_VLE_SDA21_LO))
- {
- relocation = relocation + addend;
- addend = 0;
-
- /* Force e_li insn, keeping RT from original insn. */
- insn &= 0x1f << 21;
- insn |= 28u << 26;
-
- /* We have an li20 field, bits 17..20, 11..15, 21..31. */
- /* Top 4 bits of value to 17..20. */
- insn |= (relocation & 0xf0000) >> 5;
- /* Next 5 bits of the value to 11..15. */
- insn |= (relocation & 0xf800) << 5;
- /* And the final 11 bits of the value to bits 21 to 31. */
- insn |= relocation & 0x7ff;
-
- bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
-
- if (r_type == R_PPC_VLE_SDA21
- && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
- goto overflow;
- goto copy_reloc;
- }
- /* Fill in register field. */
- insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
- bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
- }
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ if (reg == 0
+ && (r_type == R_PPC_VLE_SDA21
+ || r_type == R_PPC_VLE_SDA21_LO))
+ {
+ relocation = relocation + addend;
+ addend = 0;
+
+ /* Force e_li insn, keeping RT from original insn. */
+ insn &= 0x1f << 21;
+ insn |= 28u << 26;
+
+ /* We have an li20 field, bits 17..20, 11..15, 21..31. */
+ /* Top 4 bits of value to 17..20. */
+ insn |= (relocation & 0xf0000) >> 5;
+ /* Next 5 bits of the value to 11..15. */
+ insn |= (relocation & 0xf800) << 5;
+ /* And the final 11 bits of the value to bits 21 to 31. */
+ insn |= relocation & 0x7ff;
+
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r = bfd_reloc_ok;
+ if (r_type == R_PPC_VLE_SDA21
+ && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
+ r = bfd_reloc_overflow;
+ goto report_reloc;
+ }
+ /* Fill in register field. */
+ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ }
break;
case R_PPC_VLE_SDAREL_LO16A:
@@ -8640,95 +8694,113 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_VLE_SDAREL_HI16D:
case R_PPC_VLE_SDAREL_HA16A:
case R_PPC_VLE_SDAREL_HA16D:
- {
- bfd_vma value;
- const char *name;
- struct elf_link_hash_entry *sda = NULL;
-
- if (sec == NULL || sec->output_section == NULL)
- {
- unresolved_reloc = true;
- break;
- }
-
- name = bfd_section_name (sec->output_section);
- if (strcmp (name, ".sdata") == 0
- || strcmp (name, ".sbss") == 0)
- sda = htab->sdata[0].sym;
- else if (strcmp (name, ".sdata2") == 0
- || strcmp (name, ".sbss2") == 0)
- sda = htab->sdata[1].sym;
- else
- {
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: the target (%s) of a %s relocation is "
- "in the wrong output section (%s)"),
- input_bfd,
- sym_name,
- howto->name,
- name);
+ if (!offset_in_range (input_section, rel->r_offset, 4))
+ r = bfd_reloc_outofrange;
+ else
+ {
+ bfd_vma value;
+ const char *name;
+ struct elf_link_hash_entry *sda = NULL;
- bfd_set_error (bfd_error_bad_value);
- ret = false;
- goto copy_reloc;
- }
+ if (sec == NULL || sec->output_section == NULL)
+ {
+ unresolved_reloc = true;
+ break;
+ }
- if (sda == NULL || !is_static_defined (sda))
- {
- unresolved_reloc = true;
- break;
- }
- value = relocation + addend - SYM_VAL (sda);
+ name = bfd_section_name (sec->output_section);
+ if (strcmp (name, ".sdata") == 0
+ || strcmp (name, ".sbss") == 0)
+ sda = htab->sdata[0].sym;
+ else if (strcmp (name, ".sdata2") == 0
+ || strcmp (name, ".sbss2") == 0)
+ sda = htab->sdata[1].sym;
+ else
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: the target (%s) of a %s relocation is "
+ "in the wrong output section (%s)"),
+ input_bfd,
+ sym_name,
+ howto->name,
+ name);
+
+ bfd_set_error (bfd_error_bad_value);
+ ret = false;
+ goto copy_reloc;
+ }
- if (r_type == R_PPC_VLE_SDAREL_LO16A)
- 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, 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, 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, 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, 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, input_section, rel->r_offset,
- contents + rel->r_offset, value,
- split16d_type,
- htab->params->vle_reloc_fixup);
- }
- }
- goto copy_reloc;
+ if (sda == NULL || !is_static_defined (sda))
+ {
+ unresolved_reloc = true;
+ break;
+ }
+ value = relocation + addend - SYM_VAL (sda);
+
+ if (r_type == R_PPC_VLE_SDAREL_LO16A)
+ r = 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)
+ r = 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;
+ r = 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;
+ r = 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;
+ r = 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;
+ r = ppc_elf_vle_split16 (input_bfd, input_section,
+ rel->r_offset,
+ contents + rel->r_offset, value,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
+ }
+ else
+ abort ();
+ }
+ goto report_reloc;
case R_PPC_VLE_ADDR20:
- ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation);
- goto copy_reloc;
+ if (!offset_in_range (input_section, rel->r_offset, 4))
+ r = bfd_reloc_outofrange;
+ else
+ {
+ ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset,
+ relocation);
+ r = bfd_reloc_ok;
+ }
+ goto report_reloc;
/* Relocate against the beginning of the section. */
case R_PPC_SECTOFF:
@@ -8780,7 +8852,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
break;
case R_PPC_TPREL16_HA:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ if (htab->do_tls_opt
+ && relocation + addend + 0x8000 < 0x10000
+ && offset_in_range (input_section, rel->r_offset & ~3, 4))
+
{
bfd_byte *p = contents + (rel->r_offset & ~3);
bfd_put_32 (input_bfd, NOP, p);
@@ -8788,7 +8863,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
break;
case R_PPC_TPREL16_LO:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ if (htab->do_tls_opt
+ && relocation + addend + 0x8000 < 0x10000
+ && offset_in_range (input_section, rel->r_offset & ~3, 4))
{
bfd_byte *p = contents + (rel->r_offset & ~3);
unsigned int insn = bfd_get_32 (input_bfd, p);
@@ -8807,13 +8884,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_PLTCALL:
if (unresolved_reloc)
{
- bfd_byte *p = contents + rel->r_offset;
- unsigned int insn = bfd_get_32 (input_bfd, p);
- insn &= 1;
- bfd_put_32 (input_bfd, B | insn, p);
- unresolved_reloc = save_unresolved_reloc;
- r_type = R_PPC_REL24;
- howto = ppc_elf_howto_table[r_type];
+ if (offset_in_range (input_section, rel->r_offset, 4))
+ {
+ bfd_byte *p = contents + rel->r_offset;
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= 1;
+ bfd_put_32 (input_bfd, B | insn, p);
+ unresolved_reloc = save_unresolved_reloc;
+ r_type = R_PPC_REL24;
+ howto = ppc_elf_howto_table[r_type];
+ }
}
else if (htab->plt_type != PLT_NEW)
info->callbacks->einfo
@@ -8827,11 +8907,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_PLT16_LO:
if (unresolved_reloc)
{
- bfd_byte *p = contents + (rel->r_offset & ~3);
- bfd_put_32 (input_bfd, NOP, p);
- unresolved_reloc = false;
- r_type = R_PPC_NONE;
- howto = ppc_elf_howto_table[r_type];
+ if (offset_in_range (input_section, rel->r_offset & ~3, 4))
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ bfd_put_32 (input_bfd, NOP, p);
+ unresolved_reloc = false;
+ r_type = R_PPC_NONE;
+ howto = ppc_elf_howto_table[r_type];
+ }
}
else if (htab->plt_type != PLT_NEW)
info->callbacks->einfo
@@ -8893,36 +8976,37 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_GOT_DTPREL16_LO:
case R_PPC_GOT_TPREL16:
case R_PPC_GOT_TPREL16_LO:
- {
- /* The 32-bit ABI lacks proper relocations to deal with
- certain 64-bit instructions. Prevent damage to bits
- that make up part of the insn opcode. */
- unsigned int insn, mask, lobit;
-
- insn = bfd_get_32 (input_bfd,
- contents + rel->r_offset - d_offset);
- mask = 0;
- if (is_insn_ds_form (insn))
- mask = 3;
- else if (is_insn_dq_form (insn))
- mask = 15;
- else
- break;
- relocation += addend;
- addend = insn & mask;
- lobit = mask & relocation;
- if (lobit != 0)
- {
- relocation ^= lobit;
- info->callbacks->einfo
- /* xgettext:c-format */
- (_("%H: error: %s against `%s' not a multiple of %u\n"),
- input_bfd, input_section, rel->r_offset,
- howto->name, sym_name, mask + 1);
- bfd_set_error (bfd_error_bad_value);
- ret = false;
- }
- }
+ if (offset_in_range (input_section, rel->r_offset - d_offset, 4))
+ {
+ /* The 32-bit ABI lacks proper relocations to deal with
+ certain 64-bit instructions. Prevent damage to bits
+ that make up part of the insn opcode. */
+ unsigned int insn, mask, lobit;
+
+ insn = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - d_offset);
+ mask = 0;
+ if (is_insn_ds_form (insn))
+ mask = 3;
+ else if (is_insn_dq_form (insn))
+ mask = 15;
+ else
+ break;
+ relocation += addend;
+ addend = insn & mask;
+ lobit = mask & relocation;
+ if (lobit != 0)
+ {
+ relocation ^= lobit;
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%H: error: %s against `%s' not a multiple of %u\n"),
+ input_bfd, input_section, rel->r_offset,
+ howto->name, sym_name, mask + 1);
+ bfd_set_error (bfd_error_bad_value);
+ ret = false;
+ }
+ }
break;
}
@@ -8957,7 +9041,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
have different reloc types. */
if (howto->complain_on_overflow != complain_overflow_dont
&& howto->dst_mask == 0xffff
- && (input_section->flags & SEC_CODE) != 0)
+ && (input_section->flags & SEC_CODE) != 0
+ && offset_in_range (input_section, rel->r_offset & ~3, 4))
{
enum complain_overflow complain = complain_overflow_signed;
@@ -8984,7 +9069,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
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)
+ if (offset_in_range (input_section, rel->r_offset, 4))
r = bfd_reloc_outofrange;
else
{
@@ -9006,11 +9091,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
rel->r_offset, relocation, addend);
+ report_reloc:
if (r != bfd_reloc_ok)
{
if (r == bfd_reloc_overflow)
{
- overflow:
/* On code like "if (foo) foo();" don't report overflow
on a branch to zero when foo is undefined. */
if (!warned