Blame SOURCES/binutils-gnu-build-notes.patch

0b07f1
diff -rup binutils.orig/binutils/doc/binutils.texi binutils-2.28/binutils/doc/binutils.texi
0b07f1
--- binutils.orig/binutils/doc/binutils.texi	2017-03-20 17:03:56.166605442 +0000
0b07f1
+++ binutils-2.28/binutils/doc/binutils.texi	2017-03-20 17:04:07.688408917 +0000
0b07f1
@@ -1140,6 +1140,7 @@ objcopy [@option{-F} @var{bfdname}|@opti
0b07f1
         [@option{--compress-debug-sections}]
0b07f1
         [@option{--decompress-debug-sections}]
0b07f1
         [@option{--elf-stt-common=@var{val}}]
0b07f1
+        [@option{--merge-notes}]
0b07f1
         [@option{-v}|@option{--verbose}]
0b07f1
         [@option{-V}|@option{--version}]
0b07f1
         [@option{--help}] [@option{--info}]
0b07f1
@@ -1956,6 +1957,10 @@ converted to the @code{STT_COMMON} or @c
0b07f1
 @code{STT_COMMON}. @option{--elf-stt-common=no} converts common symbol
0b07f1
 type to @code{STT_OBJECT}.
0b07f1
 
0b07f1
+@item --merge-notes
0b07f1
+For ELF files, attempt to reduce the size of any SHT_NOTE type
0b07f1
+sections by removing duplicate notes.
0b07f1
+
0b07f1
 @item -V
0b07f1
 @itemx --version
0b07f1
 Show the version number of @command{objcopy}.
0b07f1
diff -rup binutils.orig/binutils/NEWS binutils-2.28/binutils/NEWS
0b07f1
--- binutils.orig/binutils/NEWS	2017-03-20 17:03:56.167605425 +0000
0b07f1
+++ binutils-2.28/binutils/NEWS	2017-03-20 17:04:07.688408917 +0000
0b07f1
@@ -1,5 +1,8 @@
0b07f1
 -*- text -*-
0b07f1
 
0b07f1
+* Add --merge-notes options to objcopy to reduce the size of notes in
0b07f1
+  a binary file by merging and deleting redundant notes.
0b07f1
+
0b07f1
 Changes in 2.28:
0b07f1
 
0b07f1
 * Add support for locating separate debug info files using the build-id
0b07f1
diff -rup binutils.orig/binutils/objcopy.c binutils-2.28/binutils/objcopy.c
0b07f1
--- binutils.orig/binutils/objcopy.c	2017-03-20 17:03:56.167605425 +0000
0b07f1
+++ binutils-2.28/binutils/objcopy.c	2017-03-20 17:04:07.718408405 +0000
0b07f1
@@ -30,6 +30,7 @@
0b07f1
 #include "elf-bfd.h"
0b07f1
 #include "coff/internal.h"
0b07f1
 #include "libcoff.h"
0b07f1
+#include "safe-ctype.h"
0b07f1
 
0b07f1
 /* FIXME: See bfd/peXXigen.c for why we include an architecture specific
0b07f1
    header in generic PE code.  */
0b07f1
@@ -96,6 +97,10 @@ static bfd_boolean preserve_dates;	/* Pr
0b07f1
 static int deterministic = -1;		/* Enable deterministic archives.  */
0b07f1
 static int status = 0;		/* Exit status.  */
0b07f1
 
0b07f1
+static bfd_boolean    merge_notes = FALSE;	/* Merge note sections.  */
0b07f1
+static bfd_byte *     merged_notes = NULL;	/* Contents on note section undergoing a merge.  */
0b07f1
+static bfd_size_type  merged_size = 0;		/* New, smaller size of the merged note section.  */
0b07f1
+
0b07f1
 enum strip_action
0b07f1
 {
0b07f1
   STRIP_UNDEF,
0b07f1
@@ -315,6 +320,7 @@ enum command_line_switch
0b07f1
   OPTION_LOCALIZE_HIDDEN,
0b07f1
   OPTION_LOCALIZE_SYMBOLS,
0b07f1
   OPTION_LONG_SECTION_NAMES,
0b07f1
+  OPTION_MERGE_NOTES,
0b07f1
   OPTION_NO_CHANGE_WARNINGS,
0b07f1
   OPTION_ONLY_KEEP_DEBUG,
0b07f1
   OPTION_PAD_TO,
0b07f1
@@ -436,6 +442,7 @@ static struct option copy_options[] =
0b07f1
   {"localize-symbol", required_argument, 0, 'L'},
0b07f1
   {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
0b07f1
   {"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES},
0b07f1
+  {"merge-notes", no_argument, 0, 'M'},
0b07f1
   {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
0b07f1
   {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
0b07f1
   {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
0b07f1
@@ -634,6 +641,7 @@ copy_usage (FILE *stream, int exit_statu
0b07f1
      --decompress-debug-sections   Decompress DWARF debug sections using zlib\n\
0b07f1
      --elf-stt-common=[yes|no]     Generate ELF common symbols with STT_COMMON\n\
0b07f1
                                      type\n\
0b07f1
+  -M  --merge-notes                Remove redundant entries in note sections\n\
0b07f1
   -v --verbose                     List all object files modified\n\
0b07f1
   @<file>                          Read options from <file>\n\
0b07f1
   -V --version                     Display this program's version number\n\
0b07f1
@@ -1201,6 +1209,24 @@ is_update_section (bfd *abfd ATTRIBUTE_U
0b07f1
   return FALSE;
0b07f1
 }
0b07f1
 
0b07f1
+static bfd_boolean
0b07f1
+is_merged_note_section (bfd * abfd, asection * sec)
0b07f1
+{
0b07f1
+  if (merge_notes
0b07f1
+      && bfd_get_flavour (abfd) == bfd_target_elf_flavour
0b07f1
+      && elf_section_data (sec)->this_hdr.sh_type == SHT_NOTE
0b07f1
+      /* FIXME: We currently only support merging GNU_BUILD_NOTEs.
0b07f1
+	 We should add support for more note types.  */
0b07f1
+      && ((elf_section_data (sec)->this_hdr.sh_flags & SHF_GNU_BUILD_NOTE) != 0
0b07f1
+	  /* Old versions of GAS (prior to 2.27) could not set the section
0b07f1
+	     flags to OS-specific values, so we also accept sections with the
0b07f1
+	     expected name.  */
0b07f1
+	  || (strcmp (sec->name, GNU_BUILD_ATTRS_SECTION_NAME) == 0)))
0b07f1
+    return TRUE;
0b07f1
+
0b07f1
+  return FALSE;
0b07f1
+}
0b07f1
+
0b07f1
 /* See if a non-group section is being removed.  */
0b07f1
 
0b07f1
 static bfd_boolean
0b07f1
@@ -1818,6 +1844,255 @@ copy_unknown_object (bfd *ibfd, bfd *obf
0b07f1
   return TRUE;
0b07f1
 }
0b07f1
 
0b07f1
+/* Merge the notes on SEC, removing redundant entries.
0b07f1
+   Returns the new, smaller size of the section upon success.  */
0b07f1
+
0b07f1
+static bfd_size_type
0b07f1
+merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte * contents)
0b07f1
+{
0b07f1
+  Elf_Internal_Note * pnotes_end;
0b07f1
+  Elf_Internal_Note * pnotes;
0b07f1
+  Elf_Internal_Note * pnote;
0b07f1
+  bfd_size_type       remain = size;
0b07f1
+  unsigned            version_notes_seen = 0;
0b07f1
+  bfd_boolean         duplicate_found = FALSE;
0b07f1
+  const char *        err = NULL;
0b07f1
+  bfd_byte *          in = contents;
0b07f1
+
0b07f1
+  /* Make a copy of the notes.
0b07f1
+     Minimum size of a note is 12 bytes.  */
0b07f1
+  pnote = pnotes = (Elf_Internal_Note *) xmalloc ((size / 12) * sizeof (Elf_Internal_Note));
0b07f1
+  while (remain >= 12)
0b07f1
+    {
0b07f1
+      pnote->namesz = (bfd_get_32 (abfd, in    ) + 3) & ~3;
0b07f1
+      pnote->descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
0b07f1
+      pnote->type   =  bfd_get_32 (abfd, in + 8);
0b07f1
+
0b07f1
+      if (pnote->type    != NT_GNU_BUILD_ATTRIBUTE_OPEN
0b07f1
+	  && pnote->type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
0b07f1
+	{
0b07f1
+	  err = _("corrupt GNU build attribute note: wrong note type");
0b07f1
+	  goto done;
0b07f1
+	}
0b07f1
+
0b07f1
+      if (pnote->namesz + pnote->descsz + 12 > remain)
0b07f1
+	{
0b07f1
+	  err = _("corrupt GNU build attribute note: note too big");
0b07f1
+	  goto done;
0b07f1
+	}
0b07f1
+
0b07f1
+      if (pnote->namesz < 2)
0b07f1
+	{
0b07f1
+	  err = _("corrupt GNU build attribute note: name too small");
0b07f1
+	  goto done;
0b07f1
+	}
0b07f1
+
0b07f1
+      if (pnote->descsz != 0
0b07f1
+	  && pnote->descsz != 4
0b07f1
+	  && pnote->descsz != 8)
0b07f1
+	{
0b07f1
+	  err = _("corrupt GNU build attribute note: bad description size");
0b07f1
+	  goto done;
0b07f1
+	}
0b07f1
+
0b07f1
+      pnote->namedata = (char *)(in + 12);
0b07f1
+      pnote->descdata = (char *)(in + 12 + pnote->namesz);
0b07f1
+
0b07f1
+      remain -= 12 + pnote->namesz + pnote->descsz;
0b07f1
+      in     += 12 + pnote->namesz + pnote->descsz;
0b07f1
+
0b07f1
+      if (pnote->namesz > 1 && pnote->namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION)
0b07f1
+	++ version_notes_seen;
0b07f1
+      pnote ++;
0b07f1
+    }
0b07f1
+
0b07f1
+  pnotes_end = pnote;
0b07f1
+
0b07f1
+  /* Check that the notes are valid.  */
0b07f1
+  if (remain != 0)
0b07f1
+    {
0b07f1
+      err = _("corrupt GNU build attribute notes: data at end");
0b07f1
+      goto done;
0b07f1
+    }
0b07f1
+
0b07f1
+  if (version_notes_seen == 0)
0b07f1
+    {
0b07f1
+      err = _("bad GNU build attribute notes: no version note");
0b07f1
+      goto done;
0b07f1
+    }
0b07f1
+
0b07f1
+  /* Merging is only needed if there is more than one version note...  */
0b07f1
+  if (version_notes_seen == 1)
0b07f1
+    goto done;
0b07f1
+
0b07f1
+  /* The first note should be the first version note.  */
0b07f1
+  if (pnotes[0].namedata[1] != GNU_BUILD_ATTRIBUTE_VERSION)
0b07f1
+    {
0b07f1
+      err = _("bad GNU build attribute notes: first note not version note");
0b07f1
+      goto done;
0b07f1
+    }
0b07f1
+
0b07f1
+  if (pnotes[0].namedata[0] != GNU_BUILD_ATTRIBUTE_TYPE_STRING
0b07f1
+      || pnotes[0].namedata[2] != '1')
0b07f1
+    {
0b07f1
+      err = _("bad GNU build attribute notes: version note not v1");
0b07f1
+      goto done;
0b07f1
+    }
0b07f1
+
0b07f1
+  /* Now merge the notes.  The rules are:
0b07f1
+     1. Preserve the ordering of the notes.
0b07f1
+     2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes.
0b07f1
+     3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same
0b07f1
+        full name field as the immediately preceeding note with the same type
0b07f1
+	of name.
0b07f1
+     4. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
0b07f1
+        its description field is empty then the nearest preceeding OPEN note
0b07f1
+	with a non-empty description field must also be preserved *OR* the
0b07f1
+	description field of the note must be changed to contain the starting
0b07f1
+	address to which it refers.  */
0b07f1
+  for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++)
0b07f1
+    {
0b07f1
+      Elf_Internal_Note * back;
0b07f1
+      Elf_Internal_Note * prev_open = NULL;
0b07f1
+
0b07f1
+      if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC)
0b07f1
+	continue;
0b07f1
+
0b07f1
+      /* Scan for duplicates.  Clear the type field of any found - but do not
0b07f1
+	 delete them just yet.  */
0b07f1
+      for (back = pnote - 1; back >= pnotes; back --)
0b07f1
+	{
0b07f1
+	  if (back->descsz > 0
0b07f1
+	      && back->type != NT_GNU_BUILD_ATTRIBUTE_FUNC
0b07f1
+	      && prev_open == NULL)
0b07f1
+	    prev_open = back;
0b07f1
+
0b07f1
+	  if (back->type == pnote->type
0b07f1
+	      && back->namedata[1] == pnote->namedata[1])
0b07f1
+	    {
0b07f1
+	      if (back->namesz == pnote->namesz
0b07f1
+		  && memcmp (back->namedata, pnote->namedata, back->namesz) == 0)
0b07f1
+		{
0b07f1
+		  duplicate_found = TRUE;
0b07f1
+		  pnote->type = 0;
0b07f1
+		  break;
0b07f1
+		}
0b07f1
+
0b07f1
+	      /* If we have found an attribute match then stop searching backwards.  */
0b07f1
+	      if (! ISPRINT (back->namedata[1])
0b07f1
+		  || strcmp (back->namedata + 2, pnote->namedata + 2) == 0)
0b07f1
+		{
0b07f1
+		  /* Since we are keeping this note we must check to see if its
0b07f1
+		     description refers back to an earlier OPEN note.  If so
0b07f1
+		     then we must make sure that version note is also preserved.  */
0b07f1
+		  if (pnote->descsz == 0
0b07f1
+		      && prev_open != NULL
0b07f1
+		      && prev_open->type == 0)
0b07f1
+		    prev_open->type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
0b07f1
+
0b07f1
+		  break;
0b07f1
+		}
0b07f1
+	    }
0b07f1
+	}
0b07f1
+    }
0b07f1
+
0b07f1
+  if (duplicate_found)
0b07f1
+    {
0b07f1
+      bfd_byte *     new_contents;
0b07f1
+      bfd_byte *     old;
0b07f1
+      bfd_byte *     new;
0b07f1
+      bfd_size_type  new_size;
0b07f1
+      arelent **     relpp = NULL;
0b07f1
+      long           relsize;
0b07f1
+      long           relcount = 0;
0b07f1
+
0b07f1
+      relsize = bfd_get_reloc_upper_bound (abfd, sec);
0b07f1
+      if (relsize > 0)
0b07f1
+	{
0b07f1
+	  /* If there are relocs associated with this section then we may
0b07f1
+	     have to adjust them as well, as we remove notes.  */
0b07f1
+	  relpp = (arelent **) xmalloc (relsize);
0b07f1
+	  relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
0b07f1
+	  if (relcount < 0)
0b07f1
+	    /* Do not bother complaining here - copy_relocations_in_section
0b07f1
+	       will do that for us.  */
0b07f1
+	    relcount = 0;
0b07f1
+	}
0b07f1
+
0b07f1
+      /* Eliminate the duplicates.  */
0b07f1
+      new = new_contents = xmalloc (size);
0b07f1
+      for (pnote = pnotes, old = contents;
0b07f1
+	   pnote < pnotes_end;
0b07f1
+	   pnote ++)
0b07f1
+	{
0b07f1
+	  bfd_size_type note_size = 12 + pnote->namesz + pnote->descsz;
0b07f1
+
0b07f1
+	  if (pnote->type == 0)
0b07f1
+	    {
0b07f1
+	      if (relcount > 0)
0b07f1
+		{
0b07f1
+		  arelent ** rel;
0b07f1
+
0b07f1
+		  /* If there is a reloc at the current offset, delete it.
0b07f1
+		     Adjust the location of any relocs above the current
0b07f1
+		     location downwards by the size of the note being deleted.
0b07f1
+		     FIXME: We could optimize this loop by retaining a pointer to
0b07f1
+		     the last reloc below the current note.  */
0b07f1
+		  for (rel = relpp; rel < relpp + relcount; rel ++)
0b07f1
+		    {
0b07f1
+		      if ((* rel)->howto == NULL)
0b07f1
+			continue;
0b07f1
+		      if ((* rel)->address < (bfd_vma) (new - new_contents))
0b07f1
+			continue;
0b07f1
+		      if ((* rel)->address >= (bfd_vma) ((new + note_size) - new_contents))
0b07f1
+			  (* rel)->address -= note_size;
0b07f1
+		      else
0b07f1
+			(* rel)->howto = NULL;
0b07f1
+		    }
0b07f1
+		}
0b07f1
+	    }
0b07f1
+	  else
0b07f1
+	    {
0b07f1
+	      memcpy (new, old, note_size);
0b07f1
+	      new += note_size;
0b07f1
+	    }
0b07f1
+
0b07f1
+	  old += note_size;
0b07f1
+	}
0b07f1
+
0b07f1
+      new_size = new - new_contents;
0b07f1
+      memcpy (contents, new_contents, new_size);
0b07f1
+      size = new_size;
0b07f1
+      free (new_contents);
0b07f1
+
0b07f1
+      if (relcount > 0)
0b07f1
+	{
0b07f1
+	  arelent ** rel;
0b07f1
+
0b07f1
+	  for (rel = relpp; rel < relpp + relcount; rel ++)
0b07f1
+	    if ((* rel)->howto == NULL)
0b07f1
+	      {
0b07f1
+		/* Delete eliminated relocs.
0b07f1
+		   FIXME: There are better ways to do this.  */
0b07f1
+		memmove (rel, rel + 1, ((relcount - (rel - relpp)) - 1) * sizeof (* rel));
0b07f1
+		relcount --;
0b07f1
+	      }
0b07f1
+	  bfd_set_reloc (abfd, sec, relpp, relcount);
0b07f1
+	}
0b07f1
+    }
0b07f1
+
0b07f1
+ done:
0b07f1
+  if (err)
0b07f1
+    {
0b07f1
+      bfd_set_error (bfd_error_bad_value);
0b07f1
+      bfd_nonfatal_message (NULL, abfd, sec, err);
0b07f1
+      status = 1;
0b07f1
+    }
0b07f1
+
0b07f1
+  free (pnotes);
0b07f1
+  return size;
0b07f1
+}
0b07f1
+
0b07f1
 /* Copy object file IBFD onto OBFD.
0b07f1
    Returns TRUE upon success, FALSE otherwise.  */
0b07f1
 
0b07f1
@@ -2145,6 +2420,57 @@ copy_object (bfd *ibfd, bfd *obfd, const
0b07f1
 	}
0b07f1
     }
0b07f1
 
0b07f1
+  if (merge_notes)
0b07f1
+    {
0b07f1
+      asection *osec;
0b07f1
+
0b07f1
+      /* This palaver is necessary because we must set the output
0b07f1
+	 section size first, before its contents are ready.  */
0b07f1
+      osec = bfd_get_section_by_name (ibfd, GNU_BUILD_ATTRS_SECTION_NAME);
0b07f1
+      if (osec && is_merged_note_section (ibfd, osec))
0b07f1
+	{
0b07f1
+	  bfd_size_type size;
0b07f1
+	  
0b07f1
+	  size = bfd_get_section_size (osec);
0b07f1
+	  if (size == 0)
0b07f1
+	    {
0b07f1
+	      bfd_nonfatal_message (NULL, ibfd, osec, _("warning: note section is empty"));
0b07f1
+	      merge_notes = FALSE;
0b07f1
+	    }
0b07f1
+	  else if (! bfd_get_full_section_contents (ibfd, osec, & merged_notes))
0b07f1
+	    {
0b07f1
+	      bfd_nonfatal_message (NULL, ibfd, osec, _("warning: could not load note section"));
0b07f1
+	      free (merged_notes);
0b07f1
+	      merged_notes = NULL;
0b07f1
+	      merge_notes = FALSE;
0b07f1
+	    }
0b07f1
+	  else
0b07f1
+	    {
0b07f1
+	      merged_size = merge_gnu_build_notes (ibfd, osec, size, merged_notes);
0b07f1
+	      if (merged_size == size)
0b07f1
+		{
0b07f1
+		  /* Merging achieves nothing.  */
0b07f1
+		  free (merged_notes);
0b07f1
+		  merged_notes = NULL;
0b07f1
+		  merge_notes = FALSE;
0b07f1
+		  merged_size = 0;
0b07f1
+		}
0b07f1
+	      else
0b07f1
+		{
0b07f1
+		  if (osec->output_section == NULL
0b07f1
+		      || ! bfd_set_section_size (obfd, osec->output_section, merged_size))
0b07f1
+		    {
0b07f1
+		      bfd_nonfatal_message (NULL, obfd, osec, _("warning: failed to set merged notes size"));
0b07f1
+		      free (merged_notes);
0b07f1
+		      merged_notes = NULL;
0b07f1
+		      merge_notes = FALSE;
0b07f1
+		      merged_size = 0;
0b07f1
+		    }
0b07f1
+		}
0b07f1
+	    }
0b07f1
+	}
0b07f1
+    }
0b07f1
+
0b07f1
   if (dump_sections != NULL)
0b07f1
     {
0b07f1
       struct section_add * pdump;
0b07f1
@@ -2454,6 +2780,24 @@ copy_object (bfd *ibfd, bfd *obfd, const
0b07f1
 	}
0b07f1
     }
0b07f1
 
0b07f1
+  if (merge_notes)
0b07f1
+    {
0b07f1
+      asection * osec = bfd_get_section_by_name (obfd, GNU_BUILD_ATTRS_SECTION_NAME);
0b07f1
+      if (osec && is_merged_note_section (obfd, osec))
0b07f1
+	{
0b07f1
+	  if (! bfd_set_section_contents (obfd, osec, merged_notes, 0, merged_size))
0b07f1
+	    {
0b07f1
+	      bfd_nonfatal_message (NULL, obfd, osec, _("error: failed to copy merged notes into output"));
0b07f1
+	      return FALSE;
0b07f1
+	    }
0b07f1
+	}
0b07f1
+      else
0b07f1
+	bfd_nonfatal_message (NULL, obfd, osec, _("ICE: lost merged note section"));
0b07f1
+      free (merged_notes);
0b07f1
+      merged_notes = NULL;
0b07f1
+      merge_notes = FALSE;
0b07f1
+    }
0b07f1
+
0b07f1
   if (gnu_debuglink_filename != NULL)
0b07f1
     {
0b07f1
       if (! bfd_fill_in_gnu_debuglink_section
0b07f1
@@ -3179,7 +3523,7 @@ setup_section (bfd *ibfd, sec_ptr isecti
0b07f1
 /* Return TRUE if input section ISECTION should be skipped.  */
0b07f1
 
0b07f1
 static bfd_boolean
0b07f1
-skip_section (bfd *ibfd, sec_ptr isection)
0b07f1
+skip_section (bfd *ibfd, sec_ptr isection, bfd_boolean skip_copy)
0b07f1
 {
0b07f1
   sec_ptr osection;
0b07f1
   bfd_size_type size;
0b07f1
@@ -3199,6 +3543,11 @@ skip_section (bfd *ibfd, sec_ptr isectio
0b07f1
   if (is_update_section (ibfd, isection))
0b07f1
     return TRUE;
0b07f1
 
0b07f1
+  /* When merging a note section we skip the copying of the contents,
0b07f1
+     but not the copying of the relocs associated with the contents.  */
0b07f1
+  if (skip_copy && is_merged_note_section (ibfd, isection))
0b07f1
+    return TRUE;
0b07f1
+
0b07f1
   flags = bfd_get_section_flags (ibfd, isection);
0b07f1
   if ((flags & SEC_GROUP) != 0)
0b07f1
     return TRUE;
0b07f1
@@ -3265,7 +3614,7 @@ copy_relocations_in_section (bfd *ibfd,
0b07f1
   long relcount;
0b07f1
   sec_ptr osection;
0b07f1
 
0b07f1
-  if (skip_section (ibfd, isection))
0b07f1
+  if (skip_section (ibfd, isection, FALSE))
0b07f1
     return;
0b07f1
 
0b07f1
   osection = isection->output_section;
0b07f1
@@ -3354,7 +3703,7 @@ copy_section (bfd *ibfd, sec_ptr isectio
0b07f1
   sec_ptr osection;
0b07f1
   bfd_size_type size;
0b07f1
 
0b07f1
-  if (skip_section (ibfd, isection))
0b07f1
+  if (skip_section (ibfd, isection, TRUE))
0b07f1
     return;
0b07f1
 
0b07f1
   osection = isection->output_section;
0b07f1
@@ -4010,7 +4359,7 @@ copy_main (int argc, char *argv[])
0b07f1
   struct stat statbuf;
0b07f1
   const bfd_arch_info_type *input_arch = NULL;
0b07f1
 
0b07f1
-  while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
0b07f1
+  while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:MN:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
0b07f1
 			   copy_options, (int *) 0)) != EOF)
0b07f1
     {
0b07f1
       switch (c)
0b07f1
@@ -4104,6 +4453,10 @@ copy_main (int argc, char *argv[])
0b07f1
 	  add_specific_symbol (optarg, keep_specific_htab);
0b07f1
 	  break;
0b07f1
 
0b07f1
+	case 'M':
0b07f1
+	  merge_notes = TRUE;
0b07f1
+	  break;
0b07f1
+
0b07f1
 	case 'N':
0b07f1
 	  add_specific_symbol (optarg, strip_specific_htab);
0b07f1
 	  break;
0b07f1
diff -rup binutils.orig/binutils/readelf.c binutils-2.28/binutils/readelf.c
0b07f1
--- binutils.orig/binutils/readelf.c	2017-03-20 17:03:56.164605476 +0000
0b07f1
+++ binutils-2.28/binutils/readelf.c	2017-03-20 17:06:13.368265213 +0000
0b07f1
@@ -15557,6 +15557,10 @@ get_note_type (unsigned e_type)
0b07f1
 	return _("NT_VERSION (version)");
0b07f1
       case NT_ARCH:
0b07f1
 	return _("NT_ARCH (architecture)");
0b07f1
+      case NT_GNU_BUILD_ATTRIBUTE_OPEN:
0b07f1
+	return _("NT_GNU_BUILD_ATTRIBUTE_OPEN");
0b07f1
+      case NT_GNU_BUILD_ATTRIBUTE_FUNC:
0b07f1
+	return _("NT_GNU_BUILD_ATTRIBUTE_FUNC");
0b07f1
       default:
0b07f1
 	break;
0b07f1
       }
0b07f1
@@ -15665,6 +15669,12 @@ get_gnu_elf_note_type (unsigned e_type)
0b07f1
       return _("NT_GNU_BUILD_ID (unique build ID bitstring)");
0b07f1
     case NT_GNU_GOLD_VERSION:
0b07f1
       return _("NT_GNU_GOLD_VERSION (gold version)");
0b07f1
+    case NT_GNU_PROPERTY_TYPE_0:
0b07f1
+      return _("NT_GNU_PROPERTY_TYPE_0");
0b07f1
+    case NT_GNU_BUILD_ATTRIBUTE_OPEN:
0b07f1
+      return _("NT_GNU_BUILD_ATTRIBUTE_OPEN");
0b07f1
+    case NT_GNU_BUILD_ATTRIBUTE_FUNC:
0b07f1
+      return _("NT_GNU_BUILD_ATTRIBUTE_FUNC");
0b07f1
     default:
0b07f1
       {
0b07f1
 	static char buff[64];
0b07f1
@@ -15675,6 +15685,155 @@ get_gnu_elf_note_type (unsigned e_type)
0b07f1
     }
0b07f1
 }
0b07f1
 
0b07f1
+static void
0b07f1
+decode_x86_isa (unsigned int bitmask)
0b07f1
+{
0b07f1
+  while (bitmask)
0b07f1
+    {
0b07f1
+      unsigned int bit = bitmask & (- bitmask);
0b07f1
+
0b07f1
+      bitmask &= ~ bit;
0b07f1
+      switch (bit)
0b07f1
+	{
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_486: printf ("i486"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_586: printf ("586"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_686: printf ("686"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_SSE: printf ("SSE"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_SSE2: printf ("SSE2"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_SSE3: printf ("SSE3"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_SSSE3: printf ("SSSE3"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_SSE4_1: printf ("SSE4_1"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_SSE4_2: printf ("SSE4_2"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX: printf ("AVX"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX2: printf ("AVX2"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX512F: printf ("AVX512F"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX512CD: printf ("AVX512CD"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX512ER: printf ("AVX512ER"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX512PF: printf ("AVX512PF"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX512VL: printf ("AVX512VL"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX512DQ: printf ("AVX512DQ"); break;
0b07f1
+	case GNU_PROPERTY_X86_ISA_1_AVX512BW: printf ("AVX512BW"); break;
0b07f1
+	default: printf (_("<unknown: %x>"), bit); break;
0b07f1
+	}
0b07f1
+      if (bitmask)
0b07f1
+	printf (", ");
0b07f1
+    }
0b07f1
+}
0b07f1
+
0b07f1
+static void
0b07f1
+print_gnu_property_note (Elf_Internal_Note * pnote)
0b07f1
+{
0b07f1
+  unsigned char * ptr = (unsigned char *) pnote->descdata;
0b07f1
+  unsigned char * ptr_end = ptr + pnote->descsz;
0b07f1
+  unsigned int    size = is_32bit_elf ? 4 : 8;
0b07f1
+
0b07f1
+  printf (_("      Properties: "));
0b07f1
+
0b07f1
+  if (pnote->descsz < 8 || (pnote->descsz % size) != 0)
0b07f1
+    {
0b07f1
+      printf (_("<corrupt GNU_PROPERTY_TYPE, size = %#lx>\n"), pnote->descsz);
0b07f1
+      return;
0b07f1
+    }
0b07f1
+
0b07f1
+  while (1)
0b07f1
+    {
0b07f1
+      unsigned int j;
0b07f1
+      unsigned int type = byte_get (ptr, 4);
0b07f1
+      unsigned int datasz = byte_get (ptr + 4, 4);
0b07f1
+
0b07f1
+      ptr += 8;
0b07f1
+
0b07f1
+      if ((ptr + datasz) > ptr_end)
0b07f1
+	{
0b07f1
+	  printf (_("<corrupt type (%#x) datasz: %#x>\n"),
0b07f1
+		  type, datasz);
0b07f1
+	  break;
0b07f1
+	}
0b07f1
+
0b07f1
+      if (type >= GNU_PROPERTY_LOPROC && type <= GNU_PROPERTY_HIPROC)
0b07f1
+	{
0b07f1
+	  if (elf_header.e_machine == EM_X86_64
0b07f1
+	      || elf_header.e_machine == EM_IAMCU
0b07f1
+	      || elf_header.e_machine == EM_386)
0b07f1
+	    {
0b07f1
+	      switch (type)
0b07f1
+		{
0b07f1
+		case GNU_PROPERTY_X86_ISA_1_USED:
0b07f1
+		  printf ("x86 ISA used: ");
0b07f1
+		  if (datasz != 4)
0b07f1
+		    printf (_("<corrupt length: %#x> "), datasz);
0b07f1
+		  else
0b07f1
+		    decode_x86_isa (byte_get (ptr, 4));
0b07f1
+		  goto next;
0b07f1
+
0b07f1
+		case GNU_PROPERTY_X86_ISA_1_NEEDED:
0b07f1
+		  printf ("x86 ISA needed: ");
0b07f1
+		  if (datasz != 4)
0b07f1
+		    printf (_("<corrupt length: %#x> "), datasz);
0b07f1
+		  else
0b07f1
+		    decode_x86_isa (byte_get (ptr, 4));
0b07f1
+		  goto next;
0b07f1
+
0b07f1
+		default:
0b07f1
+		  break;
0b07f1
+		}
0b07f1
+	    }
0b07f1
+	}
0b07f1
+      else
0b07f1
+	{
0b07f1
+	  switch (type)
0b07f1
+	    {
0b07f1
+	    case GNU_PROPERTY_STACK_SIZE:
0b07f1
+	      printf (_("stack size: "));
0b07f1
+	      if (datasz != size)
0b07f1
+		printf (_("<corrupt length: %#x> "), datasz);
0b07f1
+	      else
0b07f1
+		printf ("%#lx", (unsigned long) byte_get (ptr, size));
0b07f1
+	      goto next;
0b07f1
+
0b07f1
+	    case GNU_PROPERTY_NO_COPY_ON_PROTECTED:
0b07f1
+	      printf ("no copy on protected ");
0b07f1
+	      if (datasz)
0b07f1
+		printf (_("<corrupt length: %#x> "), datasz);
0b07f1
+	      goto next;
0b07f1
+
0b07f1
+	    default:
0b07f1
+	      break;
0b07f1
+	    }
0b07f1
+	}
0b07f1
+
0b07f1
+      if (type < GNU_PROPERTY_LOPROC)
0b07f1
+	printf (_("
0b07f1
+      else if (type < GNU_PROPERTY_LOUSER)
0b07f1
+	printf (_("
0b07f1
+      else
0b07f1
+	printf (_("
0b07f1
+      for (j = 0; j < datasz; ++j)
0b07f1
+	printf ("%02x ", ptr[j] & 0xff);
0b07f1
+      printf (">");
0b07f1
+
0b07f1
+next:
0b07f1
+      ptr += ((datasz + (size - 1)) & ~ (size - 1));
0b07f1
+      if (ptr == ptr_end)
0b07f1
+	break;
0b07f1
+      else
0b07f1
+	{
0b07f1
+	  if (do_wide)
0b07f1
+	    printf (", ");
0b07f1
+	  else
0b07f1
+	    printf ("\n\t");
0b07f1
+	}
0b07f1
+
0b07f1
+      if (ptr > (ptr_end - 8))
0b07f1
+	{
0b07f1
+	  printf (_("<corrupt descsz: %#lx>\n"), pnote->descsz);
0b07f1
+	  break;
0b07f1
+	}
0b07f1
+    }
0b07f1
+
0b07f1
+  printf ("\n");
0b07f1
+}
0b07f1
+
0b07f1
 static int
0b07f1
 print_gnu_note (Elf_Internal_Note *pnote)
0b07f1
 {
0b07f1
@@ -15775,6 +15934,10 @@ print_gnu_note (Elf_Internal_Note *pnote
0b07f1
       }
0b07f1
       break;
0b07f1
 
0b07f1
+    case NT_GNU_PROPERTY_TYPE_0:
0b07f1
+      print_gnu_property_note (pnote);
0b07f1
+      break;
0b07f1
+      
0b07f1
     default:
0b07f1
       /* Handle unrecognised types.  An error message should have already been
0b07f1
 	 created by get_gnu_elf_note_type(), so all that we need to do is to
0b07f1
@@ -16164,15 +16327,370 @@ print_ia64_vms_note (Elf_Internal_Note *
0b07f1
   return 1;
0b07f1
 }
0b07f1
 
0b07f1
+/* Print the name of the symbol associated with a build attribute
0b07f1
+   that is attached to address OFFSET.  */
0b07f1
+
0b07f1
+static bfd_boolean
0b07f1
+print_symbol_for_build_attribute (FILE *         file,
0b07f1
+				  unsigned long  offset,
0b07f1
+				  bfd_boolean    is_open_attr)
0b07f1
+{
0b07f1
+  static FILE *             saved_file = NULL;
0b07f1
+  static char *             strtab;
0b07f1
+  static unsigned long      strtablen;
0b07f1
+  static Elf_Internal_Sym * symtab;
0b07f1
+  static unsigned long      nsyms;
0b07f1
+  Elf_Internal_Sym *  saved_sym = NULL;
0b07f1
+  Elf_Internal_Sym *  sym;
0b07f1
+
0b07f1
+  if (saved_file == NULL || file != saved_file)
0b07f1
+    {
0b07f1
+      Elf_Internal_Shdr * symsec;
0b07f1
+
0b07f1
+      /* Load the symbol and string sections.  */
0b07f1
+      for (symsec = section_headers;
0b07f1
+	   symsec < section_headers + elf_header.e_shnum;
0b07f1
+	   symsec ++)
0b07f1
+	{
0b07f1
+	  if (symsec->sh_type == SHT_SYMTAB)
0b07f1
+	    {
0b07f1
+	      symtab = GET_ELF_SYMBOLS (file, symsec, & nsyms);
0b07f1
+
0b07f1
+	      if (symsec->sh_link < elf_header.e_shnum)
0b07f1
+		{
0b07f1
+		  Elf_Internal_Shdr * strtab_sec = section_headers + symsec->sh_link;
0b07f1
+
0b07f1
+		  strtab = (char *) get_data (NULL, file, strtab_sec->sh_offset,
0b07f1
+					      1, strtab_sec->sh_size,
0b07f1
+					      _("string table"));
0b07f1
+		  strtablen = strtab != NULL ? strtab_sec->sh_size : 0;
0b07f1
+		}
0b07f1
+	    }
0b07f1
+	}
0b07f1
+      saved_file = file;
0b07f1
+    }
0b07f1
+
0b07f1
+  if (symtab == NULL || strtab == NULL)
0b07f1
+    {
0b07f1
+      printf ("\n");
0b07f1
+      return FALSE;
0b07f1
+    }
0b07f1
+
0b07f1
+  /* Find a symbol whose value matches offset.  */
0b07f1
+  for (sym = symtab; sym < symtab + nsyms; sym ++)
0b07f1
+    if (sym->st_value == offset)
0b07f1
+      {
0b07f1
+	if (sym->st_name >= strtablen)
0b07f1
+	  /* Huh ?  This should not happen.  */
0b07f1
+	  continue;
0b07f1
+
0b07f1
+	if (strtab[sym->st_name] == 0)
0b07f1
+	  continue;
0b07f1
+
0b07f1
+	if (is_open_attr)
0b07f1
+	  {
0b07f1
+	    /* For OPEN attributes we prefer GLOBAL over LOCAL symbols
0b07f1
+	       and FILE or OBJECT symbols over NOTYPE symbols.  We skip
0b07f1
+	       FUNC symbols entirely.  */
0b07f1
+	    switch (ELF_ST_TYPE (sym->st_info))
0b07f1
+	      {
0b07f1
+	      case STT_FILE:
0b07f1
+		saved_sym = sym;
0b07f1
+		/* We can stop searching now.  */
0b07f1
+		sym = symtab + nsyms;
0b07f1
+		continue;
0b07f1
+
0b07f1
+	      case STT_OBJECT:
0b07f1
+		saved_sym = sym;
0b07f1
+		continue;
0b07f1
+
0b07f1
+	      case STT_FUNC:
0b07f1
+		/* Ignore function symbols.  */
0b07f1
+		continue;
0b07f1
+
0b07f1
+	      default:
0b07f1
+		break;
0b07f1
+	      }
0b07f1
+
0b07f1
+	    switch (ELF_ST_BIND (sym->st_info))
0b07f1
+	      {
0b07f1
+	      case STB_GLOBAL:
0b07f1
+		if (saved_sym == NULL
0b07f1
+		    || ELF_ST_TYPE (saved_sym->st_info) != STT_OBJECT)
0b07f1
+		  saved_sym = sym;
0b07f1
+		break;
0b07f1
+
0b07f1
+	      case STB_LOCAL:
0b07f1
+		if (saved_sym == NULL)
0b07f1
+		  saved_sym = sym;
0b07f1
+		break;
0b07f1
+
0b07f1
+	      default:
0b07f1
+		break;
0b07f1
+	      }
0b07f1
+	  }
0b07f1
+	else
0b07f1
+	  {
0b07f1
+	    if (ELF_ST_TYPE (sym->st_info) != STT_FUNC)
0b07f1
+	      continue;
0b07f1
+
0b07f1
+	    saved_sym = sym;
0b07f1
+	    break;
0b07f1
+	  }
0b07f1
+      }
0b07f1
+
0b07f1
+  printf (" (%s: %s)\n",
0b07f1
+	  is_open_attr ? _("file") : _("func"),
0b07f1
+	  saved_sym ? strtab + saved_sym->st_name : _("<no symbol found>)"));
0b07f1
+  return TRUE;
0b07f1
+}
0b07f1
+
0b07f1
+static bfd_boolean
0b07f1
+print_gnu_build_attribute_description (Elf_Internal_Note * pnote,
0b07f1
+				       FILE *              file)
0b07f1
+{
0b07f1
+  static unsigned long global_offset = 0;
0b07f1
+  unsigned long        offset;
0b07f1
+  unsigned int         desc_size = is_32bit_elf ? 4 : 8;
0b07f1
+  bfd_boolean          is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
0b07f1
+
0b07f1
+  if (pnote->descsz == 0)
0b07f1
+    {
0b07f1
+      if (is_open_attr)
0b07f1
+	{
0b07f1
+	  printf (_("    Applies from offset %#lx\n"), global_offset);
0b07f1
+	  return TRUE;
0b07f1
+	}
0b07f1
+      else
0b07f1
+	{
0b07f1
+	  printf (_("    Applies to func at %#lx"), global_offset);
0b07f1
+	  return print_symbol_for_build_attribute (file, global_offset, is_open_attr);
0b07f1
+	}
0b07f1
+    }
0b07f1
+
0b07f1
+  if (pnote->descsz != desc_size)
0b07f1
+    {
0b07f1
+      error (_("    <invalid description size: %lx>\n"), pnote->descsz);
0b07f1
+      printf (_("    <invalid descsz>"));
0b07f1
+      return FALSE;
0b07f1
+    }
0b07f1
+
0b07f1
+  offset = byte_get ((unsigned char *) pnote->descdata, desc_size);
0b07f1
+
0b07f1
+  if (is_open_attr)
0b07f1
+    {
0b07f1
+      printf (_("    Applies from offset %#lx"), offset);
0b07f1
+      global_offset = offset;
0b07f1
+    }
0b07f1
+  else
0b07f1
+    {
0b07f1
+      printf (_("    Applies to func at %#lx"), offset);
0b07f1
+    }
0b07f1
+
0b07f1
+  return print_symbol_for_build_attribute (file, offset, is_open_attr);
0b07f1
+}
0b07f1
+
0b07f1
+static bfd_boolean
0b07f1
+print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
0b07f1
+{
0b07f1
+  char         name_type;
0b07f1
+  char         name_attribute;
0b07f1
+  char *       expected_types;
0b07f1
+  const char * name = pnote->namedata;
0b07f1
+  const char * text;
0b07f1
+  int          left;
0b07f1
+
0b07f1
+  if (name == NULL || pnote->namesz < 2)
0b07f1
+    {
0b07f1
+      error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
0b07f1
+      print_symbol (-20, _("  <corrupt name field>"));
0b07f1
+      return FALSE;
0b07f1
+    }
0b07f1
+
0b07f1
+  switch ((name_type = * name))
0b07f1
+    {
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC:
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_STRING:
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE:
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE:
0b07f1
+      printf ("%c", * name);
0b07f1
+      break;
0b07f1
+    default:
0b07f1
+      error (_("unrecognised attribute type in name field: %d\n"), name_type);
0b07f1
+      print_symbol (-20, _("<unknown name type>"));
0b07f1
+      return FALSE;
0b07f1
+    }
0b07f1
+
0b07f1
+  left = 19;
0b07f1
+  ++ name;
0b07f1
+  text = NULL;
0b07f1
+
0b07f1
+  switch ((name_attribute = * name))
0b07f1
+    {
0b07f1
+    case GNU_BUILD_ATTRIBUTE_VERSION:
0b07f1
+      text = _("<version>");
0b07f1
+      expected_types = "$";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_STACK_PROT:
0b07f1
+      text = _("<stack prot>");
0b07f1
+      expected_types = "!+*";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_RELRO:
0b07f1
+      text = _("<relro>");
0b07f1
+      expected_types = "!+";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_STACK_SIZE:
0b07f1
+      text = _("<stack size>");
0b07f1
+      expected_types = "*";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TOOL:
0b07f1
+      text = _("<tool>");
0b07f1
+      expected_types = "$";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_ABI:
0b07f1
+      text = _("<ABI>");
0b07f1
+      expected_types = "$*";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_PIC:
0b07f1
+      text = _("<PIC>");
0b07f1
+      expected_types = "*";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_SHORT_ENUM:
0b07f1
+      text = _("<short enum>");
0b07f1
+      expected_types = "!+";
0b07f1
+      ++ name;
0b07f1
+      break;
0b07f1
+
0b07f1
+    default:
0b07f1
+      if (ISPRINT (* name))
0b07f1
+	{
0b07f1
+	  int len = strnlen (name, pnote->namesz - (name - pnote->namedata)) + 1;
0b07f1
+
0b07f1
+	  if (len > left && ! do_wide)
0b07f1
+	    len = left;
0b07f1
+	  printf ("%.*s:", len, name);
0b07f1
+	  left -= len;
0b07f1
+	  name += len;
0b07f1
+	}
0b07f1
+      else
0b07f1
+	{
0b07f1
+	  error (_("unexpected character in name field\n"));
0b07f1
+	  print_symbol (- left, _("<unknown attribute>"));
0b07f1
+	  return 0;
0b07f1
+	}
0b07f1
+      expected_types = "*$!+";
0b07f1
+      break;
0b07f1
+    }
0b07f1
+
0b07f1
+  if (text)
0b07f1
+    {
0b07f1
+      printf ("%s", text);
0b07f1
+      left -= strlen (text);
0b07f1
+    }
0b07f1
+
0b07f1
+  if (strchr (expected_types, name_type) == NULL)
0b07f1
+    warn (_("attribute does not have an expected type (%c)\n"), name_type);
0b07f1
+
0b07f1
+  if ((unsigned long)(name - pnote->namedata) > pnote->namesz)
0b07f1
+    {
0b07f1
+      error (_("corrupt name field: namesz: %lu but parsing gets to %ld\n"),
0b07f1
+	     (unsigned long) pnote->namesz,
0b07f1
+	     (long) (name - pnote->namedata));
0b07f1
+      return FALSE;
0b07f1
+    }
0b07f1
+
0b07f1
+  if (left < 1 && ! do_wide)
0b07f1
+    return TRUE;
0b07f1
+
0b07f1
+  switch (name_type)
0b07f1
+    {
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC:
0b07f1
+      {
0b07f1
+	unsigned int   bytes = pnote->namesz - (name - pnote->namedata);
0b07f1
+	unsigned long  val = 0;
0b07f1
+	unsigned int   shift = 0;
0b07f1
+	char *         decoded = NULL;
0b07f1
+
0b07f1
+	while (bytes --)
0b07f1
+	  {
0b07f1
+	    unsigned long byte = (* name ++) & 0xff;
0b07f1
+
0b07f1
+	    val |= byte << shift;
0b07f1
+	    shift += 8;
0b07f1
+	  }
0b07f1
+
0b07f1
+	switch (name_attribute)
0b07f1
+	  {
0b07f1
+	  case GNU_BUILD_ATTRIBUTE_PIC:
0b07f1
+	    switch (val)
0b07f1
+	      {
0b07f1
+	      case 0: decoded = "static"; break;
0b07f1
+	      case 1: decoded = "pic"; break;
0b07f1
+	      case 2: decoded = "PIC"; break;
0b07f1
+	      case 3: decoded = "pie"; break;
0b07f1
+	      case 4: decoded = "PIE"; break;
0b07f1
+	      default: break;
0b07f1
+	      }
0b07f1
+	    break;
0b07f1
+	  case GNU_BUILD_ATTRIBUTE_STACK_PROT:
0b07f1
+	    switch (val)
0b07f1
+	      {
0b07f1
+		/* Based upon the SPCT_FLAG_xxx enum values in gcc/cfgexpand.c.  */
0b07f1
+	      case 0: decoded = "off"; break;
0b07f1
+	      case 1: decoded = "on"; break;
0b07f1
+	      case 2: decoded = "all"; break;
0b07f1
+	      case 3: decoded = "strong"; break;
0b07f1
+	      case 4: decoded = "explicit"; break;
0b07f1
+	      default: break;
0b07f1
+	      }
0b07f1
+	    break;
0b07f1
+	  default:
0b07f1
+	    break;
0b07f1
+	  }
0b07f1
+
0b07f1
+	if (decoded != NULL)
0b07f1
+	  print_symbol (-left, decoded);
0b07f1
+	else
0b07f1
+	  {
0b07f1
+	    if (do_wide)
0b07f1
+	      left -= printf ("0x%lx", val);
0b07f1
+	    else
0b07f1
+	      left -= printf ("0x%-.*lx", left, val);
0b07f1
+	  }
0b07f1
+      }
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_STRING:
0b07f1
+      left -= print_symbol (- left, name);
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE:
0b07f1
+      left -= print_symbol (- left, "true");
0b07f1
+      break;
0b07f1
+    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE:
0b07f1
+      left -= print_symbol (- left, "false");
0b07f1
+      break;
0b07f1
+    }
0b07f1
+
0b07f1
+  if (do_wide && left > 0)
0b07f1
+    printf ("%-*s", left, " ");
0b07f1
+    
0b07f1
+  return TRUE;
0b07f1
+}
0b07f1
+
0b07f1
 /* Note that by the ELF standard, the name field is already null byte
0b07f1
    terminated, and namesz includes the terminating null byte.
0b07f1
    I.E. the value of namesz for the name "FSF" is 4.
0b07f1
 
0b07f1
    If the value of namesz is zero, there is no name present.  */
0b07f1
 static int
0b07f1
-process_note (Elf_Internal_Note * pnote,
0b07f1
-	      FILE * file ATTRIBUTE_UNUSED,
0b07f1
-	      Elf_Internal_Shdr * section ATTRIBUTE_UNUSED)
0b07f1
+process_note (Elf_Internal_Note *  pnote,
0b07f1
+	      FILE *               file)
0b07f1
 {
0b07f1
   const char * name = pnote->namesz ? pnote->namedata : "(NONE)";
0b07f1
   const char * nt;
0b07f1
@@ -16218,8 +16736,17 @@ process_note (Elf_Internal_Note * pnote,
0b07f1
     nt = get_note_type (pnote->type);
0b07f1
 
0b07f1
   printf ("  ");
0b07f1
-  print_symbol (-20, name);
0b07f1
-  printf (" 0x%08lx\t%s\n", pnote->descsz, nt);
0b07f1
+
0b07f1
+  if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN
0b07f1
+      || pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC)
0b07f1
+    print_gnu_build_attribute_name (pnote);
0b07f1
+  else
0b07f1
+    print_symbol (-20, name);
0b07f1
+
0b07f1
+  if (do_wide)
0b07f1
+    printf (" 0x%08lx\t%s\t", pnote->descsz, nt);
0b07f1
+  else
0b07f1
+    printf (" 0x%08lx\t%s\n", pnote->descsz, nt);
0b07f1
 
0b07f1
   if (const_strneq (pnote->namedata, "IPF/VMS"))
0b07f1
     return print_ia64_vms_note (pnote);
0b07f1
@@ -16229,17 +16756,22 @@ process_note (Elf_Internal_Note * pnote,
0b07f1
     return print_stapsdt_note (pnote);
0b07f1
   else if (const_strneq (pnote->namedata, "CORE"))
0b07f1
     return print_core_note (pnote);
0b07f1
+  else if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN
0b07f1
+	   || pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC)
0b07f1
+    return print_gnu_build_attribute_description (pnote, file);
0b07f1
 
0b07f1
-  else if (pnote->descsz)
0b07f1
+  if (pnote->descsz)
0b07f1
     {
0b07f1
       unsigned long i;
0b07f1
 
0b07f1
       printf (_("   description data: "));
0b07f1
       for (i = 0; i < pnote->descsz; i++)
0b07f1
 	printf ("%02x ", pnote->descdata[i]);
0b07f1
-      printf ("\n");
0b07f1
     }
0b07f1
 
0b07f1
+  if (do_wide)
0b07f1
+    printf ("\n");
0b07f1
+
0b07f1
   return 1;
0b07f1
 }
0b07f1
 
0b07f1
@@ -16369,14 +16901,14 @@ process_notes_at (FILE *              fi
0b07f1
 	      break;
0b07f1
 	    }
0b07f1
 
0b07f1
-	  strncpy (temp, inote.namedata, inote.namesz);
0b07f1
+	  memcpy (temp, inote.namedata, inote.namesz);
0b07f1
 	  temp[inote.namesz] = 0;
0b07f1
 
0b07f1
 	  /* warn (_("'%s' NOTE name not properly null terminated\n"), temp);  */
0b07f1
 	  inote.namedata = temp;
0b07f1
 	}
0b07f1
 
0b07f1
-      res &= process_note (& inote, file, section);
0b07f1
+      res &= process_note (& inote, file);
0b07f1
 
0b07f1
       if (temp != NULL)
0b07f1
 	{
0b07f1
Only in binutils-2.28/binutils/testsuite/binutils-all: note-2-32.d
0b07f1
Only in binutils-2.28/binutils/testsuite/binutils-all: note-2-32.s
0b07f1
Only in binutils-2.28/binutils/testsuite/binutils-all: note-2-64.d
0b07f1
Only in binutils-2.28/binutils/testsuite/binutils-all: note-2-64.s
0b07f1
diff -rup binutils.orig/binutils/testsuite/binutils-all/objcopy.exp binutils-2.28/binutils/testsuite/binutils-all/objcopy.exp
0b07f1
--- binutils.orig/binutils/testsuite/binutils-all/objcopy.exp	2017-03-20 17:03:56.174605306 +0000
0b07f1
+++ binutils-2.28/binutils/testsuite/binutils-all/objcopy.exp	2017-03-20 17:04:07.721408353 +0000
0b07f1
@@ -1053,6 +1053,11 @@ if [is_elf_format] {
0b07f1
     run_dump_test "group-6"
0b07f1
     run_dump_test "copy-1"
0b07f1
     run_dump_test "note-1"
0b07f1
+    if [is_elf64 tmpdir/bintest.o] {
0b07f1
+	run_dump_test "note-2-64"
0b07f1
+    } else {
0b07f1
+	run_dump_test "note-2-32"
0b07f1
+    }
0b07f1
 }
0b07f1
 
0b07f1
 run_dump_test "copy-2"
0b07f1
diff -rup binutils.orig/include/elf/common.h binutils-2.28/include/elf/common.h
0b07f1
--- binutils.orig/include/elf/common.h	2017-03-20 17:03:56.417601161 +0000
0b07f1
+++ binutils-2.28/include/elf/common.h	2017-03-20 17:04:07.733408149 +0000
0b07f1
@@ -538,6 +538,7 @@
0b07f1
 
0b07f1
 /* #define SHF_MASKOS	0x0F000000    *//* OS-specific semantics */
0b07f1
 #define SHF_MASKOS	0x0FF00000	/* New value, Oct 4, 1999 Draft */
0b07f1
+#define SHF_GNU_BUILD_NOTE    (1 << 20)	/* Section contains GNU BUILD ATTRIBUTE notes.  */
0b07f1
 #define SHF_MASKPROC	0xF0000000	/* Processor-specific semantics */
0b07f1
 
0b07f1
 /* This used to be implemented as a processor specific section flag.
0b07f1
@@ -669,6 +670,62 @@
0b07f1
 #define NT_GNU_HWCAP		2	/* Used by ld.so and kernel vDSO.  */
0b07f1
 #define NT_GNU_BUILD_ID		3	/* Generated by ld --build-id.  */
0b07f1
 #define NT_GNU_GOLD_VERSION	4	/* Generated by gold.  */
0b07f1
+#define NT_GNU_PROPERTY_TYPE_0  5	/* Generated by gcc.  */
0b07f1
+
0b07f1
+#define NT_GNU_BUILD_ATTRIBUTE_OPEN	0x100
0b07f1
+#define NT_GNU_BUILD_ATTRIBUTE_FUNC	0x101
0b07f1
+
0b07f1
+#define GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC	'*'
0b07f1
+#define GNU_BUILD_ATTRIBUTE_TYPE_STRING		'$'
0b07f1
+#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE	'+'
0b07f1
+#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE	'!'
0b07f1
+
0b07f1
+#define GNU_BUILD_ATTRIBUTE_VERSION	1
0b07f1
+#define GNU_BUILD_ATTRIBUTE_STACK_PROT	2
0b07f1
+#define GNU_BUILD_ATTRIBUTE_RELRO	3
0b07f1
+#define GNU_BUILD_ATTRIBUTE_STACK_SIZE	4
0b07f1
+#define GNU_BUILD_ATTRIBUTE_TOOL	5
0b07f1
+#define GNU_BUILD_ATTRIBUTE_ABI		6
0b07f1
+#define GNU_BUILD_ATTRIBUTE_PIC		7
0b07f1
+#define GNU_BUILD_ATTRIBUTE_SHORT_ENUM		8
0b07f1
+
0b07f1
+#define NOTE_GNU_PROPERTY_SECTION_NAME	".note.gnu.property"
0b07f1
+#define GNU_BUILD_ATTRS_SECTION_NAME	".gnu.build.attributes"
0b07f1
+
0b07f1
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0).  */
0b07f1
+#define GNU_PROPERTY_STACK_SIZE			1
0b07f1
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED	2
0b07f1
+
0b07f1
+/* Processor-specific semantics, lo */
0b07f1
+#define GNU_PROPERTY_LOPROC  0xc0000000
0b07f1
+/* Processor-specific semantics, hi */
0b07f1
+#define GNU_PROPERTY_HIPROC  0xdfffffff
0b07f1
+/* Application-specific semantics, lo */
0b07f1
+#define GNU_PROPERTY_LOUSER  0xe0000000
0b07f1
+/* Application-specific semantics, hi */
0b07f1
+#define GNU_PROPERTY_HIUSER  0xffffffff
0b07f1
+
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_USED		0xc0000000
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_NEEDED		0xc0000001
0b07f1
+
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_486           (1U << 0)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_586           (1U << 1)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_686           (1U << 2)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_SSE           (1U << 3)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_SSE2          (1U << 4)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_SSE3          (1U << 5)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_SSSE3         (1U << 6)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_SSE4_1        (1U << 7)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_SSE4_2        (1U << 8)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX           (1U << 9)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX2          (1U << 10)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX512F       (1U << 11)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX512CD      (1U << 12)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX512ER      (1U << 13)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX512PF      (1U << 14)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX512VL      (1U << 15)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX512DQ      (1U << 16)
0b07f1
+#define GNU_PROPERTY_X86_ISA_1_AVX512BW      (1U << 17)
0b07f1
 
0b07f1
 /* Values used in GNU .note.ABI-tag notes (NT_GNU_ABI_TAG).  */
0b07f1
 #define GNU_ABI_TAG_LINUX	0
0b07f1
--- /dev/null	2017-03-20 08:02:04.287194455 +0000
0b07f1
+++ binutils-2.28/binutils/testsuite/binutils-all/note-2-32.s	2017-03-20 17:16:18.922951480 +0000
0b07f1
@@ -0,0 +1,95 @@
0b07f1
+	.text
0b07f1
+	.org 0x100
0b07f1
+	.global note1.s
0b07f1
+note1.s:
0b07f1
+	.word 0
0b07f1
+	
0b07f1
+	.pushsection .gnu.build.attributes, "0x100000", %note
0b07f1
+	.balign 4
0b07f1
+	.dc.l 4
0b07f1
+	.dc.l 4
0b07f1
+	.dc.l 0x100
0b07f1
+	.asciz "$?1"
0b07f1
+	.dc.l note1.s
0b07f1
+
0b07f1
+	.dc.l 12
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.asciz "$?gcc 7.0.1"
0b07f1
+
0b07f1
+	.dc.l 2
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.dc.b 0x2b, 0x2
0b07f1
+	.dc.b  0, 0
0b07f1
+
0b07f1
+	.dc.l 3
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.dc.b 0x2a, 0x7, 0
0b07f1
+	.dc.b  0
0b07f1
+
0b07f1
+	.dc.l 3
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.dc.b 0x2a, 0x6, 0
0b07f1
+	.dc.b  0
0b07f1
+	.popsection
0b07f1
+
0b07f1
+
0b07f1
+	.global note2.s
0b07f1
+note2.s:
0b07f1
+	.type func1, STT_FUNC
0b07f1
+func1:	
0b07f1
+	.word 0x100
0b07f1
+	
0b07f1
+	.pushsection .gnu.build.attributes, "0x100000", %note
0b07f1
+	.dc.l 4 	
0b07f1
+	.dc.l 4		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?1"	
0b07f1
+	.dc.l note2.s	
0b07f1
+
0b07f1
+	.dc.l 12 	
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?gcc 7.0.1"	
0b07f1
+
0b07f1
+	.dc.l 2		
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.dc.b 0x21, 0x2	
0b07f1
+	.dc.b  0, 0 	
0b07f1
+
0b07f1
+	.dc.l 3		
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x101	
0b07f1
+	.dc.b 0x2a, 0x7, 1 	
0b07f1
+	.dc.b  0 	
0b07f1
+
0b07f1
+	.dc.l 3		
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.dc.b 0x2a, 0x6, 0 	
0b07f1
+	.dc.b  0 	
0b07f1
+	.popsection
0b07f1
+
0b07f1
+	.global note3.s
0b07f1
+note3.s:
0b07f1
+	.word 0x100
0b07f1
+	
0b07f1
+	.pushsection .gnu.build.attributes, "0x100000", %note
0b07f1
+	.dc.l 4 	
0b07f1
+	.dc.l 4		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?1"	
0b07f1
+	.dc.l note3.s
0b07f1
+
0b07f1
+	.dc.l 12 	
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?gcc 7.0.1"	
0b07f1
+
0b07f1
+	.popsection
0b07f1
+	
0b07f1
+	
0b07f1
--- /dev/null	2017-03-20 08:02:04.287194455 +0000
0b07f1
+++ binutils-2.28/binutils/testsuite/binutils-all/note-2-32.d	2017-03-20 17:16:18.922951480 +0000
0b07f1
@@ -0,0 +1,17 @@
0b07f1
+#PROG: objcopy
0b07f1
+#readelf: --notes --wide
0b07f1
+#objcopy: --merge-notes
0b07f1
+#name: merge notes section (32-bits)
0b07f1
+#source: note-2-32.s
0b07f1
+
0b07f1
+#...
0b07f1
+  Owner                 Data size	Description
0b07f1
+[ 	]+\$<version>1[ 	]+0x00000004[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100 \(file: note1.s\)
0b07f1
+[ 	]+\$<tool>gcc 7.0.1[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\+<stack prot>true[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\*<PIC>static[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\*<ABI>0x0[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\$<version>1[ 	]+0x00000004[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10. \(file: note2.s\)
0b07f1
+[ 	]+!<stack prot>false[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10.
0b07f1
+[ 	]+\*<PIC>pic[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ 	]+Applies to func at 0x10. \(func: func1\)
0b07f1
+#...
0b07f1
--- /dev/null	2017-03-20 08:02:04.287194455 +0000
0b07f1
+++ binutils-2.28/binutils/testsuite/binutils-all/note-2-64.d	2017-03-20 17:16:18.922951480 +0000
0b07f1
@@ -0,0 +1,17 @@
0b07f1
+#PROG: objcopy
0b07f1
+#readelf: --notes --wide
0b07f1
+#objcopy: --merge-notes
0b07f1
+#name: merge notes section (64-bits)
0b07f1
+#source: note-2-64.s
0b07f1
+
0b07f1
+#...
0b07f1
+  Owner                 Data size	Description
0b07f1
+[ 	]+\$<version>1[ 	]+0x00000008[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100 \(file: note1.s\)
0b07f1
+[ 	]+\$<tool>gcc 7.0.1[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\+<stack prot>true[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\*<PIC>static[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\*<ABI>0x0[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x100
0b07f1
+[ 	]+\$<version>1[ 	]+0x00000008[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10. \(file: note2.s\)
0b07f1
+[ 	]+!<stack prot>false[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ 	]+Applies from offset 0x10.
0b07f1
+[ 	]+\*<PIC>pic[ 	]+0x00000000[ 	]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ 	]+Applies to func at 0x10. \(func: func1\)
0b07f1
+#...
0b07f1
--- /dev/null	2017-03-20 08:02:04.287194455 +0000
0b07f1
+++ binutils-2.28/binutils/testsuite/binutils-all/note-2-64.s	2017-03-20 17:16:18.922951480 +0000
0b07f1
@@ -0,0 +1,97 @@
0b07f1
+	.text
0b07f1
+	.org 0x100
0b07f1
+	.global note1.s
0b07f1
+note1.s:
0b07f1
+	.word 0
0b07f1
+	
0b07f1
+	.pushsection .gnu.build.attributes, "0x100000", %note
0b07f1
+	.balign 4
0b07f1
+	.dc.l 4
0b07f1
+	.dc.l 8
0b07f1
+	.dc.l 0x100
0b07f1
+	.asciz "$?1"
0b07f1
+	.8byte note1.s
0b07f1
+
0b07f1
+	.dc.l 12
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.asciz "$?gcc 7.0.1"
0b07f1
+
0b07f1
+	.dc.l 2
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.dc.b 0x2b, 0x2
0b07f1
+	.dc.b  0, 0
0b07f1
+
0b07f1
+	.dc.l 3
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.dc.b 0x2a, 0x7, 0
0b07f1
+	.dc.b  0
0b07f1
+
0b07f1
+	.dc.l 3
0b07f1
+	.dc.l 0
0b07f1
+	.dc.l 0x100
0b07f1
+	.dc.b 0x2a, 0x6, 0
0b07f1
+	.dc.b  0
0b07f1
+	.popsection
0b07f1
+
0b07f1
+
0b07f1
+	.global note2.s
0b07f1
+note2.s:
0b07f1
+	.global func1
0b07f1
+	.type func1, STT_FUNC
0b07f1
+func1:	
0b07f1
+	.word 0x100
0b07f1
+
0b07f1
+	.pushsection .gnu.build.attributes, "0x100000", %note
0b07f1
+	.dc.l 4 	
0b07f1
+	.dc.l 8		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?1"	
0b07f1
+	.8byte note2.s	
0b07f1
+
0b07f1
+	.dc.l 12 	
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?gcc 7.0.1"	
0b07f1
+
0b07f1
+	.dc.l 2		
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.dc.b 0x21, 0x2	
0b07f1
+	.dc.b  0, 0 	
0b07f1
+
0b07f1
+	.dc.l 3		
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x101	
0b07f1
+	.dc.b 0x2a, 0x7, 1 	
0b07f1
+	.dc.b  0 	
0b07f1
+
0b07f1
+	.dc.l 3		
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.dc.b 0x2a, 0x6, 0 	
0b07f1
+	.dc.b  0 	
0b07f1
+	.popsection
0b07f1
+	
0b07f1
+
0b07f1
+	.global note3.s
0b07f1
+note3.s:
0b07f1
+	.word 0x100
0b07f1
+	
0b07f1
+	.pushsection .gnu.build.attributes, "0x100000", %note
0b07f1
+	.dc.l 4 	
0b07f1
+	.dc.l 8		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?1"	
0b07f1
+	.8byte note3.s
0b07f1
+
0b07f1
+	.dc.l 12 	
0b07f1
+	.dc.l 0		
0b07f1
+	.dc.l 0x100	
0b07f1
+	.asciz "$?gcc 7.0.1"	
0b07f1
+
0b07f1
+	.popsection
0b07f1
+	
0b07f1
+	
0b07f1
diff -rup binutils.orig/binutils/readelf.c binutils-2.28/binutils/readelf.c
0b07f1
--- binutils.orig/binutils/readelf.c	2017-05-15 17:12:12.760814593 +0100
0b07f1
+++ binutils-2.28/binutils/readelf.c	2017-05-15 17:26:46.142293641 +0100
0b07f1
@@ -4130,7 +4130,18 @@ get_section_type_name (unsigned int sh_t
0b07f1
 	      if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
0b07f1
 		result = get_solaris_section_type (sh_type);
0b07f1
 	      else
0b07f1
-		result = NULL;
0b07f1
+		{
0b07f1
+		  switch (sh_type)
0b07f1
+		    {
0b07f1
+		    case SHT_GNU_INCREMENTAL_INPUTS: result = "GNU_INCREMENTAL_INPUTS"; break;
0b07f1
+		    case SHT_GNU_ATTRIBUTES: result = "GNU_ATTRIBUTES"; break;
0b07f1
+		    case SHT_GNU_HASH: result = "GNU_HASH"; break;
0b07f1
+		    case SHT_GNU_LIBLIST: result = "GNU_LIBLIST"; break;
0b07f1
+		    default:
0b07f1
+		      result = NULL;
0b07f1
+		      break;
0b07f1
+		    }
0b07f1
+		}
0b07f1
 	      break;
0b07f1
 	    }
0b07f1
 
0b07f1
@@ -15928,8 +15939,8 @@ print_gnu_note (Elf_Internal_Note *pnote
0b07f1
 	printf (_("      Hardware Capabilities: "));
0b07f1
 	if (pnote->descsz < 8)
0b07f1
 	  {
0b07f1
-	    printf (_("<corrupt GNU_HWCAP>\n"));
0b07f1
-	    break;
0b07f1
+	    error (_("<corrupt GNU_HWCAP>\n"));
0b07f1
+	    return 0;
0b07f1
 	  }
0b07f1
 	num_entries = byte_get ((unsigned char *) pnote->descdata, 4);
0b07f1
 	mask = byte_get ((unsigned char *) pnote->descdata + 4, 4);
0b07f1
@@ -16347,7 +16358,8 @@ print_symbol_for_build_attribute (FILE *
0b07f1
   Elf_Internal_Sym *  saved_sym = NULL;
0b07f1
   Elf_Internal_Sym *  sym;
0b07f1
 
0b07f1
-  if (saved_file == NULL || file != saved_file)
0b07f1
+  if (section_headers != NULL
0b07f1
+      && (saved_file == NULL || file != saved_file))
0b07f1
     {
0b07f1
       Elf_Internal_Shdr * symsec;
0b07f1
 
0b07f1
@@ -16497,9 +16509,12 @@ print_gnu_build_attribute_description (E
0b07f1
 static bfd_boolean
0b07f1
 print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
0b07f1
 {
0b07f1
+  static const char string_expected [2] = { GNU_BUILD_ATTRIBUTE_TYPE_STRING, 0 };
0b07f1
+  static const char number_expected [2] = { GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC, 0 };
0b07f1
+  static const char bool_expected [3] = { GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE, GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE, 0 };
0b07f1
   char         name_type;
0b07f1
   char         name_attribute;
0b07f1
-  char *       expected_types;
0b07f1
+  const char * expected_types;
0b07f1
   const char * name = pnote->namedata;
0b07f1
   const char * text;
0b07f1
   int          left;
0b07f1
@@ -16507,7 +16522,7 @@ print_gnu_build_attribute_name (Elf_Inte
0b07f1
   if (name == NULL || pnote->namesz < 2)
0b07f1
     {
0b07f1
       error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
0b07f1
-      print_symbol (-20, _("  <corrupt name field>"));
0b07f1
+      print_symbol (-20, _("  <corrupt name>"));
0b07f1
       return FALSE;
0b07f1
     }
0b07f1
 
0b07f1
@@ -16533,7 +16548,7 @@ print_gnu_build_attribute_name (Elf_Inte
0b07f1
     {
0b07f1
     case GNU_BUILD_ATTRIBUTE_VERSION:
0b07f1
       text = _("<version>");
0b07f1
-      expected_types = "$";
0b07f1
+      expected_types = string_expected;
0b07f1
       ++ name;
0b07f1
       break;
0b07f1
     case GNU_BUILD_ATTRIBUTE_STACK_PROT:
0b07f1
@@ -16543,17 +16558,17 @@ print_gnu_build_attribute_name (Elf_Inte
0b07f1
       break;
0b07f1
     case GNU_BUILD_ATTRIBUTE_RELRO:
0b07f1
       text = _("<relro>");
0b07f1
-      expected_types = "!+";
0b07f1
+      expected_types = bool_expected;
0b07f1
       ++ name;
0b07f1
       break;
0b07f1
     case GNU_BUILD_ATTRIBUTE_STACK_SIZE:
0b07f1
       text = _("<stack size>");
0b07f1
-      expected_types = "*";
0b07f1
+      expected_types = number_expected;
0b07f1
       ++ name;
0b07f1
       break;
0b07f1
     case GNU_BUILD_ATTRIBUTE_TOOL:
0b07f1
       text = _("<tool>");
0b07f1
-      expected_types = "$";
0b07f1
+      expected_types = string_expected;
0b07f1
       ++ name;
0b07f1
       break;
0b07f1
     case GNU_BUILD_ATTRIBUTE_ABI:
0b07f1
@@ -16563,12 +16578,12 @@ print_gnu_build_attribute_name (Elf_Inte
0b07f1
       break;
0b07f1
     case GNU_BUILD_ATTRIBUTE_PIC:
0b07f1
       text = _("<PIC>");
0b07f1
-      expected_types = "*";
0b07f1
+      expected_types = number_expected;
0b07f1
       ++ name;
0b07f1
       break;
0b07f1
     case GNU_BUILD_ATTRIBUTE_SHORT_ENUM:
0b07f1
       text = _("<short enum>");
0b07f1
-      expected_types = "!+";
0b07f1
+      expected_types = bool_expected;
0b07f1
       ++ name;
0b07f1
       break;
0b07f1
 
0b07f1
@@ -16585,9 +16600,11 @@ print_gnu_build_attribute_name (Elf_Inte
0b07f1
 	}
0b07f1
       else
0b07f1
 	{
0b07f1
-	  error (_("unexpected character in name field\n"));
0b07f1
-	  print_symbol (- left, _("<unknown attribute>"));
0b07f1
-	  return 0;
0b07f1
+	  static char tmpbuf [128];
0b07f1
+	  error (_("unrecognised byte in name field: %d\n"), * name);
0b07f1
+	  sprintf (tmpbuf, _("<unknown:_%d>"), * name);
0b07f1
+	  text = tmpbuf;
0b07f1
+	  name ++;
0b07f1
 	}
0b07f1
       expected_types = "*$!+";
0b07f1
       break;
0b07f1
@@ -16617,11 +16634,29 @@ print_gnu_build_attribute_name (Elf_Inte
0b07f1
     {
0b07f1
     case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC:
0b07f1
       {
0b07f1
-	unsigned int   bytes = pnote->namesz - (name - pnote->namedata);
0b07f1
-	unsigned long  val = 0;
0b07f1
+	unsigned int   bytes;
0b07f1
+	unsigned long long val = 0;
0b07f1
 	unsigned int   shift = 0;
0b07f1
 	char *         decoded = NULL;
0b07f1
 
0b07f1
+	bytes = pnote->namesz - (name - pnote->namedata);
0b07f1
+	if (bytes > 0)
0b07f1
+	  /* The -1 is because the name field is always 0 terminated, and we
0b07f1
+	     want to be able to ensure that the shift in the while loop below
0b07f1
+	     will not overflow.  */
0b07f1
+	  -- bytes;
0b07f1
+
0b07f1
+	if (bytes > sizeof (val))
0b07f1
+	  {
0b07f1
+	    fprintf (stderr, "namesz %lx name %p namedata %p\n",
0b07f1
+		     pnote->namesz, name, pnote->namedata);
0b07f1
+	    error (_("corrupt numeric name field: too many bytes in the value: %x\n"),
0b07f1
+		   bytes);
0b07f1
+	    bytes = sizeof (val);
0b07f1
+	  }
0b07f1
+	/* We do not bother to warn if bytes == 0 as this can
0b07f1
+	   happen with some early versions of the gcc plugin.  */
0b07f1
+
0b07f1
 	while (bytes --)
0b07f1
 	  {
0b07f1
 	    unsigned long byte = (* name ++) & 0xff;
0b07f1
@@ -16660,13 +16695,21 @@ print_gnu_build_attribute_name (Elf_Inte
0b07f1
 	  }
0b07f1
 
0b07f1
 	if (decoded != NULL)
0b07f1
-	  print_symbol (-left, decoded);
0b07f1
+	  {
0b07f1
+	    print_symbol (-left, decoded);
0b07f1
+	    left = 0;
0b07f1
+	  }
0b07f1
+	else if (val == 0)
0b07f1
+	  {
0b07f1
+	    printf ("0x0");
0b07f1
+	    left -= 3;
0b07f1
+	  }
0b07f1
 	else
0b07f1
 	  {
0b07f1
 	    if (do_wide)
0b07f1
-	      left -= printf ("0x%lx", val);
0b07f1
+	      left -= printf ("0x%llx", val);
0b07f1
 	    else
0b07f1
-	      left -= printf ("0x%-.*lx", left, val);
0b07f1
+	      left -= printf ("0x%-.*llx", left, val);
0b07f1
 	  }
0b07f1
       }
0b07f1
       break;
0b07f1
diff -rup binutils.orig/binutils/testsuite/binutils-all/note-2-32.s binutils-2.28/binutils/testsuite/binutils-all/note-2-32.s
0b07f1
--- binutils.orig/binutils/testsuite/binutils-all/note-2-32.s	2017-05-23 11:03:36.320767285 +0100
0b07f1
+++ binutils-2.28/binutils/testsuite/binutils-all/note-2-32.s	2017-05-23 11:04:48.851919399 +0100
0b07f1
@@ -17,23 +17,21 @@ note1.s:
0b07f1
 	.dc.l 0x100
0b07f1
 	.asciz "$?gcc 7.0.1"
0b07f1
 
0b07f1
-	.dc.l 2
0b07f1
+	.dc.l 3
0b07f1
 	.dc.l 0
0b07f1
 	.dc.l 0x100
0b07f1
-	.dc.b 0x2b, 0x2
0b07f1
-	.dc.b  0, 0
0b07f1
+	.dc.b 0x2b, 0x2, 0
0b07f1
+	.dc.b 0
0b07f1
 
0b07f1
-	.dc.l 3
0b07f1
+	.dc.l 4
0b07f1
 	.dc.l 0
0b07f1
 	.dc.l 0x100
0b07f1
-	.dc.b 0x2a, 0x7, 0
0b07f1
-	.dc.b  0
0b07f1
+	.dc.b 0x2a, 0x7, 0, 0
0b07f1
 
0b07f1
-	.dc.l 3
0b07f1
+	.dc.l 4
0b07f1
 	.dc.l 0
0b07f1
 	.dc.l 0x100
0b07f1
-	.dc.b 0x2a, 0x6, 0
0b07f1
-	.dc.b  0
0b07f1
+	.dc.b 0x2a, 0x6, 0, 0
0b07f1
 	.popsection
0b07f1
 
0b07f1
 
0b07f1
@@ -55,23 +53,21 @@ func1:
0b07f1
 	.dc.l 0x100	
0b07f1
 	.asciz "$?gcc 7.0.1"	
0b07f1
 
0b07f1
-	.dc.l 2		
0b07f1
+	.dc.l 3		
0b07f1
 	.dc.l 0		
0b07f1
 	.dc.l 0x100	
0b07f1
-	.dc.b 0x21, 0x2	
0b07f1
-	.dc.b  0, 0 	
0b07f1
+	.dc.b 0x21, 0x2, 0
0b07f1
+	.dc.b 0 	
0b07f1
 
0b07f1
-	.dc.l 3		
0b07f1
+	.dc.l 4		
0b07f1
 	.dc.l 0		
0b07f1
 	.dc.l 0x101	
0b07f1
-	.dc.b 0x2a, 0x7, 1 	
0b07f1
-	.dc.b  0 	
0b07f1
+	.dc.b 0x2a, 0x7, 1, 0
0b07f1
 
0b07f1
-	.dc.l 3		
0b07f1
+	.dc.l 4		
0b07f1
 	.dc.l 0		
0b07f1
 	.dc.l 0x100	
0b07f1
-	.dc.b 0x2a, 0x6, 0 	
0b07f1
-	.dc.b  0 	
0b07f1
+	.dc.b 0x2a, 0x6, 0, 0
0b07f1
 	.popsection
0b07f1
 
0b07f1
 	.global note3.s
0b07f1
@@ -91,5 +87,3 @@ note3.s:
0b07f1
 	.asciz "$?gcc 7.0.1"	
0b07f1
 
0b07f1
 	.popsection
0b07f1
-	
0b07f1
-	
0b07f1
diff -rup binutils.orig/binutils/testsuite/binutils-all/note-2-64.s binutils-2.28/binutils/testsuite/binutils-all/note-2-64.s
0b07f1
--- binutils.orig/binutils/testsuite/binutils-all/note-2-64.s	2017-05-23 11:03:36.322767262 +0100
0b07f1
+++ binutils-2.28/binutils/testsuite/binutils-all/note-2-64.s	2017-05-23 11:05:15.333609830 +0100
0b07f1
@@ -17,23 +17,21 @@ note1.s:
0b07f1
 	.dc.l 0x100
0b07f1
 	.asciz "$?gcc 7.0.1"
0b07f1
 
0b07f1
-	.dc.l 2
0b07f1
+	.dc.l 3
0b07f1
 	.dc.l 0
0b07f1
 	.dc.l 0x100
0b07f1
-	.dc.b 0x2b, 0x2
0b07f1
-	.dc.b  0, 0
0b07f1
+	.dc.b 0x2b, 0x2, 0
0b07f1
+	.dc.b 0
0b07f1
 
0b07f1
-	.dc.l 3
0b07f1
+	.dc.l 4
0b07f1
 	.dc.l 0
0b07f1
 	.dc.l 0x100
0b07f1
-	.dc.b 0x2a, 0x7, 0
0b07f1
-	.dc.b  0
0b07f1
+	.dc.b 0x2a, 0x7, 0, 0
0b07f1
 
0b07f1
-	.dc.l 3
0b07f1
+	.dc.l 4
0b07f1
 	.dc.l 0
0b07f1
 	.dc.l 0x100
0b07f1
-	.dc.b 0x2a, 0x6, 0
0b07f1
-	.dc.b  0
0b07f1
+	.dc.b 0x2a, 0x6, 0, 0
0b07f1
 	.popsection
0b07f1
 
0b07f1
 
0b07f1
@@ -56,23 +54,21 @@ func1:
0b07f1
 	.dc.l 0x100	
0b07f1
 	.asciz "$?gcc 7.0.1"	
0b07f1
 
0b07f1
-	.dc.l 2		
0b07f1
+	.dc.l 3		
0b07f1
 	.dc.l 0		
0b07f1
 	.dc.l 0x100	
0b07f1
-	.dc.b 0x21, 0x2	
0b07f1
-	.dc.b  0, 0 	
0b07f1
+	.dc.b 0x21, 0x2, 0
0b07f1
+	.dc.b 0 	
0b07f1
 
0b07f1
-	.dc.l 3		
0b07f1
+	.dc.l 4
0b07f1
 	.dc.l 0		
0b07f1
 	.dc.l 0x101	
0b07f1
-	.dc.b 0x2a, 0x7, 1 	
0b07f1
-	.dc.b  0 	
0b07f1
+	.dc.b 0x2a, 0x7, 1, 0
0b07f1
 
0b07f1
-	.dc.l 3		
0b07f1
+	.dc.l 4
0b07f1
 	.dc.l 0		
0b07f1
 	.dc.l 0x100	
0b07f1
-	.dc.b 0x2a, 0x6, 0 	
0b07f1
-	.dc.b  0 	
0b07f1
+	.dc.b 0x2a, 0x6, 0, 0
0b07f1
 	.popsection
0b07f1
 	
0b07f1
 
0b07f1
@@ -93,5 +89,3 @@ note3.s:
0b07f1
 	.asciz "$?gcc 7.0.1"	
0b07f1
 
0b07f1
 	.popsection
0b07f1
-	
0b07f1
-