diff options
Diffstat (limited to 'bfd/elfxx-mips.c')
-rw-r--r-- | bfd/elfxx-mips.c | 84 |
1 files changed, 65 insertions, 19 deletions
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 932167c15c6..618fb43540c 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) |