Blob Blame History Raw
diff -rup binutils.orig/binutils/objcopy.c binutils-2.29.1/binutils/objcopy.c
--- binutils.orig/binutils/objcopy.c	2018-01-03 16:06:45.005657092 +0000
+++ binutils-2.29.1/binutils/objcopy.c	2018-01-03 16:06:57.927502748 +0000
@@ -1905,84 +1905,229 @@ num_bytes (unsigned long val)
   return count;
 }
 
+typedef struct objcopy_internal_note
+{
+  Elf_Internal_Note  note;
+  bfd_vma            start;
+  bfd_vma            end;
+  bfd_boolean        modified;
+} objcopy_internal_note;
+  
+/* Returns TRUE if a gap does, or could, exist between the address range
+   covered by PNOTE1 and PNOTE2.  */
+
+static bfd_boolean
+gap_exists (objcopy_internal_note * pnote1,
+	    objcopy_internal_note * pnote2)
+{
+  /* Without range end notes, we assume that a gap might exist.  */
+  if (pnote1->end == 0 || pnote2->end == 0)
+    return TRUE;
+
+  /* FIXME: Alignment of 16 bytes taken from x86_64 binaries.
+     Really we should extract the alignment of the section covered by the notes.  */
+  return BFD_ALIGN (pnote1->end, 16) < pnote2->start;
+}
+
+static bfd_boolean
+is_open_note (objcopy_internal_note * pnote)
+{
+  return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN);
+}
+
+static bfd_boolean
+is_func_note (objcopy_internal_note * pnote)
+{
+  return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC);
+}
+
+static bfd_boolean
+is_64bit (bfd * abfd)
+{
+  /* Should never happen, but let's be paranoid.  */
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return FALSE;
+
+  return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64;
+}
+
 /* Merge the notes on SEC, removing redundant entries.
    Returns the new, smaller size of the section upon success.  */
 
 static bfd_size_type
 merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte * contents)
 {
-  Elf_Internal_Note * pnotes_end;
-  Elf_Internal_Note * pnotes;
-  Elf_Internal_Note * pnote;
+  objcopy_internal_note *  pnotes_end;
+  objcopy_internal_note *  pnotes = NULL;
+  objcopy_internal_note *  pnote;
   bfd_size_type       remain = size;
   unsigned            version_1_seen = 0;
   unsigned            version_2_seen = 0;
+  unsigned            version_3_seen = 0;
   bfd_boolean         duplicate_found = FALSE;
   const char *        err = NULL;
   bfd_byte *          in = contents;
   int                 attribute_type_byte;
   int                 val_start;
+  unsigned long       previous_func_start = 0;
+  unsigned long       previous_open_start = 0;
+  unsigned long       previous_func_end = 0;
+  unsigned long       previous_open_end = 0;
+  long                relsize;
+
 
-  /* Make a copy of the notes.
+  relsize = bfd_get_reloc_upper_bound (abfd, sec);
+  if (relsize > 0)
+    {
+      arelent **  relpp;
+      long        relcount;
+
+      /* If there are relocs associated with this section then we
+	 cannot safely merge it.  */
+      relpp = (arelent **) xmalloc (relsize);
+      relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
+      free (relpp);
+      if (relcount != 0)
+	goto done;
+    }
+  
+  /* Make a copy of the notes and convert to our internal format.
      Minimum size of a note is 12 bytes.  */
-  pnote = pnotes = (Elf_Internal_Note *) xcalloc ((size / 12), sizeof (Elf_Internal_Note));
+  pnote = pnotes = (objcopy_internal_note *) xcalloc ((size / 12), sizeof (* pnote));
   while (remain >= 12)
     {
-      pnote->namesz = (bfd_get_32 (abfd, in    ) + 3) & ~3;
-      pnote->descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
-      pnote->type   =  bfd_get_32 (abfd, in + 8);
+      bfd_vma start, end;
 
-      if (pnote->type    != NT_GNU_BUILD_ATTRIBUTE_OPEN
-	  && pnote->type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
+      pnote->note.namesz = (bfd_get_32 (abfd, in    ) + 3) & ~3;
+      pnote->note.descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
+      pnote->note.type   =  bfd_get_32 (abfd, in + 8);
+
+      if (pnote->note.type    != NT_GNU_BUILD_ATTRIBUTE_OPEN
+	  && pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
 	{
 	  err = _("corrupt GNU build attribute note: wrong note type");
 	  goto done;
 	}
 
-      if (pnote->namesz + pnote->descsz + 12 > remain)
+      if (pnote->note.namesz + pnote->note.descsz + 12 > remain)
 	{
 	  err = _("corrupt GNU build attribute note: note too big");
 	  goto done;
 	}
 
-      if (pnote->namesz < 2)
+      if (pnote->note.namesz < 2)
 	{
 	  err = _("corrupt GNU build attribute note: name too small");
 	  goto done;
 	}
 
-      if (pnote->descsz != 0
-	  && pnote->descsz != 4
-	  && pnote->descsz != 8)
+      pnote->note.namedata = (char *)(in + 12);
+      pnote->note.descdata = (char *)(in + 12 + pnote->note.namesz);
+
+      remain -= 12 + pnote->note.namesz + pnote->note.descsz;
+      in     += 12 + pnote->note.namesz + pnote->note.descsz;
+
+      if (pnote->note.namesz > 2
+	  && pnote->note.namedata[0] == '$'
+	  && pnote->note.namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
+	  && pnote->note.namedata[2] == '1')
+	++ version_1_seen;
+      else if (pnote->note.namesz > 4
+	       && pnote->note.namedata[0] == 'G'
+	       && pnote->note.namedata[1] == 'A'
+	       && pnote->note.namedata[2] == '$'
+	       && pnote->note.namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION)
 	{
+	  if (pnote->note.namedata[4] == '2')
+	    ++ version_2_seen;
+	  else if (pnote->note.namedata[4] == '3')
+	    ++ version_3_seen;
+	  else
+	    {
+	      err = _("corrupt GNU build attribute note: unsupported version");
+	      goto done;
+	    }
+	}
+
+      switch (pnote->note.descsz)
+	{
+	case 0:
+	  start = end = 0;
+	  break;
+
+	case 4:
+	  start = bfd_get_32 (abfd, pnote->note.descdata);
+	  /* FIXME: For version 1 and 2 notes we should try to
+	     calculate the end address by finding a symbol whose
+	     value is START, and then adding in its size.
+
+	     For now though, since v1 and v2 was not intended to
+	     handle gaps, we chose an artificially large end
+	     address.  */
+	  end = 0x7ffffffffffffffUL;
+	  break;
+	  
+	case 8:
+	  if (! is_64bit (abfd))
+	    {
+	      start = bfd_get_32 (abfd, pnote->note.descdata);
+	      end = bfd_get_32 (abfd, pnote->note.descdata + 4);
+	    }
+	  else
+	    {
+	      start = bfd_get_64 (abfd, pnote->note.descdata);
+	      /* FIXME: For version 1 and 2 notes we should try to
+		 calculate the end address by finding a symbol whose
+		 value is START, and then adding in its size.
+
+		 For now though, since v1 and v2 was not intended to
+		 handle gaps, we chose an artificially large end
+		 address.  */
+	      end = 0x7ffffffffffffffUL;
+	    }
+	  break;
+
+	case 16:
+	  start = bfd_get_64 (abfd, pnote->note.descdata);
+	  end = bfd_get_64 (abfd, pnote->note.descdata + 8);
+	  break;
+	  
+	default:
 	  err = _("corrupt GNU build attribute note: bad description size");
 	  goto done;
 	}
 
-      pnote->namedata = (char *)(in + 12);
-      pnote->descdata = (char *)(in + 12 + pnote->namesz);
+      if (is_open_note (pnote))
+	{
+	  if (start)
+	    previous_open_start = start;
+
+	  pnote->start = previous_open_start;
 
-      remain -= 12 + pnote->namesz + pnote->descsz;
-      in     += 12 + pnote->namesz + pnote->descsz;
+	  if (end)
+	    previous_open_end = end;
 
-      if (pnote->namedata[pnote->namesz - 1] != 0)
+	  pnote->end = previous_open_end;
+	}
+      else
+	{
+	  if (start)
+	    previous_func_start = start;
+
+	  pnote->start = previous_func_start;
+
+	  if (end)
+	    previous_func_end = end;
+
+	  pnote->end = previous_func_end;
+	}
+
+      if (pnote->note.namedata[pnote->note.namesz - 1] != 0)
 	{
 	  err = _("corrupt GNU build attribute note: name not NUL terminated");
 	  goto done;
 	}
-      
-      if (pnote->namesz > 2
-	  && pnote->namedata[0] == '$'
-	  && pnote->namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
-	  && pnote->namedata[2] == '1')
-	++ version_1_seen;
-      else if (pnote->namesz > 4
-	  && pnote->namedata[0] == 'G'
-	  && pnote->namedata[1] == 'A'
-	  && pnote->namedata[2] == '$'
-	  && pnote->namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION
-	  && pnote->namedata[4] == '2')
-	++ version_2_seen;
+
       pnote ++;
     }
 
@@ -1995,27 +2140,29 @@ merge_gnu_build_notes (bfd * abfd, asect
       goto done;
     }
 
-  if (version_1_seen == 0 && version_2_seen == 0)
+  if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0)
     {
       err = _("bad GNU build attribute notes: no known versions detected");
       goto done;
     }
 
-  if (version_1_seen > 0 && version_2_seen > 0)
+  if ((version_1_seen > 0 && version_2_seen > 0)
+      || (version_1_seen > 0 && version_3_seen > 0)
+      || (version_2_seen > 0 && version_3_seen > 0))
     {
       err = _("bad GNU build attribute notes: multiple different versions");
       goto done;
     }
 
   /* Merging is only needed if there is more than one version note...  */
-  if (version_1_seen == 1 || version_2_seen == 1)
+  if (version_1_seen == 1 || version_2_seen == 1 || version_3_seen == 1)
     goto done;
 
   attribute_type_byte = version_1_seen ? 1 : 3;
   val_start = attribute_type_byte + 1;
 
   /* The first note should be the first version note.  */
-  if (pnotes[0].namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
+  if (pnotes[0].note.namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
     {
       err = _("bad GNU build attribute notes: first note not version note");
       goto done;
@@ -2026,7 +2173,9 @@ merge_gnu_build_notes (bfd * abfd, asect
      2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes.
      3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same
         full name field as the immediately preceeding note with the same type
-	of name.
+	of name and whose address ranges coincide.
+	IE - it there are gaps in the coverage of the notes, then these gaps
+	must be preserved.
      4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes
         of type GNU_BUILD_ATTRIBUTE_STACK_SIZE.
      5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
@@ -2036,103 +2185,134 @@ merge_gnu_build_notes (bfd * abfd, asect
 	address to which it refers.  */
   for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++)
     {
-      Elf_Internal_Note * back;
-      Elf_Internal_Note * prev_open = NULL;
+      int                      note_type;
+      objcopy_internal_note *  back;
+      objcopy_internal_note *  prev_open_with_range = NULL;
 
-      if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC)
+      /* Rule 2 - preserve function notes.  */
+      if (! is_open_note (pnote))
 	continue;
 
-      /* Scan for duplicates.  Clear the type field of any found - but do not
-	 delete them just yet.  */
+      note_type = pnote->note.namedata[attribute_type_byte];
+
+      /* Scan backwards from pnote, looking for duplicates.
+	 Clear the type field of any found - but do not delete them just yet.  */
       for (back = pnote - 1; back >= pnotes; back --)
 	{
-	  if (back->descsz > 0
-	      && back->type != NT_GNU_BUILD_ATTRIBUTE_FUNC
-	      && prev_open == NULL)
-	    prev_open = back;
+	  int back_type = back->note.namedata[attribute_type_byte];
+
+	  /* If this is the first open note with an address
+	     range that	we have encountered then record it.  */
+	  if (prev_open_with_range == NULL
+	      && back->note.descsz > 0
+	      && ! is_func_note (back))
+	    prev_open_with_range = back;
+
+	  if (! is_open_note (back))
+	    continue;
+
+	  /* If the two notes are different then keep on searching.  */
+	  if (back_type != note_type)
+	    continue;
 
-	  if (back->type == pnote->type
-	      && back->namedata[attribute_type_byte] == pnote->namedata[attribute_type_byte])
+	  /* Rule 4 - combine stack size notes.  */
+	  if (back_type == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
 	    {
-	      if (back->namedata[attribute_type_byte] == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
+	      unsigned char * name;
+	      unsigned long   note_val;
+	      unsigned long   back_val;
+	      unsigned int    shift;
+	      unsigned int    bytes;
+	      unsigned long   byte;
+
+	      for (shift = 0, note_val = 0,
+		     bytes = pnote->note.namesz - val_start,
+		     name = (unsigned char *) pnote->note.namedata + val_start;
+		   bytes--;)
 		{
-		  unsigned char * name;
-		  unsigned long   note_val;
-		  unsigned long   back_val;
-		  unsigned int    shift;
-		  unsigned int    bytes;
-		  unsigned long   byte;
-
-		  for (shift = 0, note_val = 0,
-			 bytes = pnote->namesz - val_start,
-			 name = (unsigned char *) pnote->namedata + val_start;
-		       bytes--;)
-		    {
-		      byte = (* name ++) & 0xff;
-		      note_val |= byte << shift;
-		      shift += 8;
-		    }
-
-		  for (shift = 0, back_val = 0,
-			 bytes = back->namesz - val_start,
-			 name = (unsigned char *) back->namedata + val_start;
-		       bytes--;)
-		    {
-		      byte = (* name ++) & 0xff;
-		      back_val |= byte << shift;
-		      shift += 8;
-		    }
-
-		  back_val += note_val;
-		  if (num_bytes (back_val) >= back->namesz - val_start)
-		    {
-		      /* We have a problem - the new value requires more bytes of
-			 storage in the name field than are available.  Currently
-			 we have no way of fixing this, so we just preserve both
-			 notes.  */
-		      continue;
-		    }
-
-		  /* Write the new val into back.  */
-		  name = (unsigned char *) back->namedata + val_start;
-		  while (name < (unsigned char *) back->namedata + back->namesz)
-		    {
-		      byte = back_val & 0xff;
-		      * name ++ = byte;
-		      if (back_val == 0)
-			break;
-		      back_val >>= 8;
-		    }
-
-		  duplicate_found = TRUE;
-		  pnote->type = 0;
-		  break;
+		  byte = (* name ++) & 0xff;
+		  note_val |= byte << shift;
+		  shift += 8;
 		}
-		  
-	      if (back->namesz == pnote->namesz
-		  && memcmp (back->namedata, pnote->namedata, back->namesz) == 0)
+
+	      for (shift = 0, back_val = 0,
+		     bytes = back->note.namesz - val_start,
+		     name = (unsigned char *) back->note.namedata + val_start;
+		   bytes--;)
 		{
-		  duplicate_found = TRUE;
-		  pnote->type = 0;
-		  break;
+		  byte = (* name ++) & 0xff;
+		  back_val |= byte << shift;
+		  shift += 8;
 		}
 
-	      /* If we have found an attribute match then stop searching backwards.  */
-	      if (! ISPRINT (back->namedata[attribute_type_byte])
-		  /* Names are NUL terminated, so this is safe.  */
-		  || strcmp (back->namedata + val_start, pnote->namedata + val_start) == 0)
+	      back_val += note_val;
+	      if (num_bytes (back_val) >= back->note.namesz - val_start)
 		{
-		  /* Since we are keeping this note we must check to see if its
-		     description refers back to an earlier OPEN version note.  If so
-		     then we must make sure that version note is also preserved.  */
-		  if (pnote->descsz == 0
-		      && prev_open != NULL
-		      && prev_open->type == 0)
-		    prev_open->type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+		  /* We have a problem - the new value requires more bytes of
+		     storage in the name field than are available.  Currently
+		     we have no way of fixing this, so we just preserve both
+		     notes.  */
+		  continue;
+		}
 
-		  break;
+	      /* Write the new val into back.  */
+	      name = (unsigned char *) back->note.namedata + val_start;
+	      while (name < (unsigned char *) back->note.namedata
+		     + back->note.namesz)
+		{
+		  byte = back_val & 0xff;
+		  * name ++ = byte;
+		  if (back_val == 0)
+		    break;
+		  back_val >>= 8;
 		}
+
+	      duplicate_found = TRUE;
+	      pnote->note.type = 0;
+	      break;
+	    }
+
+	  /* Rule 3 - combine identical open notes.  */
+	  if (back->note.namesz == pnote->note.namesz
+	      && memcmp (back->note.namedata,
+			 pnote->note.namedata, back->note.namesz) == 0
+	      && ! gap_exists (back, pnote))
+	    {
+	      duplicate_found = TRUE;
+	      pnote->note.type = 0;
+
+	      if (pnote->end > back->end)
+		back->end = pnote->end;
+
+	      if (version_3_seen)
+		back->modified = TRUE;
+	      break;
 	    }
+
+	  /* Rule 5 - Since we are keeping this note we must check to see
+	     if its description refers back to an earlier OPEN version
+	     note that has been scheduled for deletion.  If so then we
+	     must make sure that version note is also preserved.  */
+	  if (version_3_seen)
+	    {
+	      /* As of version 3 we can just
+		 move the range into the note.  */
+	      pnote->modified = TRUE;
+	      pnote->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+	      back->modified = TRUE;
+	      back->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+	    }
+	  else
+	    {
+	      if (pnote->note.descsz == 0
+		  && prev_open_with_range != NULL
+		  && prev_open_with_range->note.type == 0)
+		prev_open_with_range->note.type = NT_GNU_BUILD_ATTRIBUTE_OPEN;
+	    }
+
+	  /* We have found a similar attribute but the details do not match.
+	     Stop searching backwards.  */
+	  break;
 	}
     }
 
@@ -2142,22 +2322,8 @@ merge_gnu_build_notes (bfd * abfd, asect
       bfd_byte *     old;
       bfd_byte *     new;
       bfd_size_type  new_size;
-      arelent **     relpp = NULL;
-      long           relsize;
-      long           relcount = 0;
-
-      relsize = bfd_get_reloc_upper_bound (abfd, sec);
-      if (relsize > 0)
-	{
-	  /* If there are relocs associated with this section then we may
-	     have to adjust them as well, as we remove notes.  */
-	  relpp = (arelent **) xmalloc (relsize);
-	  relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
-	  if (relcount < 0)
-	    /* Do not bother complaining here - copy_relocations_in_section
-	       will do that for us.  */
-	    relcount = 0;
-	}
+      bfd_vma        prev_start = 0;
+      bfd_vma        prev_end = 0;
 
       /* Eliminate the duplicates.  */
       new = new_contents = xmalloc (size);
@@ -2165,36 +2331,52 @@ merge_gnu_build_notes (bfd * abfd, asect
 	   pnote < pnotes_end;
 	   pnote ++)
 	{
-	  bfd_size_type note_size = 12 + pnote->namesz + pnote->descsz;
+	  bfd_size_type note_size = 12 + pnote->note.namesz + pnote->note.descsz;
 
-	  if (pnote->type == 0)
+	  if (pnote->note.type != 0)
 	    {
-	      if (relcount > 0)
+	      if (pnote->modified)
 		{
-		  arelent ** rel;
-
-		  /* If there is a reloc at the current offset, delete it.
-		     Adjust the location of any relocs above the current
-		     location downwards by the size of the note being deleted.
-		     FIXME: We could optimize this loop by retaining a pointer to
-		     the last reloc below the current note.  */
-		  for (rel = relpp; rel < relpp + relcount; rel ++)
+		  /* If the note has been modified then we must copy it by
+		     hand, potentially adding in a new description field.  */
+		  if (pnote->start == prev_start && pnote->end == prev_end)
 		    {
-		      if ((* rel)->howto == NULL)
-			continue;
-		      if ((* rel)->address < (bfd_vma) (new - new_contents))
-			continue;
-		      if ((* rel)->address >= (bfd_vma) ((new + note_size) - new_contents))
-			  (* rel)->address -= note_size;
+		      bfd_put_32 (abfd, pnote->note.namesz, new);
+		      bfd_put_32 (abfd, 0, new + 4);
+		      bfd_put_32 (abfd, pnote->note.type, new + 8);
+		      new += 12;
+		      memcpy (new, pnote->note.namedata, pnote->note.namesz);
+		      new += pnote->note.namesz;
+		    }
+		  else
+		    {
+		      bfd_put_32 (abfd, pnote->note.namesz, new);
+		      bfd_put_32 (abfd, is_64bit (abfd) ? 16 : 8, new + 4);
+		      bfd_put_32 (abfd, pnote->note.type, new + 8);
+		      new += 12;
+		      memcpy (new, pnote->note.namedata, pnote->note.namesz);
+		      new += pnote->note.namesz;
+		      if (is_64bit (abfd))
+			{
+			  bfd_put_64 (abfd, pnote->start, new);
+			  bfd_put_64 (abfd, pnote->end, new + 8);
+			  new += 16;
+			}
 		      else
-			(* rel)->howto = NULL;
+			{
+			  bfd_put_32 (abfd, pnote->start, new);
+			  bfd_put_32 (abfd, pnote->end, new + 4);
+			  new += 8;
+			}
 		    }
 		}
-	    }
-	  else
-	    {
-	      memcpy (new, old, note_size);
-	      new += note_size;
+	      else
+		{
+		  memcpy (new, old, note_size);
+		  new += note_size;
+		}
+	      prev_start = pnote->start;
+	      prev_end = pnote->end;
 	    }
 
 	  old += note_size;
@@ -2204,24 +2386,6 @@ merge_gnu_build_notes (bfd * abfd, asect
       memcpy (contents, new_contents, new_size);
       size = new_size;
       free (new_contents);
-
-      if (relcount > 0)
-	{
-	  arelent **rel = relpp;
-
-	  while (rel < relpp + relcount)
-	    if ((*rel)->howto != NULL)
-	      rel++;
-	    else
-	      {
-		/* Delete eliminated relocs.
-		   FIXME: There are better ways to do this.  */
-		memmove (rel, rel + 1,
-			 ((relcount - (rel - relpp)) - 1) * sizeof (*rel));
-		relcount--;
-	      }
-	  bfd_set_reloc (abfd, sec, relpp, relcount);
-	}
     }
 
  done:
diff -rup binutils.orig/binutils/readelf.c binutils-2.29.1/binutils/readelf.c
--- binutils.orig/binutils/readelf.c	2018-01-03 16:06:45.005657092 +0000
+++ binutils-2.29.1/binutils/readelf.c	2018-01-03 16:28:24.417115970 +0000
@@ -16247,9 +16247,9 @@ get_note_type (unsigned e_type)
       case NT_ARCH:
 	return _("NT_ARCH (architecture)");
       case NT_GNU_BUILD_ATTRIBUTE_OPEN:
-	return _("NT_GNU_BUILD_ATTRIBUTE_OPEN");
+	return _("OPEN");
       case NT_GNU_BUILD_ATTRIBUTE_FUNC:
-	return _("NT_GNU_BUILD_ATTRIBUTE_FUNC");
+	return _("func");
       default:
 	break;
       }
@@ -17064,13 +17064,16 @@ print_ia64_vms_note (Elf_Internal_Note *
   return TRUE;
 }
 
-/* Print the name of the symbol associated with a build attribute
-   that is attached to address OFFSET.  */
-
-static bfd_boolean
-print_symbol_for_build_attribute (FILE *         file,
-				  unsigned long  offset,
-				  bfd_boolean    is_open_attr)
+/* Find the symbol associated with a build attribute that is attached
+   to address OFFSET.  If PNAME is non-NULL then store the name of
+   the symbol (if found) in the provided pointer,  Returns NULL if a
+   symbol could not be found.  */
+
+static Elf_Internal_Sym *
+get_symbol_for_build_attribute (FILE *           file,
+				unsigned long    offset,
+				bfd_boolean      is_open_attr,
+				const char **    pname)
 {
   static FILE *             saved_file = NULL;
   static char *             strtab;
@@ -17109,10 +17112,7 @@ print_symbol_for_build_attribute (FILE *
     }
 
   if (symtab == NULL || strtab == NULL)
-    {
-      printf ("\n");
-      return FALSE;
-    }
+    return NULL;
 
   /* Find a symbol whose value matches offset.  */
   for (sym = symtab; sym < symtab + nsyms; sym ++)
@@ -17132,14 +17132,15 @@ print_symbol_for_build_attribute (FILE *
 	       FUNC symbols entirely.  */
 	    switch (ELF_ST_TYPE (sym->st_info))
 	      {
-	      case STT_FILE:
-		saved_sym = sym;
-		/* We can stop searching now.  */
-		sym = symtab + nsyms;
-		continue;
-
 	      case STT_OBJECT:
+	      case STT_FILE:
 		saved_sym = sym;
+		if (sym->st_size)
+		  {
+		    /* If the symbol has a size associated
+		       with it then we can stop searching.  */
+		    sym = symtab + nsyms;
+		  }
 		continue;
 
 	      case STT_FUNC:
@@ -17177,55 +17178,118 @@ print_symbol_for_build_attribute (FILE *
 	  }
       }
 
-  printf (" (%s: %s)\n",
-	  is_open_attr ? _("file") : _("func"),
-	  saved_sym ? strtab + saved_sym->st_name : _("<no symbol found>)"));
-  return TRUE;
+  if (saved_sym && pname)
+    * pname = strtab + saved_sym->st_name;
+
+  return saved_sym;
 }
 
 static bfd_boolean
 print_gnu_build_attribute_description (Elf_Internal_Note * pnote,
 				       FILE *              file)
 {
-  static unsigned long global_offset = 0;
-  unsigned long        offset;
-  unsigned int         desc_size = is_32bit_elf ? 4 : 8;
-  bfd_boolean          is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
-
-  if (pnote->descsz == 0)
-    {
+  static unsigned long  global_offset = 0;
+  static unsigned long  global_end = 0;
+  static unsigned long  func_offset = 0;
+  static unsigned long  func_end = 0;
+
+  Elf_Internal_Sym *    sym;
+  const char *          name;
+  unsigned long         start;
+  unsigned long         end;
+  bfd_boolean           is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
+
+  switch (pnote->descsz)
+    {
+    case 0:
+      /* A zero-length description means that the range of
+	 the previous note of the same type should be used.  */
       if (is_open_attr)
 	{
-	  printf (_("    Applies from offset %#lx\n"), global_offset);
-	  return TRUE;
+	  if (global_end > global_offset)
+	    printf (_("    Applies to region from %#lx to %#lx\n"),
+		    global_offset, global_end);
+	  else
+	    printf (_("    Applies to region from %#lx\n"), global_offset);
 	}
       else
 	{
-	  printf (_("    Applies to func at %#lx"), global_offset);
-	  return print_symbol_for_build_attribute (file, global_offset, is_open_attr);
+	  if (func_end > func_offset)
+	    printf (_("    Applies to region from %#lx to %#lx\n"), func_offset, func_end);
+	  else
+	    printf (_("    Applies to region from %#lx\n"), func_offset);
 	}
-    }
+      return TRUE;
 
-  if (pnote->descsz != desc_size)
-    {
+    case 4:
+      start = byte_get ((unsigned char *) pnote->descdata, 4);
+      end = 0;
+      break;
+
+    case 8:
+      if (is_32bit_elf)
+	{
+	  /* FIXME: We should check that version 3+ notes are being used here...  */
+	  start = byte_get ((unsigned char *) pnote->descdata, 4);
+	  end = byte_get ((unsigned char *) pnote->descdata + 4, 4);
+	}
+      else
+	{
+	  start = byte_get ((unsigned char *) pnote->descdata, 8);
+	  end = 0;
+	}
+      break;
+
+    case 16:
+      start = byte_get ((unsigned char *) pnote->descdata, 8);
+      end = byte_get ((unsigned char *) pnote->descdata + 8, 8);
+      break;
+      
+    default:
       error (_("    <invalid description size: %lx>\n"), pnote->descsz);
       printf (_("    <invalid descsz>"));
       return FALSE;
     }
 
-  offset = byte_get ((unsigned char *) pnote->descdata, desc_size);
+  name = NULL;
+  sym = get_symbol_for_build_attribute (file, start, is_open_attr, & name);
+
+  if (end == 0 && sym != NULL && sym->st_size > 0)
+    end = start + sym->st_size;
 
   if (is_open_attr)
     {
-      printf (_("    Applies from offset %#lx"), offset);
-      global_offset = offset;
+      /* FIXME: Need to properly allow for section alignment.  16 is just the alignment used on x86_64.  */
+      if (global_end > 0 && start > BFD_ALIGN (global_end, 16))
+	warn (_("Gap in build notes detected from %#lx to %#lx\n"),
+	      global_end + 1, start - 1);
+
+      printf (_("    Applies to region from %#lx"), start);
+      global_offset = start;
+
+      if (end)
+	{
+	  printf (_(" to %#lx"), end);
+	  global_end = end;
+	}
     }
   else
     {
-      printf (_("    Applies to func at %#lx"), offset);
+      printf (_("    Applies to region from %#lx"), start);
+      func_offset = start;
+
+      if (end)
+	{
+	  printf (_(" to %#lx"), end);
+	  func_end = end;
+	}
     }
 
-  return print_symbol_for_build_attribute (file, offset, is_open_attr);
+  if (sym && name)
+    printf (_(" (%s)"), name);
+
+  printf ("\n");
+  return TRUE;
 }
 
 static bfd_boolean
@@ -17248,11 +17312,21 @@ print_gnu_build_attribute_name (Elf_Inte
       return FALSE;
     }
 
-  left = 20;
+  if (do_wide)
+    left = 28;
+  else
+    left = 20;
 
   /* Version 2 of the spec adds a "GA" prefix to the name field.  */
   if (name[0] == 'G' && name[1] == 'A')
     {
+      if (pnote->namesz < 4)
+	{
+	  error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
+	  print_symbol (-20, _("  <corrupt name>"));
+	  return FALSE;
+	}
+
       printf ("GA");
       name += 2;
       left -= 2;
diff -rup binutils.orig/binutils/testsuite/binutils-all/mips/mips-note-2r.d binutils-2.29.1/binutils/testsuite/binutils-all/mips/mips-note-2r.d
--- binutils.orig/binutils/testsuite/binutils-all/mips/mips-note-2r.d	2018-01-03 16:06:45.013656996 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/mips/mips-note-2r.d	2018-01-03 16:06:57.927502748 +0000
@@ -5,7 +5,5 @@
 #as: -32
 #source: ../note-2-32.s
 
-Relocation section '\.rel\.gnu\.build\.attributes' at offset .* contains 2 entries:
- Offset     Info    Type            Sym\.Value  Sym\. Name
-00000010  ......02 R_MIPS_32         00000100   note1\.s
-0000006c  ......02 R_MIPS_32         00000104   note2\.s
+There are no relocations in this file.
+#...
diff -rup binutils.orig/binutils/testsuite/binutils-all/mips/mips-note-2r-n32.d binutils-2.29.1/binutils/testsuite/binutils-all/mips/mips-note-2r-n32.d
--- binutils.orig/binutils/testsuite/binutils-all/mips/mips-note-2r-n32.d	2018-01-03 16:06:45.014656984 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/mips/mips-note-2r-n32.d	2018-01-03 16:06:57.927502748 +0000
@@ -5,7 +5,5 @@
 #as: -n32 -mips3
 #source: ../note-2-32.s
 
-Relocation section '\.rela\.gnu\.build\.attributes' at offset .* contains 2 entries:
- Offset     Info    Type            Sym\.Value  Sym\. Name \+ Addend
-00000010  ......02 R_MIPS_32         00000100   note1\.s \+ 0
-0000006c  ......02 R_MIPS_32         00000104   note2\.s \+ 0
+There are no relocations in this file.
+#...
diff -rup binutils.orig/binutils/testsuite/binutils-all/mips/mips-note-2r-n64.d binutils-2.29.1/binutils/testsuite/binutils-all/mips/mips-note-2r-n64.d
--- binutils.orig/binutils/testsuite/binutils-all/mips/mips-note-2r-n64.d	2018-01-03 16:06:45.014656984 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/mips/mips-note-2r-n64.d	2018-01-03 16:06:57.927502748 +0000
@@ -5,11 +5,5 @@
 #as: -64 -mips3
 #source: ../note-2-64.s
 
-Relocation section '\.rela\.gnu\.build\.attributes' at offset .* contains 2 entries:
-  Offset          Info           Type           Sym\. Value    Sym\. Name \+ Addend
-000000000010  ....00000012 R_MIPS_64         0000000000000100 note1\.s \+ 0
-                    Type2: R_MIPS_NONE      
-                    Type3: R_MIPS_NONE      
-000000000070  ....00000012 R_MIPS_64         0000000000000104 note2\.s \+ 0
-                    Type2: R_MIPS_NONE      
-                    Type3: R_MIPS_NONE      
+There are no relocations in this file.
+#...
diff -rup binutils.orig/binutils/testsuite/binutils-all/note-2-32.d binutils-2.29.1/binutils/testsuite/binutils-all/note-2-32.d
--- binutils.orig/binutils/testsuite/binutils-all/note-2-32.d	2018-01-03 16:06:45.013656996 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-2-32.d	2018-01-03 16:06:57.927502748 +0000
@@ -6,12 +6,12 @@
 
 #...
   Owner                 Data size	Description
-[ 	]+\$<version>1[ 	]+0x00000004[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100 \(file: note1.s\)
-[ 	]+\$<tool>gcc 7.0.1[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\+<stack prot>true[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\*<PIC>static[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\*<ABI>0x0[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\$<version>1[ 	]+0x00000004[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10. \(file: note2.s\)
-[ 	]+!<stack prot>false[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10.
-[ 	]+\*<PIC>pic[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ 	]+Applies to func at 0x10. \(func: func1\)
+[ 	]+\$<version>1[ 	]+0x00000004[ 	]+OPEN[ 	]+Applies to region from 0x100 \(note1.s\)
+[ 	]+\$<tool>gcc 7.0.1[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\+<stack prot>true[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\*<PIC>static[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\*<ABI>0x0[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\$<version>1[ 	]+0x00000004[ 	]+OPEN[ 	]+Applies to region from 0x104 \(note2.s\)
+[ 	]+!<stack prot>false[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x104
+[ 	]+\*<PIC>pic[ 	]+0x00000004[ 	]+func[ 	]+Applies to region from 0x104 \(func1\)
 #...
diff -rup binutils.orig/binutils/testsuite/binutils-all/note-2-32.s binutils-2.29.1/binutils/testsuite/binutils-all/note-2-32.s
--- binutils.orig/binutils/testsuite/binutils-all/note-2-32.s	2018-01-03 16:06:45.010657032 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-2-32.s	2018-01-03 16:06:57.927502748 +0000
@@ -2,7 +2,7 @@
 	.org 0x100
 	.global note1.s
 note1.s:
-	.word 0
+	.dc.l 0
 	
 	.pushsection .gnu.build.attributes, "0x100000", %note
 	.balign 4
@@ -10,7 +10,7 @@ note1.s:
 	.dc.l 4
 	.dc.l 0x100
 	.asciz "$1"
-	.dc.l note1.s
+	.dc.l 0x100
 
 	.dc.l 12
 	.dc.l 0
@@ -39,14 +39,14 @@ note1.s:
 note2.s:
 	.type func1, STT_FUNC
 func1:	
-	.word 0x100
+	.dc.l 0x100
 	
 	.pushsection .gnu.build.attributes, "0x100000", %note
 	.dc.l 4 	
 	.dc.l 4		
 	.dc.l 0x100	
 	.asciz "$1"	
-	.dc.l note2.s	
+	.dc.l 0x104	
 
 	.dc.l 12 	
 	.dc.l 0		
@@ -60,26 +60,28 @@ func1:
 	.dc.b 0 	
 
 	.dc.l 4		
-	.dc.l 0		
+	.dc.l 4		
 	.dc.l 0x101	
 	.dc.b 0x2a, 0x7, 1, 0
-
+	.dc.l 0x104	
+	
 	.dc.l 4		
 	.dc.l 0		
 	.dc.l 0x100	
 	.dc.b 0x2a, 0x6, 0, 0
 	.popsection
 
+	
 	.global note3.s
 note3.s:
-	.word 0x100
+	.dc.l 0x100
 	
 	.pushsection .gnu.build.attributes, "0x100000", %note
 	.dc.l 4 	
 	.dc.l 4		
 	.dc.l 0x100	
 	.asciz "$1"	
-	.dc.l note3.s
+	.dc.l 0x108
 
 	.dc.l 12 	
 	.dc.l 0		
diff -rup binutils.orig/binutils/testsuite/binutils-all/note-2-64.d binutils-2.29.1/binutils/testsuite/binutils-all/note-2-64.d
--- binutils.orig/binutils/testsuite/binutils-all/note-2-64.d	2018-01-03 16:06:45.010657032 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-2-64.d	2018-01-03 16:06:57.927502748 +0000
@@ -6,12 +6,12 @@
 
 #...
   Owner                 Data size	Description
-[ 	]+\$<version>1[ 	]+0x00000008[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100 \(file: note1.s\)
-[ 	]+\$<tool>gcc 7.0.1[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\+<stack prot>true[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\*<PIC>static[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\*<ABI>0x0[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
-[ 	]+\$<version>1[ 	]+0x00000008[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10. \(file: note2.s\)
-[ 	]+!<stack prot>false[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10.
-[ 	]+\*<PIC>pic[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ 	]+Applies to func at 0x10. \(func: func1\)
+[ 	]+\$<version>1[ 	]+0x00000008[ 	]+OPEN[ 	]+Applies to region from 0x100 \(note1.s\)
+[ 	]+\$<tool>gcc 7.0.1[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\+<stack prot>true[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\*<PIC>static[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\*<ABI>0x0[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100
+[ 	]+\$<version>1[ 	]+0x00000008[ 	]+OPEN[ 	]+Applies to region from 0x104 \(note2.s\)
+[ 	]+!<stack prot>false[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x104
+[ 	]+\*<PIC>pic[ 	]+0x00000008[ 	]+func[ 	]+Applies to region from 0x104 \(func1\)
 #...
diff -rup binutils.orig/binutils/testsuite/binutils-all/note-2-64.s binutils-2.29.1/binutils/testsuite/binutils-all/note-2-64.s
--- binutils.orig/binutils/testsuite/binutils-all/note-2-64.s	2018-01-03 16:06:45.014656984 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-2-64.s	2018-01-03 16:06:57.927502748 +0000
@@ -2,7 +2,7 @@
 	.org 0x100
 	.global note1.s
 note1.s:
-	.word 0
+	.dc.l 0
 	
 	.pushsection .gnu.build.attributes, "0x100000", %note
 	.balign 4
@@ -10,7 +10,7 @@ note1.s:
 	.dc.l 8
 	.dc.l 0x100
 	.asciz "$1"
-	.8byte note1.s
+	.8byte 0x100
 
 	.dc.l 12
 	.dc.l 0
@@ -40,14 +40,14 @@ note2.s:
 	.global func1
 	.type func1, STT_FUNC
 func1:	
-	.word 0x100
+	.dc.l 0x100
 
 	.pushsection .gnu.build.attributes, "0x100000", %note
 	.dc.l 4 	
 	.dc.l 8		
 	.dc.l 0x100	
 	.asciz "$1"	
-	.8byte note2.s	
+	.8byte 0x104	
 
 	.dc.l 12 	
 	.dc.l 0		
@@ -61,9 +61,10 @@ func1:
 	.dc.b 0 	
 
 	.dc.l 4
-	.dc.l 0		
+	.dc.l 8	
 	.dc.l 0x101	
 	.dc.b 0x2a, 0x7, 1, 0
+	.8byte 0x104	
 
 	.dc.l 4
 	.dc.l 0		
@@ -74,14 +75,14 @@ func1:
 
 	.global note3.s
 note3.s:
-	.word 0x100
+	.dc.l 0x100
 	
 	.pushsection .gnu.build.attributes, "0x100000", %note
 	.dc.l 4 	
 	.dc.l 8		
 	.dc.l 0x100	
 	.asciz "$1"	
-	.8byte note3.s
+	.8byte 0x108
 
 	.dc.l 12 	
 	.dc.l 0		
diff -rup binutils.orig/binutils/testsuite/binutils-all/objcopy.exp binutils-2.29.1/binutils/testsuite/binutils-all/objcopy.exp
--- binutils.orig/binutils/testsuite/binutils-all/objcopy.exp	2018-01-03 16:06:45.013656996 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/objcopy.exp	2018-01-03 16:21:05.682365371 +0000
@@ -1056,8 +1056,10 @@ if [is_elf_format] {
     run_dump_test "note-1"
     if [is_elf64 tmpdir/bintest.o] {
 	run_dump_test "note-2-64"
+	run_dump_test "note-4-64"
     } else {
 	run_dump_test "note-2-32"
+	run_dump_test "note-4-32"
     }
 }
 

--- /dev/null	2018-01-03 08:45:19.457895336 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-4-32.s	2018-01-03 16:36:13.314505682 +0000
@@ -0,0 +1,74 @@
+	.text
+	.org 0x100
+note_4.s:
+	.dc.l 0
+	.dc.l 0
+
+	.type	bar, STT_FUNC
+bar:
+	.dc.l 0
+bar_end:
+	.dc.l 0
+note_4.s_end:
+	
+	.pushsection .gnu.build.attributes, "", %note
+	.balign 4
+
+	.dc.l 8
+	.dc.l 8
+	.dc.l 0x100
+	.asciz "GA$3p3"
+	.dc.l note_4.s
+	.dc.l note_4.s_end
+
+	.dc.l 23
+	.dc.l 0
+	.dc.l 0x100
+	.asciz "GA$gcc 7.2.1 20170915"
+	.dc.b 0
+
+	.dc.l 10
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x47, 0x4f, 0x57, 0, 0, 0x7, 0
+	.dc.b 0, 0
+
+	.dc.l 6
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x2, 0, 0
+	.dc.b 0, 0
+
+	.dc.l 13
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x46, 0x4f, 0x52, 0x54, 0x49, 0x46, 0x59, 0, 0xff, 0
+	.dc.b 0, 0, 0
+
+	.dc.l 6
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+	.dc.b 0, 0
+
+	.dc.l 5
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x21, 0x8, 0
+	.dc.b 0, 0, 0
+
+	.dc.l 13
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
+	.dc.b 0, 0, 0
+
+	.dc.l 6
+	.dc.l 8
+	.dc.l 0x101
+	.dc.b 0x47, 0x41, 0x2a, 0x2, 0x3, 0
+	.dc.b 0, 0
+	.dc.l bar
+	.dc.l bar_end
+	
+	.popsection
--- /dev/null	2018-01-03 08:45:19.457895336 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-4-32.d	2018-01-03 16:36:13.313505694 +0000
@@ -0,0 +1,19 @@
+#PROG: objcopy
+#readelf: --notes --wide
+#objcopy: --merge-notes
+#name: v3 gnu build attribute notes (32-bit)
+#source: note-4-32.s
+
+#...
+Displaying notes found in: .gnu.build.attributes
+[ 	]+Owner[ 	]+Data size[ 	]+Description
+[ 	]+GA\$<version>3p3[ 	]+0x00000008[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110 \(note_4.s\)
+[ 	]+GA\$<tool>gcc 7.2.1 20170915[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110
+[ 	]+GA\*GOW:0x700[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110
+[ 	]+GA\*<stack prot>off[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110
+[ 	]+GA\*FORTIFY:0xff[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110
+[ 	]+GA\*<PIC>PIC[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110
+[ 	]+GA\!<short enum>false[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110
+[ 	]+GA\*<ABI>0x[0-9a-f]+[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x110
+[ 	]+GA\*<stack prot>strong[ 	]+0x00000008[ 	]+func[ 	]+Applies to region from 0x108 to 0x10c.*
+#...
--- /dev/null	2018-01-03 08:45:19.457895336 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-4-64.s	2018-01-03 16:36:07.041580738 +0000
@@ -0,0 +1,78 @@
+	.text
+	.org 0x100
+note_4.s:
+	.dc.l 0
+	.dc.l 0
+	.dc.l 0
+	.dc.l 0
+
+	.type	bar, @function
+bar:
+	.dc.l 0
+	.dc.l 0
+	.dc.l 0
+bar_end:
+	.dc.l 0
+note_4.s_end:
+
+	.pushsection .gnu.build.attributes, "", %note
+	.balign 4
+
+	.dc.l 8
+	.dc.l 16
+	.dc.l 0x100
+	.asciz "GA$3p3"
+	.8byte note_4.s
+	.8byte note_4.s_end
+
+	.dc.l 23
+	.dc.l 0
+	.dc.l 0x100
+	.asciz "GA$gcc 7.2.1 20170915"
+	.dc.b 0
+
+	.dc.l 10
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x47, 0x4f, 0x57, 0, 0, 0x7, 0
+	.dc.b 0, 0
+
+	.dc.l 6
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x2, 0, 0
+	.dc.b 0, 0
+
+	.dc.l 13
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x46, 0x4f, 0x52, 0x54, 0x49, 0x46, 0x59, 0, 0xff, 0
+	.dc.b 0, 0, 0
+
+	.dc.l 6
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+	.dc.b 0, 0
+
+	.dc.l 5
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x21, 0x8, 0
+	.dc.b 0, 0, 0
+
+	.dc.l 13
+	.dc.l 0
+	.dc.l 0x100
+	.dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
+	.dc.b 0, 0, 0
+
+	.dc.l 6
+	.dc.l 16
+	.dc.l 0x101
+	.dc.b 0x47, 0x41, 0x2a, 0x2, 0x3, 0
+	.dc.b 0, 0
+	.8byte bar
+	.8byte bar_end
+	
+	.popsection
--- /dev/null	2018-01-03 08:45:19.457895336 +0000
+++ binutils-2.29.1/binutils/testsuite/binutils-all/note-4-64.d	2018-01-03 16:36:07.041580738 +0000
@@ -0,0 +1,19 @@
+#PROG: objcopy
+#readelf: --notes --wide
+#objcopy: --merge-notes
+#name: v3 gnu build attribute notes (64-bit)
+#source: note-4-64.s
+
+#...
+Displaying notes found in: .gnu.build.attributes
+[ 	]+Owner[ 	]+Data size[ 	]+Description
+[ 	]+GA\$<version>3p3[ 	]+0x00000010[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120 \(note_4.s\)
+[ 	]+GA\$<tool>gcc 7.2.1 20170915[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120
+[ 	]+GA\*GOW:0x700[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120
+[ 	]+GA\*<stack prot>off[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120
+[ 	]+GA\*FORTIFY:0xff[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120
+[ 	]+GA\*<PIC>PIC[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120
+[ 	]+GA\!<short enum>false[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120
+[ 	]+GA\*<ABI>0x[0-9a-f]+[ 	]+0x00000000[ 	]+OPEN[ 	]+Applies to region from 0x100 to 0x120
+[ 	]+GA\*<stack prot>strong[ 	]+0x00000010[ 	]+func[ 	]+Applies to region from 0x110 to 0x11c.*
+#...