|| 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.  */
 {
   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);
   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,
   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;
 
 
   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);
   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,
 
   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.  */
     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;
    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;
   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;
 
 
 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)
 
   /* 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);
 
              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.  */
                  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;
                                         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)