aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elf32-mips.c11
-rw-r--r--bfd/elf64-mips.c7
-rw-r--r--bfd/elfn32-mips.c7
-rw-r--r--bfd/elfxx-mips.c84
-rw-r--r--bfd/elfxx-mips.h9
5 files changed, 96 insertions, 22 deletions
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 3f92df6..be28d1a 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -1790,6 +1790,10 @@ _bfd_mips_elf32_gprel16_reloc (bfd *abfd, arelent *reloc_entry,
if (ret != bfd_reloc_ok)
return ret;
+ if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
+ check_shuffle))
+ return bfd_reloc_outofrange;
+
location = (bfd_byte *) data + reloc_entry->address;
_bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
@@ -1857,7 +1861,8 @@ gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
+ check_inplace))
return bfd_reloc_outofrange;
/* Set val to the offset into the section or symbol. */
@@ -1956,6 +1961,10 @@ mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
if (ret != bfd_reloc_ok)
return ret;
+ if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
+ check_shuffle))
+ return bfd_reloc_outofrange;
+
location = (bfd_byte *) data + reloc_entry->address;
_bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
index e3ee0b9..419d9bc 100644
--- a/bfd/elf64-mips.c
+++ b/bfd/elf64-mips.c
@@ -3580,7 +3580,8 @@ mips_elf64_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
+ check_inplace))
return bfd_reloc_outofrange;
/* Set val to the offset into the section or symbol. */
@@ -3661,6 +3662,10 @@ mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
if (ret != bfd_reloc_ok)
return ret;
+ if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
+ check_shuffle))
+ return bfd_reloc_outofrange;
+
location = (bfd_byte *) data + reloc_entry->address;
_bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
index ac604ed..d222d1a 100644
--- a/bfd/elfn32-mips.c
+++ b/bfd/elfn32-mips.c
@@ -3411,7 +3411,8 @@ gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
+ reloc_entry->address))
return bfd_reloc_outofrange;
if (reloc_entry->howto->src_mask == 0)
@@ -3491,6 +3492,10 @@ mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
if (ret != bfd_reloc_ok)
return ret;
+ if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
+ check_shuffle))
+ return bfd_reloc_outofrange;
+
location = (bfd_byte *) data + reloc_entry->address;
_bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 932167c..618fb43 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -2346,13 +2346,19 @@ tls_gottprel_reloc_p (unsigned int r_type)
|| r_type == R_MICROMIPS_TLS_GOTTPREL);
}
+static inline bool
+needs_shuffle (int r_type)
+{
+ return mips16_reloc_p (r_type) || micromips_reloc_shuffle_p (r_type);
+}
+
void
_bfd_mips_elf_reloc_unshuffle (bfd *abfd, int r_type,
bool jal_shuffle, bfd_byte *data)
{
bfd_vma first, second, val;
- if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
+ if (!needs_shuffle (r_type))
return;
/* Pick up the first and second halfwords of the instruction. */
@@ -2375,7 +2381,7 @@ _bfd_mips_elf_reloc_shuffle (bfd *abfd, int r_type,
{
bfd_vma first, second, val;
- if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
+ if (!needs_shuffle (r_type))
return;
val = bfd_get_32 (abfd, data);
@@ -2399,6 +2405,32 @@ _bfd_mips_elf_reloc_shuffle (bfd *abfd, int r_type,
bfd_put_16 (abfd, first, data);
}
+/* Perform reloc offset checking.
+ We can only use bfd_reloc_offset_in_range, which takes into account
+ the size of the field being relocated, when section contents will
+ be accessed because mips object files may use relocations that seem
+ to access beyond section limits.
+ gas/testsuite/gas/mips/dla-reloc.s is an example that puts
+ R_MIPS_SUB, a 64-bit relocation, on the last instruction in the
+ section. The R_MIPS_SUB applies to the addend for the next reloc
+ rather than the section contents.
+
+ CHECK is CHECK_STD for the standard bfd_reloc_offset_in_range check,
+ CHECK_INPLACE to only check partial_inplace relocs, and
+ CHECK_SHUFFLE to only check relocs that shuffle/unshuffle. */
+
+bool
+_bfd_mips_reloc_offset_in_range (bfd *abfd, asection *input_section,
+ arelent *reloc_entry, enum reloc_check check)
+{
+ if (check == check_inplace && !reloc_entry->howto->partial_inplace)
+ return true;
+ if (check == check_shuffle && !needs_shuffle (reloc_entry->howto->type))
+ return true;
+ return bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+ input_section, reloc_entry->address);
+}
+
bfd_reloc_status_type
_bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
arelent *reloc_entry, asection *input_section,
@@ -2416,9 +2448,6 @@ _bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
- return bfd_reloc_outofrange;
-
/* Set val to the offset into the section or symbol. */
val = reloc_entry->addend;
@@ -2433,6 +2462,10 @@ _bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
if (reloc_entry->howto->partial_inplace)
{
+ if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
+ reloc_entry->address))
+ return bfd_reloc_outofrange;
+
status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
(bfd_byte *) data
+ reloc_entry->address);
@@ -2534,7 +2567,8 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
bfd_vma vallo;
bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
+ reloc_entry->address))
return bfd_reloc_outofrange;
_bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
@@ -2597,7 +2631,9 @@ _bfd_mips_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
relocatable = (output_bfd != NULL);
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
+ (relocatable
+ ? check_inplace : check_std)))
return bfd_reloc_outofrange;
/* Build up the field adjustment in VAL. */
@@ -5819,6 +5855,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
case R_MICROMIPS_CALL_LO16:
if (resolved_to_zero
&& !bfd_link_relocatable (info)
+ && bfd_reloc_offset_in_range (howto, input_bfd, input_section,
+ relocation->r_offset)
&& mips_elf_nullify_got_load (input_bfd, contents,
relocation, howto, true))
return bfd_reloc_continue;
@@ -8142,7 +8180,8 @@ mips_elf_rel_relocation_p (bfd *abfd, asection *sec,
of the section that REL is against. */
static bfd_vma
-mips_elf_read_rel_addend (bfd *abfd, const Elf_Internal_Rela *rel,
+mips_elf_read_rel_addend (bfd *abfd, asection *sec,
+ const Elf_Internal_Rela *rel,
reloc_howto_type *howto, bfd_byte *contents)
{
bfd_byte *location;
@@ -8150,6 +8189,9 @@ mips_elf_read_rel_addend (bfd *abfd, const Elf_Internal_Rela *rel,
bfd_vma addend;
bfd_vma bytes;
+ if (!bfd_reloc_offset_in_range (howto, abfd, sec, rel->r_offset))
+ return 0;
+
r_type = ELF_R_TYPE (abfd, rel->r_info);
location = contents + rel->r_offset;
@@ -8176,6 +8218,7 @@ mips_elf_read_rel_addend (bfd *abfd, const Elf_Internal_Rela *rel,
static bool
mips_elf_add_lo16_rel_addend (bfd *abfd,
+ asection *sec,
const Elf_Internal_Rela *rel,
const Elf_Internal_Rela *relend,
bfd_byte *contents, bfd_vma *addend)
@@ -8218,7 +8261,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
/* Obtain the addend kept there. */
lo16_howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, lo16_type, false);
- l = mips_elf_read_rel_addend (abfd, lo16_relocation, lo16_howto, contents);
+ l = mips_elf_read_rel_addend (abfd, sec, lo16_relocation, lo16_howto,
+ contents);
l <<= lo16_howto->rightshift;
l = _bfd_mips_elf_sign_extend (l, 16);
@@ -8685,11 +8729,12 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
rel_reloc = mips_elf_rel_relocation_p (abfd, sec, relocs, rel);
howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, !rel_reloc);
-
- if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
- false))
- if (!mips_elf_define_absolute_zero (abfd, info, htab, r_type))
- return false;
+ if (bfd_reloc_offset_in_range (howto, abfd, sec, rel->r_offset))
+ if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
+ false))
+ if (!mips_elf_define_absolute_zero (abfd, info, htab,
+ r_type))
+ return false;
}
/* Fall through. */
@@ -8903,10 +8948,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (!mips_elf_get_section_contents (abfd, sec, &contents))
return false;
howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, false);
- addend = mips_elf_read_rel_addend (abfd, rel,
+ addend = mips_elf_read_rel_addend (abfd, sec, rel,
howto, contents);
if (got16_reloc_p (r_type))
- mips_elf_add_lo16_rel_addend (abfd, rel, rel_end,
+ mips_elf_add_lo16_rel_addend (abfd, sec, rel, rel_end,
contents, &addend);
else
addend <<= howto->rightshift;
@@ -10423,14 +10468,15 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
relocs, rel))
{
rela_relocation_p = false;
- addend = mips_elf_read_rel_addend (input_bfd, rel,
- howto, contents);
+ addend = mips_elf_read_rel_addend (input_bfd, input_section,
+ rel, howto, contents);
if (hi16_reloc_p (r_type)
|| (got16_reloc_p (r_type)
&& mips_elf_local_relocation_p (input_bfd, rel,
local_sections)))
{
- if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend,
+ if (!mips_elf_add_lo16_rel_addend (input_bfd, input_section,
+ rel, relend,
contents, &addend))
{
if (h)
diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
index af6d14c..6b22fda 100644
--- a/bfd/elfxx-mips.h
+++ b/bfd/elfxx-mips.h
@@ -22,6 +22,13 @@
#include "elf/internal.h"
#include "elf/mips.h"
+enum reloc_check
+{
+ check_std,
+ check_inplace,
+ check_shuffle
+};
+
extern bool _bfd_mips_elf_mkobject
(bfd *);
extern bool _bfd_mips_elf_new_section_hook
@@ -129,6 +136,8 @@ extern void _bfd_mips_elf_reloc_unshuffle
(bfd *, int, bool, bfd_byte *);
extern void _bfd_mips_elf_reloc_shuffle
(bfd *, int, bool, bfd_byte *);
+extern bool _bfd_mips_reloc_offset_in_range
+ (bfd *, asection *, arelent *, enum reloc_check);
extern bfd_reloc_status_type _bfd_mips_elf_gprel16_with_gp
(bfd *, asymbol *, arelent *, asection *, bool, void *, bfd_vma);
extern bfd_reloc_status_type _bfd_mips_elf32_gprel16_reloc