+2017-11-28  Nick Clifton  <nickc@redhat.com>
+
+       PR 22506
+       * reloc.c (reloc_offset_in_range): Rename to
+       bfd_reloc_offset_in_range and export.
+       (bfd_perform_relocation): Rename function invocation.
+       (bfd_install_relocation): Likewise.
+       (bfd_final_link_relocate): Likewise.
+       * bfd-in2.h: Regenerate.
+       * coff-arm.c (coff_arm_reloc): Use bfd_reloc_offset_in_range.
+       * coff-i386.c (coff_i386_reloc): Likewise.
+       * coff-i860.c (coff_i860_reloc): Likewise.
+       * coff-m68k.c (mk68kcoff_common_addend_special_fn): Likewise.
+       * coff-m88k.c (m88k_special_reloc): Likewise.
+       * coff-mips.c (mips_reflo_reloc): Likewise.
+       * coff-x86_64.c (coff_amd64_reloc): Likewise.
+
 2017-11-28  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elf-m10300.c (mn10300_elf_check_relocs): Don't set
 
     unsigned int addrsize,
     bfd_vma relocation);
 
+bfd_boolean bfd_reloc_offset_in_range
+   (reloc_howto_type *howto,
+    bfd *abfd,
+    asection *section,
+    bfd_size_type offset);
+
 bfd_reloc_status_type bfd_perform_relocation
    (bfd *abfd,
     arelent *reloc_entry,
 
   x = ((x & ~howto->dst_mask)                                  \
        | (((x & howto->src_mask) + diff) & howto->dst_mask))
 
-    if (diff != 0)
-      {
-       reloc_howto_type *howto = reloc_entry->howto;
-       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+  if (diff != 0)
+    {
+      reloc_howto_type *howto = reloc_entry->howto;
+      unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
-       switch (howto->size)
-         {
-         case 0:
-           {
-             char x = bfd_get_8 (abfd, addr);
-             DOIT (x);
-             bfd_put_8 (abfd, x, addr);
-           }
-           break;
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+                                      reloc_entry->address
+                                      * bfd_octets_per_byte (abfd)))
+       return bfd_reloc_outofrange;
 
-         case 1:
-           {
-             short x = bfd_get_16 (abfd, addr);
-             DOIT (x);
-             bfd_put_16 (abfd, (bfd_vma) x, addr);
-           }
-           break;
+      switch (howto->size)
+       {
+       case 0:
+         {
+           char x = bfd_get_8 (abfd, addr);
+           DOIT (x);
+           bfd_put_8 (abfd, x, addr);
+         }
+         break;
 
-         case 2:
-           {
-             long x = bfd_get_32 (abfd, addr);
-             DOIT (x);
-             bfd_put_32 (abfd, (bfd_vma) x, addr);
-           }
-           break;
+       case 1:
+         {
+           short x = bfd_get_16 (abfd, addr);
+           DOIT (x);
+           bfd_put_16 (abfd, (bfd_vma) x, addr);
+         }
+         break;
 
-         default:
-           abort ();
+       case 2:
+         {
+           long x = bfd_get_32 (abfd, addr);
+           DOIT (x);
+           bfd_put_32 (abfd, (bfd_vma) x, addr);
          }
-      }
+         break;
+
+       default:
+         abort ();
+       }
+    }
 
   /* Now let bfd_perform_relocation finish everything up.  */
   return bfd_reloc_continue;
 
       reloc_howto_type *howto = reloc_entry->howto;
       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+                                      reloc_entry->address
+                                      * bfd_octets_per_byte (abfd)))
+       return bfd_reloc_outofrange;
+
       switch (howto->size)
        {
        case 0:
 
        reloc_howto_type *howto = reloc_entry->howto;
        unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
+       if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+                                        reloc_entry->address
+                                        * bfd_octets_per_byte (abfd)))
+         return bfd_reloc_outofrange;
+
        switch (howto->size)
          {
          case 0:
 
       reloc_howto_type *howto = reloc_entry->howto;
       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+                                      reloc_entry->address
+                                      * bfd_octets_per_byte (abfd)))
+       return bfd_reloc_outofrange;
+
       switch (howto->size)
        {
        case 0:
 
        {
          bfd_vma output_base = 0;
          bfd_vma addr = reloc_entry->address;
-         bfd_vma x = bfd_get_16 (abfd, (bfd_byte *) data + addr);
+         bfd_vma x;
          asection *reloc_target_output_section;
          long relocation = 0;
 
+         if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+                                          reloc_entry->address
+                                          * bfd_octets_per_byte (abfd)))
+           return bfd_reloc_outofrange;
+
+         x = bfd_get_16 (abfd, (bfd_byte *) data + addr);        
+
          /* Work out which section the relocation is targeted at and the
             initial relocation command value.  */
 
 
          unsigned long vallo;
          struct mips_hi *next;
 
+         if (! bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+                                          input_section,
+                                          reloc_entry->address
+                                          * bfd_octets_per_byte (abfd)))
+           return bfd_reloc_outofrange;
+         
          /* Do the REFHI relocation.  Note that we actually don't
             need to know anything about the REFLO itself, except
             where to find the low 16 bits of the addend needed by the
 
     {
       reloc_howto_type *howto = reloc_entry->howto;
       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
-
-      /* FIXME: We do not have an end address for data, so we cannot
-        accurately range check any addresses computed against it.
-        cf: PR binutils/17512: file: 1085-1761-0.004.
-        For now we do the best that we can.  */
-      if (addr < (unsigned char *) data
-         || addr > ((unsigned char *) data) + input_section->size)
-       {
-         bfd_set_error (bfd_error_bad_value);
-         return bfd_reloc_notsupported;
-       }
+      
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+                                      reloc_entry->address
+                                      * bfd_octets_per_byte (abfd)))
+       return bfd_reloc_outofrange;
 
       switch (howto->size)
        {
 
   return flag;
 }
 
+/*
+FUNCTION
+       bfd_reloc_offset_in_range
+
+SYNOPSIS
+       bfd_boolean bfd_reloc_offset_in_range
+          (reloc_howto_type *howto,
+           bfd *abfd,
+           asection *section,
+           bfd_size_type offset);
+
+DESCRIPTION
+        Returns TRUE if the reloc described by @var{HOWTO} can be
+       applied at @var{OFFSET} octets in @var{SECTION}.
+
+*/
+
 /* HOWTO describes a relocation, at offset OCTET.  Return whether the
    relocation field is within SECTION of ABFD.  */
 
-static bfd_boolean
-reloc_offset_in_range (reloc_howto_type *howto, bfd *abfd,
-                      asection *section, bfd_size_type octet)
+bfd_boolean
+bfd_reloc_offset_in_range (reloc_howto_type *howto,
+                          bfd *abfd,
+                          asection *section,
+                          bfd_size_type octet)
 {
   bfd_size_type octet_end = bfd_get_section_limit_octets (abfd, section);
   bfd_size_type reloc_size = bfd_get_reloc_size (howto);
   if (howto && howto->special_function)
     {
       bfd_reloc_status_type cont;
+
+      /* Note - we do not call bfd_reloc_offset_in_range here as the
+        reloc_entry->address field might actually be valid for the
+        backend concerned.  It is up to the special_function itself
+        to call bfd_reloc_offset_in_range if needed.  */
       cont = howto->special_function (abfd, reloc_entry, symbol, data,
                                      input_section, output_bfd,
                                      error_message);
 
   /* Is the address of the relocation really within the section?  */
   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
-  if (!reloc_offset_in_range (howto, abfd, input_section, octets))
+  if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
     return bfd_reloc_outofrange;
 
   /* Work out which section the relocation is targeted at and the
     {
       bfd_reloc_status_type cont;
 
+      /* Note - we do not call bfd_reloc_offset_in_range here as the
+        reloc_entry->address field might actually be valid for the
+        backend concerned.  It is up to the special_function itself
+        to call bfd_reloc_offset_in_range if needed.  */
       /* XXX - The special_function calls haven't been fixed up to deal
         with creating new relocations and section contents.  */
       cont = howto->special_function (abfd, reloc_entry, symbol,
 
   /* Is the address of the relocation really within the section?  */
   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
-  if (!reloc_offset_in_range (howto, abfd, input_section, octets))
+  if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
     return bfd_reloc_outofrange;
 
   /* Work out which section the relocation is targeted at and the
   bfd_size_type octets = address * bfd_octets_per_byte (input_bfd);
 
   /* Sanity check the address.  */
-  if (!reloc_offset_in_range (howto, input_bfd, input_section, octets))
+  if (!bfd_reloc_offset_in_range (howto, input_bfd, input_section, octets))
     return bfd_reloc_outofrange;
 
   /* This function assumes that we are dealing with a basic relocation