From b2802c5afa0790eea1dd42b4c7b4fc2938784cb4 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 31 May 2017 16:12:25 -0400
Subject: [PATCH 35/38] FIXME: hack in annobin

---
 gcc/Makefile.in       |   2 +
 gcc/annobin.cc        | 891 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/annobin.h         |  99 ++++++
 gcc/x86_64.annobin.cc | 211 ++++++++++++
 4 files changed, 1203 insertions(+)
 create mode 100644 gcc/annobin.cc
 create mode 100644 gcc/annobin.h
 create mode 100644 gcc/x86_64.annobin.cc

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7c044a3..4608a88 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1214,6 +1214,8 @@ OBJS = \
 	ggc-page.o \
 	alias.o \
 	alloc-pool.o \
+	annobin.o \
+	x86_64.annobin.o \
 	auto-inc-dec.o \
 	auto-profile.o \
 	bb-reorder.o \
diff --git a/gcc/annobin.cc b/gcc/annobin.cc
new file mode 100644
index 0000000..f674ada
--- /dev/null
+++ b/gcc/annobin.cc
@@ -0,0 +1,891 @@
+/* annobin - a gcc plugin for annotating binary files.
+   Copyright (c) 2017 Red Hat.
+   Created by Nick Clifton.
+
+  This is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  It is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.  */
+
+#include "annobin.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <intl.h>
+
+/* The version of the annotation specification supported by this plugin.  */
+#define SPEC_VERSION  1
+
+/* Required by the GCC plugin API.  */
+int            plugin_is_GPL_compatible;
+
+/* True if this plugin is enabled.  Disabling is permitted so that build
+   systems can globally enable the plugin, and then have specific build
+   targets that disable the plugin because they do not want it.  */
+static bool    enabled = true;
+
+/* True if the symbols used to map addresses to file names should be global.
+   On some architectures these symbols have to be global so that they will
+   be preserved in object files.  But doing so can prevent the build-id
+   mechanism from working, since the symbols contain build-date information.  */
+static bool    global_file_name_symbols = false;
+
+/* True if notes about the stack usage should be included.  Doing can be useful
+   if stack overflow problems need to be diagnosed, but they do increase the size
+   of the note section quite a lot.  */
+bool           annobin_enable_stack_size_notes = false;
+unsigned long  annobin_total_static_stack_usage = 0;
+unsigned long  annobin_max_stack_size = 0;
+
+/* If a function's static stack size requirement is greater than STACK_THRESHOLD
+   then a function specific note will be generated indicating the amount of stack
+   that it needs.  */
+#define DEFAULT_THRESHOLD (10240)
+static unsigned long  stack_threshold = DEFAULT_THRESHOLD;
+
+/* Internal variable, used by target specific parts of the annobin plugin as well
+   as this generic part.  True if the object file being generated is for a 64-bit
+   target.  */
+bool           annobin_is_64bit = false;
+
+/* True if notes in the .note.gnu.property section should be produced.  */
+static bool           annobin_enable_dynamic_notes = true;
+
+/* True if notes in the .gnu.build.attributes section should be produced.  */
+static bool           annobin_enable_static_notes = true;
+
+static unsigned int   global_GOWall_options = 0;
+static int            global_stack_prot_option = -1;
+static int            global_pic_option = -1;
+static int            global_short_enums = -1;
+static char *         compiler_version = NULL;
+static unsigned       verbose_level = 0;
+static char *         annobin_current_filename = NULL;
+static unsigned char  annobin_version = 1; /* NB. Keep in sync with version_string.  */
+static const char *   version_string = N_("Version 1");
+static const char *   help_string =  N_("Supported options:\n\
+   disable                Disable this plugin\n\
+   enable                 Enable this plugin\n\
+   help                   Print out this information\n\
+   version                Print out the version of the plugin\n\
+   verbose                Be talkative about what is going on\n\
+   [no-]dynamic-notes     Do [do not] create dynamic notes (default: do)\n\
+   [no-]static-notes      Do [do not] create static notes (default: do)\n\
+   [no-]global-file-syms  Create global [or local] file name symbols (default: local)\n\
+   [no-]stack-size-notes  Do [do not] create stack size notes (default: do not)\n\
+   stack-threshold=N      Only create function specific stack size notes when the size is > N.");
+
+static struct plugin_info annobin_info =
+{
+  version_string,
+  help_string
+};
+
+/* Create a symbol name to represent the sources we are annotating.
+   Since there can be multiple input files, we choose the main output
+   filename (stripped of any path prefixes).  Since filenames can
+   contain characters that symbol names do not (eg '-') we have to
+   allocate our own name.  */
+
+static void
+init_annobin_current_filename (void)
+{
+  char * name;
+  unsigned i;
+
+  if (annobin_current_filename != NULL
+      || main_input_filename == NULL)
+    return;
+
+  name = (char *) lbasename (main_input_filename);
+  if (global_file_name_symbols)
+    name = strcpy ((char *) xmalloc (strlen (name) + 20), name);
+  else
+    name = xstrdup (name);
+
+  /* Convert any non-symbolic characters into underscores.  */
+  for (i = strlen (name); i--;)
+    {
+      char c = name[i];
+
+      if (! ISALNUM (c) && c != '_' && c != '.' && c != '$')
+	name[i] = '_';
+      else if (i == 0 && ISDIGIT (c))
+	name[i] = '_';
+    }
+
+  if (global_file_name_symbols)
+    {
+      /* A program can have multiple source files with the same name.
+	 Or indeed the same source file can be included multiple times.
+	 Or a library can be built from a sources which include file names
+	 that match application file names.  Whatever the reason, we need
+	 to be ensure that we generate unique global symbol names.  So we
+	 append the time to the symbol name.  This will of course break
+	 the functionality of build-ids.  That is why this option is off
+	 by default.  */
+      struct timeval tv;
+
+      if (gettimeofday (& tv, NULL))
+	{
+	  annobin_inform (0, "ICE: unable to get time of day.");
+	  tv.tv_sec = tv.tv_usec = 0;
+	}
+      sprintf (name + strlen (name),
+	       "_%8.8lx_%8.8lx", (long) tv.tv_sec, (long) tv.tv_usec);
+    }
+
+  annobin_current_filename = name;
+}
+
+void
+annobin_inform (unsigned level, const char * format, ...)
+{
+  va_list args;
+
+  if (level > 0 && level > verbose_level)
+    return;
+
+  fflush (stdout);
+  fprintf (stderr, "annobin: ");
+  if (annobin_current_filename == NULL)
+    init_annobin_current_filename ();
+  if (annobin_current_filename)
+    fprintf (stderr, "%s: ", annobin_current_filename);
+  va_start (args, format);
+  vfprintf (stderr, format, args);
+  va_end (args);
+  putc ('\n', stderr);
+}
+
+void
+annobin_output_note (const void * name, unsigned namesz, bool name_is_string,
+		     const char * name_description,
+		     const void * desc, unsigned descsz, bool desc_is_string,
+		     unsigned type)
+{
+  unsigned i;
+
+  if (type == NT_GNU_BUILD_ATTRIBUTE_FUNC
+      || type == NT_GNU_BUILD_ATTRIBUTE_OPEN)
+    {
+      fprintf (asm_out_file, "\t.pushsection %s\n", GNU_BUILD_ATTRS_SECTION_NAME);    
+    }
+
+  if (name == NULL)
+    {
+      if (namesz)
+	annobin_inform (0, "ICE: null name with non-zero size");
+      fprintf (asm_out_file, "\t.dc.l 0\t\t%s no name\n", ASM_COMMENT_START);
+    }
+  else if (name_is_string)
+    {
+      if (strlen ((char *) name) != namesz - 1)
+	annobin_inform (0, "ICE: name string '%s' does not match name size %d", name, namesz);
+      fprintf (asm_out_file, "\t.dc.l %u \t%s namesz = strlen (%s)\n", namesz, ASM_COMMENT_START, (char *) name);
+    }
+  else
+    fprintf (asm_out_file, "\t.dc.l %u\t\t%s size of name\n", namesz, ASM_COMMENT_START);
+
+  if (desc == NULL)
+    {
+      if (descsz)
+	annobin_inform (0, "ICE: null desc with non-zero size");
+      fprintf (asm_out_file, "\t.dc.l 0\t\t%s no description\n", ASM_COMMENT_START);
+    }
+  else if (desc_is_string)
+    {
+      if (descsz != (annobin_is_64bit ? 8 : 4))
+	annobin_inform (0, "ICE: description string size (%d) not sizeof address 8/4", descsz);
+      fprintf (asm_out_file, "\t.dc.l %u\t\t%s descsz = sizeof (address)\n", descsz, ASM_COMMENT_START);
+    }
+  else
+    fprintf (asm_out_file, "\t.dc.l %u\t\t%s size of description\n", descsz, ASM_COMMENT_START);
+
+  fprintf (asm_out_file, "\t.dc.l %#x\t%s type = %s\n", type, ASM_COMMENT_START,
+	   type == NT_GNU_BUILD_ATTRIBUTE_OPEN ? "OPEN" :
+	   type == NT_GNU_BUILD_ATTRIBUTE_FUNC ? "FUNC" :
+	   type == NT_GNU_PROPERTY_TYPE_0      ? "PROPERTY_TYPE_0" : "*UNKNOWN*");
+
+  if (name)
+    {
+      if (name_is_string)
+	{
+	  fprintf (asm_out_file, "\t.asciz \"%s\"", (char *) name);
+	}
+      else
+	{
+	  fprintf (asm_out_file, "\t.dc.b");
+	  for (i = 0; i < namesz; i++)
+	    fprintf (asm_out_file, " %#x%c",
+		     ((unsigned char *) name)[i],
+		     i < (namesz - 1) ? ',' : ' ');
+	}
+
+      fprintf (asm_out_file, "\t%s name (%s)\n",
+	       ASM_COMMENT_START, name_description);
+
+      if (namesz % 4)
+	{
+	  fprintf (asm_out_file, "\t.dc.b");
+	  while (namesz % 4)
+	    {
+	      namesz++;
+	      fprintf (asm_out_file, " 0%c", namesz % 4 ? ',' : ' ');
+	    }
+	  fprintf (asm_out_file, "\t%s Padding\n", ASM_COMMENT_START);
+	}
+    }
+
+  if (desc)
+    {
+      if (desc_is_string)
+	{
+	  /* The DESCRIPTION string is the name of a symbol.  We want to produce
+	     a reference to this symbol of the appropriate size for the target
+	     architecture.  */
+	  if (annobin_is_64bit)
+	    fprintf (asm_out_file, "\t.quad %s", (char *) desc);
+	  else
+	    fprintf (asm_out_file, "\t.dc.l %s", (char *) desc);
+	  fprintf (asm_out_file, "\t%s description (symbol name)\n", ASM_COMMENT_START);
+	}
+      else
+	{
+	  fprintf (asm_out_file, "\t.dc.b");
+
+	  for (i = 0; i < descsz; i++)
+	    {
+	      fprintf (asm_out_file, " %#x", ((unsigned char *) desc)[i]);
+	      if (i == (descsz - 1))
+		fprintf (asm_out_file, "\t%s description\n", ASM_COMMENT_START);
+	      else if ((i % 8) == 7)
+		fprintf (asm_out_file, "\t%s description\n\t.dc.b", ASM_COMMENT_START);
+	      else
+		fprintf (asm_out_file, ",");
+	    }
+
+	  if (descsz % 4)
+	    {
+	      fprintf (asm_out_file, "\t.dc.b");
+	      while (descsz % 4)
+		{
+		  descsz++;
+		  fprintf (asm_out_file, " 0%c", descsz % 4 ? ',' : ' ');
+		}
+	      fprintf (asm_out_file, "\t%s Padding\n", ASM_COMMENT_START);
+	    }
+	}
+    }
+
+  if (type == NT_GNU_BUILD_ATTRIBUTE_FUNC
+      || type == NT_GNU_BUILD_ATTRIBUTE_OPEN)
+    {
+      fprintf (asm_out_file, "\t.popsection\n");
+      fflush (asm_out_file);
+    }
+
+  fprintf (asm_out_file, "\n");
+}
+
+void
+annobin_output_bool_note (const char    bool_type,
+			  const bool    bool_value,
+			  const char *  name_description,
+			  const char *  description,
+			  unsigned      note_type)
+{
+  char buffer [1024]; /* FIXME: Is this enough ?  */
+
+  snprintf (buffer, sizeof buffer, "%c%c",
+	    bool_value ? GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE : GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE,
+	    bool_type);
+
+  /* Include the NUL byte at the end of the name "string".
+     This is required by the ELF spec.  */
+  annobin_output_note (buffer, 3, false, name_description,
+		       description, description == NULL ? 0 : (annobin_is_64bit ? 8 : 4),
+		       description != NULL, note_type);
+}
+
+void
+annobin_output_string_note (const char    string_type,
+			    const char *  string,
+			    const char *  name_description,
+			    const char *  description,
+			    unsigned      note_type)
+{
+  char buffer [1024]; /* FIXME: Is this enough ?  */
+
+  snprintf (buffer, sizeof buffer, "%c%c%s", GNU_BUILD_ATTRIBUTE_TYPE_STRING,
+	    string_type, string);
+
+  annobin_output_note (buffer, strlen (buffer) + 1, true, name_description,
+		       description, description == NULL ? 0 : (annobin_is_64bit ? 8 : 4),
+		       description != NULL, note_type);
+}
+
+void
+annobin_output_numeric_note (const char     numeric_type,
+			     unsigned long  value,
+			     const char *   name_description,
+			     const char *   description,
+			     unsigned       note_type)
+{
+  unsigned i;
+  char buffer [32];
+  
+  sprintf (buffer, "%c%c", GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC, numeric_type);
+
+  if (value == 0)
+    {
+      /* We need to record *two* zero bytes for a zero value.  One for
+	 the value itself and one as a NUL terminator, since this is a
+	 name field...  */
+      buffer [2] = buffer [3] = 0;
+      i = 3;
+    }
+  else
+    {
+      for (i = 2; i < sizeof buffer; i++)
+	{
+	  buffer[i] = value & 0xff;
+	  /* Note - The name field in ELF Notes must be NUL terminated, even if,
+	     like here, it is not really being used as a name.  Hence the test
+	     for value being zero is performed here, rather than after the shift.  */
+	  if (value == 0)
+	    break;
+	  value >>= 8;
+	}
+    }
+
+  /* If the value needs more than 8 bytes, consumers are unlikely to be able
+     to handle it.  */
+  if (i > 10)
+    annobin_inform (0, "ICE: Numeric value for %s too big to fit into 8 bytes\n", name_description);
+  if (value)
+    annobin_inform (0, "ICE: Unable to record numeric value in note %s\n", name_description);
+
+  annobin_output_note (buffer, i + 1, false, name_description,
+		       description, description == NULL ? 0 : (annobin_is_64bit ? 8 : 4), true,
+		       note_type);
+}
+
+static int
+compute_pic_option (void)
+{
+  if (flag_pie > 1)
+    return 4;
+  if (flag_pie)
+    return 3;
+  if (flag_pic > 1)
+    return 2;
+  if (flag_pic)
+    return 1;
+  return 0;
+}
+
+/* Compute a numeric value representing the settings/levels of
+   the -O and -g options, and whether -Wall has been used.  This
+   is to help verify the recommended hardening options for binaries.
+   The format of the number is as follows:
+
+   bits 0 -  2 : debug type (from enum debug_info_type)
+   bit  3      : with GNU extensions
+   bits 4 -  5 : debug level (from enum debug_info_levels)
+   bits 6 -  8 : DWARF version level
+   bits 9 - 10 : optimization level
+   bit  11     : -Os
+   bit  12     : -Ofast
+   bit  13     : -Og
+   bit  14     : -Wall.  */
+
+static unsigned int
+compute_GOWall_options (void)
+{
+  unsigned int val, i;
+
+  /* FIXME: Keep in sync with changes to gcc/flag-types.h:enum debug_info_type.  */
+  if (write_symbols > VMS_AND_DWARF2_DEBUG)
+    {
+      annobin_inform (0, "ICE: unknown debug info type %d\n", write_symbols);
+      val = 0;
+    }
+  else
+    val = write_symbols;
+
+  if (use_gnu_debug_info_extensions)
+    val |= (1 << 3);
+
+  if (debug_info_level > DINFO_LEVEL_VERBOSE)
+    annobin_inform (0, "ICE: unknown debug info level %d\n", debug_info_level);
+  else
+    val |= (debug_info_level << 4);
+
+  if (dwarf_version < 0 || dwarf_version > 7)
+    annobin_inform (0, "ICE: unknown dwarf version level %d\n", dwarf_version);
+  else
+    val |= (dwarf_version << 6);
+  
+  if (optimize > 3)
+    val |= (3 << 9);
+  else
+    val |= (optimize << 9);
+
+  /* FIXME: It should not be possible to enable more than one of -Os/-Of/-Og,
+     so the tests below could be simplified.  */
+  if (optimize_size)
+    val |= (1 << 11);
+  if (optimize_fast)
+    val |= (1 << 12);
+  if (optimize_debug)
+    val |= (1 << 13);
+
+  /* Unfortunately -Wall is not recorded by gcc.  So we have to scan the
+     command line...  */
+  for (i = 0; i < save_decoded_options_count; i++)
+    {
+      if (save_decoded_options[i].opt_index == OPT_Wall)
+	{
+	  val |= (1 << 14);
+	  break;
+	}
+    }
+
+  return val;
+}
+
+static void
+record_GOW_settings (unsigned int gow, bool local)
+{
+  char buffer [128];
+  unsigned i;
+
+  (void) sprintf (buffer, "%cGOW", GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC);
+
+  for (i = 5; i < sizeof buffer; i++)
+    {
+      buffer[i] = gow & 0xff;
+      /* Note - The name field in ELF Notes must be NUL terminated, even if,
+	 like here, it is not really being used as a name.  Hence the test
+	 for value being zero is performed here, rather than after the shift.  */
+      if (gow == 0)
+	break;
+      gow >>= 8;
+    }
+
+  if (local)
+    {
+      annobin_inform (1, "Record a change in -g/-O/-Wall status for %s", current_function_name ());
+      annobin_output_note (buffer, i + 1, false, "numeric: -g/-O/-Wall",
+			   current_function_name (), annobin_is_64bit ? 8 : 4, true,
+			   NT_GNU_BUILD_ATTRIBUTE_FUNC);
+    }
+  else
+    {
+      annobin_inform (1, "Record status of -g/-O/-Wall");
+      annobin_output_note (buffer, i + 1, false, "numeric: -g/-O/-Wall",
+			   NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+    }
+}
+
+static void
+annobin_create_function_notes (void * gcc_data, void * user_data)
+{
+  if (! annobin_enable_static_notes)
+    return;
+  
+  annobin_target_specific_function_notes ();
+
+  if (global_stack_prot_option != flag_stack_protect)
+    {
+      annobin_inform (1, "Recording change in stack protection status for %s (from %d to %d)",
+		      current_function_name (), global_stack_prot_option, flag_stack_protect);
+
+      annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, flag_stack_protect,
+				   "numeric: -fstack-protector status",
+				   current_function_name (), NT_GNU_BUILD_ATTRIBUTE_FUNC);
+    }
+
+  if (global_pic_option != compute_pic_option ())
+    {
+      annobin_inform (1, "Recording change in PIC status for %s", current_function_name ());
+      annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, compute_pic_option (),
+				   "numeric: pic type", current_function_name (), 
+				   NT_GNU_BUILD_ATTRIBUTE_FUNC);
+    }
+
+  if (global_GOWall_options != compute_GOWall_options ())
+    record_GOW_settings (compute_GOWall_options (), true);
+
+  if (global_short_enums != flag_short_enums)
+    {
+      annobin_inform (1, "Recording change in enum size for %s", current_function_name ());
+      annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, flag_short_enums,
+				flag_short_enums ? "bool: short-enums: on" : "bool: short-enums: off",
+				current_function_name (), NT_GNU_BUILD_ATTRIBUTE_FUNC);
+    }
+
+  
+  if (annobin_enable_stack_size_notes && flag_stack_usage_info)
+    {
+      if ((unsigned long) current_function_static_stack_size > stack_threshold)
+	{
+	  annobin_inform (1, "Recording stack usage of %lu for %s",
+			  current_function_static_stack_size, current_function_name ());
+
+	  annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_SIZE, current_function_static_stack_size,
+				       "numeric: stack-size", current_function_name (),
+				       NT_GNU_BUILD_ATTRIBUTE_FUNC);
+	}
+
+      annobin_total_static_stack_usage += current_function_static_stack_size;
+
+      if ((unsigned long) current_function_static_stack_size > annobin_max_stack_size)
+	annobin_max_stack_size = current_function_static_stack_size;
+    }
+}
+
+static void
+record_fortify_level (int level)
+{
+  char buffer [128];
+  unsigned len = sprintf (buffer, "%cFORTIFY", GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC);
+
+  buffer[++len] = level;
+  buffer[++len] = 0;
+  annobin_output_note (buffer, len + 1, false, "FORTIFY SOURCE level",
+		       NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+  annobin_inform (1, "Record a FORTIFY SOURCE level of %d", level);
+}
+
+static void
+annobin_create_global_notes (void * gcc_data, void * user_data)
+{
+  int i;
+  char buffer [1024]; /* FIXME: Is this enough ?  */
+
+  if (! annobin_enable_static_notes)
+    return;
+  
+  /* Record global information.
+     Note - we do this here, rather than in plugin_init() as some
+     information, PIC status or POINTER_SIZE, may not be initialised
+     until after the target backend has had a chance to process its
+     command line options, and this happens *after* plugin_init.  */
+
+  /* Compute the default data size.  */
+  switch (POINTER_SIZE)
+    {
+    case 16:
+    case 32:
+      annobin_is_64bit = false; break;
+    case 64:
+      annobin_is_64bit = true; break;
+    default:
+      annobin_inform (0, _("Unknown target pointer size: %d"), POINTER_SIZE);
+    }
+
+  if (annobin_enable_stack_size_notes)
+    /* We must set this flag in order to obtain per-function stack usage info.  */
+    flag_stack_usage_info = 1;
+
+  global_stack_prot_option = flag_stack_protect;
+  global_pic_option = compute_pic_option ();
+  global_short_enums = flag_short_enums;
+  global_GOWall_options = compute_GOWall_options ();
+
+  /* Output a file name symbol to be referenced by the notes...  */
+  if (annobin_current_filename == NULL)
+    init_annobin_current_filename ();
+  if (annobin_current_filename == NULL)
+    {
+      annobin_inform (0, "ICE: Could not find output filename");
+      /* We need a filename, so invent one.  */
+      annobin_current_filename = (char *) "unknown_source";
+    }
+  if (global_file_name_symbols)
+    fprintf (asm_out_file, ".global %s\n", annobin_current_filename);
+  fprintf (asm_out_file, ".type %s STT_OBJECT\n", annobin_current_filename);
+  fprintf (asm_out_file, "%s:\n", annobin_current_filename);
+
+  /* Create the static notes section.  */
+#ifdef OLD_GAS
+  /* GAS prior to version 2.27 did not support setting section flags via a numeric value.  */
+  fprintf (asm_out_file, "\t.pushsection %s, \"\", %%note\n",
+	   GNU_BUILD_ATTRS_SECTION_NAME);
+#else
+  fprintf (asm_out_file, "\t.pushsection %s, \"%#x\", %%note\n",
+	   GNU_BUILD_ATTRS_SECTION_NAME, SHF_GNU_BUILD_NOTE);
+#endif
+  fprintf (asm_out_file, "\t.balign 4\n");
+
+  /* Output the version of the specification supported.  */
+  sprintf (buffer, "%dp%d", SPEC_VERSION, annobin_version);
+  annobin_output_string_note (GNU_BUILD_ATTRIBUTE_VERSION, buffer,
+			      "string: version", annobin_current_filename, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+
+  /* Record the version of the compiler.  */
+  annobin_output_string_note (GNU_BUILD_ATTRIBUTE_TOOL, compiler_version,
+			      "string: build-tool", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+
+  /* Record optimization level, -W setting and -g setting  */
+  record_GOW_settings (global_GOWall_options, false);
+     
+  /* Record -fstack-protector option.  */
+  annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, global_stack_prot_option,
+			       "numeric: -fstack-protector status",
+			       NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+
+  /* Look for -D _FORTIFY_SOURCE=<n> on the original gcc command line.
+     Scan backwards so that we record the last version of the option,
+     should multiple versions be set.  */
+  for (i = save_decoded_options_count; i--;)
+    {
+      if (save_decoded_options[i].opt_index == OPT_D
+	  && save_decoded_options[i].arg != NULL
+	  && strncmp (save_decoded_options[i].arg, "_FORTIFY_SOURCE=", strlen ("_FORTIFY_SOURCE=")) == 0)
+	{
+	  int level = atoi (save_decoded_options[i].arg + strlen ("_FORTIFY_SOURCE="));
+
+	  if (level < 0 || level > 3)
+	    {
+	      annobin_inform (0, "Unexpected value for FORIFY SOURCE: %s",
+			      save_decoded_options[i].arg);
+	      level = 0;
+	    }
+	  record_fortify_level (level);
+	  break;
+	}
+      else if (save_decoded_options[i].opt_index == OPT_fpreprocessed)
+	{
+	  /* Preprocessed sources *might* have had -D_FORTIFY_SOURCE=<n>
+	     applied, but we cannot tell from here.  Well not without a
+	     deep inspection of the preprocessed sources.  So instead we
+	     record a level of -1 to let the user known that we do not know.
+	     Note: preprocessed sources includes the use of --save-temps.  */
+	  record_fortify_level (-1);
+	  break;
+	}
+    }
+  if (i < 0)
+    record_fortify_level (0);
+  
+  /* Record the PIC status.  */
+  annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, global_pic_option,
+			       "numeric: PIC", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+
+  /* Record enum size.  */
+  annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, global_short_enums,
+			    global_short_enums ? "bool: short-enums: on" : "bool: short-enums: off",
+			    NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+
+  /* Record target specific notes.  */
+  annobin_record_global_target_notes ();
+
+  fprintf (asm_out_file, "\t.popsection\n");
+  fflush (asm_out_file);
+}
+
+static void
+annobin_create_loader_notes (void * gcc_data, void * user_data)
+{
+  if (! annobin_enable_dynamic_notes)
+    return;
+
+  if (annobin_enable_stack_size_notes && annobin_total_static_stack_usage)
+    {
+      annobin_inform (1, "Recording total static usage of %ld", annobin_total_static_stack_usage);
+
+      fprintf (asm_out_file, "\t.pushsection %s\n", GNU_BUILD_ATTRS_SECTION_NAME);    
+      annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_SIZE, annobin_total_static_stack_usage,
+				   "numeric: stack-size", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+      fprintf (asm_out_file, "\t.popsection\n");
+    }
+
+  annobin_target_specific_loader_notes ();
+}
+
+static bool
+parse_args (unsigned argc, struct plugin_argument * argv)
+{
+  while (argc--)
+    {
+      char * key = argv[argc].key;
+
+      while (*key == '-')
+	++ key;
+
+      /* These options allow the plugin to be enabled/disabled by a build
+	 system without having to change the option that loads the plugin
+	 itself.  */
+      if (strcmp (key, "disable") == 0)
+	enabled = false;
+
+      else if (strcmp (key, "enable") == 0)
+	enabled = true;
+
+      else if (strcmp (key, "help") == 0)
+	annobin_inform (0, help_string);
+
+      else if (strcmp (key, "version") == 0)
+	annobin_inform (0, version_string);
+
+      else if (strcmp (key, "verbose") == 0)
+	verbose_level ++;
+
+      else if (strcmp (key, "global-file-syms") == 0)
+	global_file_name_symbols = true;
+      else if (strcmp (key, "no-global-file-syms") == 0)
+	global_file_name_symbols = false;
+
+      else if (strcmp (key, "stack-size-notes") == 0)
+	annobin_enable_stack_size_notes = true;
+      else if (strcmp (key, "no-stack-size-notes") == 0)
+	annobin_enable_stack_size_notes = false;
+
+      else if (strcmp (key, "dynamic-notes") == 0)
+	annobin_enable_dynamic_notes = true;
+      else if (strcmp (key, "no-dynamic-notes") == 0)
+	annobin_enable_dynamic_notes = false;
+      
+      else if (strcmp (key, "static-notes") == 0)
+	annobin_enable_static_notes = true;
+      else if (strcmp (key, "no-static-notes") == 0)
+	annobin_enable_static_notes = false;
+      
+      else if (strcmp (key, "stack-threshold") == 0)
+	{
+	  stack_threshold = strtoul (argv[argc].value, NULL, 0);
+	  if (stack_threshold == 0)
+	    stack_threshold = DEFAULT_THRESHOLD;
+	}
+
+      else
+	{
+	  annobin_inform (0, "unrecognised option: %s", argv[argc].key);
+	  return false;
+	}
+    }
+
+  return true;
+}
+
+int
+plugin_init (struct plugin_name_args *   plugin_info,
+             struct plugin_gcc_version * version)
+{
+#if 0
+  if (!plugin_default_version_check (version, & gcc_version))
+    {
+      if (strcmp (version->basever, gcc_version.basever))
+	annobin_inform (0, _("ICE: plugin built for compiler version (%s) but run with compiler version (%s)"),
+		     version->basever, gcc_version.basever);
+      else if (strcmp (version->datestamp, gcc_version.datestamp))
+	annobin_inform (0, _("ICE: plugin datestamp (%s) different from compiler datestamp (%s)"),
+		     version->datestamp, gcc_version.datestamp);
+      else if (strcmp (version->devphase, gcc_version.devphase))
+	annobin_inform (0, _("ICE: plugin built for development phase (%s) not (%s)"),
+		     version->devphase, gcc_version.devphase);
+      else if (strcmp (version->revision, gcc_version.revision))
+	annobin_inform (0, _("ICE: plugin built for compiler revision (%s) not (%s)"),
+		     version->revision, gcc_version.revision);
+      else
+	{
+	  const char * plugin_target;
+	  const char * gcc_target;
+	  const char * plugin_target_end;
+	  const char * gcc_target_end;
+
+	  /* The entire configuration string can be very verbose,
+	     so try to catch the case of compiler and plugin being
+	     built for different targets and tell the user just that.  */
+	  plugin_target = strstr (version->configuration_arguments, "target=");
+	  gcc_target = strstr (gcc_version.configuration_arguments, "target=");
+	  if (plugin_target)
+	    {
+	      plugin_target += 7; /* strlen ("target=") */
+	      plugin_target_end = strchr (plugin_target, ' ');
+	    }
+	  else
+	    {
+	      plugin_target = "native";
+	      plugin_target_end = gcc_target + 6; /* strlen ("native")  */
+	    }
+	  if (gcc_target)
+	    {
+	      gcc_target += 7;
+	      gcc_target_end = strchr (gcc_target, ' ');
+	    }
+	  else
+	    {
+	      gcc_target = "native";
+	      gcc_target_end = gcc_target + 6;
+	    }
+
+	  if (plugin_target_end && gcc_target_end
+	      && strncmp (plugin_target, gcc_target, plugin_target_end - plugin_target))
+	    {
+	      annobin_inform (0, _("ICE: plugin run on a %.*s compiler but built on a %.*s compiler"),
+			   plugin_target_end - plugin_target, plugin_target,
+			   gcc_target_end - gcc_target, gcc_target);
+	    }
+	  else
+	    {
+	      annobin_inform (0, _("ICE: plugin run on a compiler configured as (%s) not (%s)"),
+			   version->configuration_arguments, gcc_version.configuration_arguments);
+	    }
+	}
+      return 1;
+    }
+#endif
+
+  if (! parse_args (plugin_info->argc, plugin_info->argv))
+    {
+      annobin_inform (1, _("failed to parse arguments to plugin"));
+      return 1;
+    }
+
+  if (! enabled)
+    return 0;
+
+  if (! annobin_enable_dynamic_notes && ! annobin_enable_static_notes)
+    {
+      annobin_inform (1, _("nothing to be done"));
+      return 0;
+    }
+
+  /* Record global compiler options.  */
+  compiler_version = (char *) xmalloc (strlen (version->basever) + strlen (version->datestamp) + 6);
+  sprintf (compiler_version, "gcc %s %s", version->basever, version->datestamp);
+
+  annobin_save_target_specific_information ();
+
+#if 0
+  register_callback (plugin_info->base_name,
+		     PLUGIN_INFO,
+		     NULL,
+		     & annobin_info);
+
+  register_callback ("Generate global annotations",
+		     PLUGIN_START_UNIT,
+		     annobin_create_global_notes,
+		     NULL);
+
+  register_callback ("Generate per-function annotations",
+		     PLUGIN_ALL_PASSES_END,
+		     annobin_create_function_notes,
+		     NULL);
+
+  register_callback ("Generate final annotations",
+		     PLUGIN_FINISH_UNIT,
+		     annobin_create_loader_notes,
+		     NULL);
+#endif
+  return 0;
+}
diff --git a/gcc/annobin.h b/gcc/annobin.h
new file mode 100644
index 0000000..5f8bd64
--- /dev/null
+++ b/gcc/annobin.h
@@ -0,0 +1,99 @@
+/* annobin - Header file for the gcc plugin for annotating binary files.
+   Copyright (c) 2017 Red Hat.
+   Created by Nick Clifton.
+
+  This is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  It is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.  */
+
+/* What a mess.  All of this is so that we can include gcc-plugin.h.  */
+
+#include <auto-host.h>
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include <config.h>
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include <gcc-plugin.h>
+
+/* These are necessary so that we can call examine the target's options.  */
+#include <plugin-version.h>
+extern struct plugin_gcc_version gcc_version ATTRIBUTE_UNUSED;
+#include <machmode.h>
+#include <output.h>
+#include <opts.h>
+#include <toplev.h>
+#include <function.h>
+#include <defaults.h>
+
+#include <elf.h>
+
+#if 0 /* This would be the correct thing to do if elf/common.h did not conflict with elf.h.  */
+#include "elf/common.h"
+#else
+#define SHF_GNU_BUILD_NOTE      (1 << 20)	/* Section contains GNU BUILD ATTRIBUTE notes.  */
+#define NT_GNU_PROPERTY_TYPE_0  5		/* Generated by gcc.  */
+
+#define NT_GNU_BUILD_ATTRIBUTE_OPEN	0x100
+#define NT_GNU_BUILD_ATTRIBUTE_FUNC	0x101
+
+#define GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC	'*'
+#define GNU_BUILD_ATTRIBUTE_TYPE_STRING		'$'
+#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE	'+'
+#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE	'!'
+
+#define GNU_BUILD_ATTRIBUTE_VERSION	1
+#define GNU_BUILD_ATTRIBUTE_STACK_PROT	2
+#define GNU_BUILD_ATTRIBUTE_RELRO	3
+#define GNU_BUILD_ATTRIBUTE_STACK_SIZE	4
+#define GNU_BUILD_ATTRIBUTE_TOOL	5
+#define GNU_BUILD_ATTRIBUTE_ABI		6
+#define GNU_BUILD_ATTRIBUTE_PIC		7
+#define GNU_BUILD_ATTRIBUTE_SHORT_ENUM	8
+
+#define NOTE_GNU_PROPERTY_SECTION_NAME	".note.gnu.property"
+#define GNU_BUILD_ATTRS_SECTION_NAME	".gnu.build.attributes"
+
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0).  */
+#define GNU_PROPERTY_STACK_SIZE			1
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED	2
+#endif /* Copy of elf/common.h  */
+
+/* Called during plugin_init().  */
+extern void annobin_save_target_specific_information (void);
+
+/* Called during PLUGIN_START_UNIT.
+   Should only produce notes for the static tools, ie
+   notes in the .gnu.build.attributes section.  */
+extern void annobin_record_global_target_notes (void);
+
+/* Called during PLUGIN_ALL_PASSES_END.
+   Should only produce notes for the static tools, ie
+   notes in the .gnu.build.attributes section.  */
+extern void annobin_target_specific_function_notes (void);
+
+/* Called during PLUGIN_FINISH_UNIT.
+   Should only produce notes for the dynamic loader, ie
+   notes in the .note.gnu.property section.  */
+extern void annobin_target_specific_loader_notes (void);
+
+extern void annobin_inform (unsigned, const char *, ...);
+extern void annobin_output_note (const void *, unsigned, bool, const char *, const void *, unsigned, bool, unsigned);
+extern void annobin_output_bool_note (const char , const bool, const char *, const char *, unsigned);
+extern void annobin_output_string_note (const char, const char *, const char *, const char *, unsigned);
+extern void annobin_output_numeric_note (const char, unsigned long, const char *, const char *, unsigned);
+
+extern bool           annobin_is_64bit;
+extern bool           annobin_enable_stack_size_notes;
+extern unsigned long  annobin_total_static_stack_usage;
+extern unsigned long  annobin_max_stack_size;
diff --git a/gcc/x86_64.annobin.cc b/gcc/x86_64.annobin.cc
new file mode 100644
index 0000000..f9c5b03
--- /dev/null
+++ b/gcc/x86_64.annobin.cc
@@ -0,0 +1,211 @@
+/* x86_64.annobin - x86_64 specific parts of the annobin plugin.
+   Copyright (c) 2017 Red Hat.
+   Created by Nick Clifton.
+
+  This is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  It is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.  */
+
+#include "annobin.h"
+
+#define GNU_PROPERTY_X86_ISA_1_USED		0xc0000000
+#define GNU_PROPERTY_X86_ISA_1_NEEDED		0xc0000001
+
+#define GNU_PROPERTY_X86_ISA_1_486           (1U << 0)
+#define GNU_PROPERTY_X86_ISA_1_586           (1U << 1)
+#define GNU_PROPERTY_X86_ISA_1_686           (1U << 2)
+#define GNU_PROPERTY_X86_ISA_1_SSE           (1U << 3)
+#define GNU_PROPERTY_X86_ISA_1_SSE2          (1U << 4)
+#define GNU_PROPERTY_X86_ISA_1_SSE3          (1U << 5)
+#define GNU_PROPERTY_X86_ISA_1_SSSE3         (1U << 6)
+#define GNU_PROPERTY_X86_ISA_1_SSE4_1        (1U << 7)
+#define GNU_PROPERTY_X86_ISA_1_SSE4_2        (1U << 8)
+#define GNU_PROPERTY_X86_ISA_1_AVX           (1U << 9)
+#define GNU_PROPERTY_X86_ISA_1_AVX2          (1U << 10)
+#define GNU_PROPERTY_X86_ISA_1_AVX512F       (1U << 11)
+#define GNU_PROPERTY_X86_ISA_1_AVX512CD      (1U << 12)
+#define GNU_PROPERTY_X86_ISA_1_AVX512ER      (1U << 13)
+#define GNU_PROPERTY_X86_ISA_1_AVX512PF      (1U << 14)
+#define GNU_PROPERTY_X86_ISA_1_AVX512VL      (1U << 15)
+#define GNU_PROPERTY_X86_ISA_1_AVX512DQ      (1U << 16)
+#define GNU_PROPERTY_X86_ISA_1_AVX512BW      (1U << 17)
+
+
+static unsigned long global_x86_isa = 0;
+static unsigned long min_x86_isa = 0;
+static unsigned long max_x86_isa = 0;
+
+void
+annobin_save_target_specific_information (void)
+{
+}
+
+void
+annobin_record_global_target_notes (void)
+{
+  /* Note - most, but not all, bits in the ix86_isa_flags variable
+     are significant for purposes of ABI compatibility.  We do not
+     bother to filter out any bits however, as we prefer to leave
+     it to the consumer to decide what is significant.  */
+  min_x86_isa = max_x86_isa = global_x86_isa = ix86_isa_flags;
+
+  annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, global_x86_isa,
+			       "numeric: ABI", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+  annobin_inform (1, "Record global isa of %lx", global_x86_isa);
+}
+
+void
+annobin_target_specific_function_notes (void)
+{
+  if ((unsigned long) ix86_isa_flags != global_x86_isa)
+    {
+      annobin_inform (1, "ISA value has changed from %lx to %lx for %s",
+		   global_x86_isa, ix86_isa_flags, current_function_name ());
+
+      annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, ix86_isa_flags,
+				   "numeric: ABI", current_function_name (),
+				   NT_GNU_BUILD_ATTRIBUTE_FUNC);
+
+      if ((unsigned long) ix86_isa_flags < min_x86_isa)
+	min_x86_isa = ix86_isa_flags;
+      if ((unsigned long) ix86_isa_flags > max_x86_isa)
+	max_x86_isa = ix86_isa_flags;
+    }
+}
+
+static unsigned int
+convert_gcc_isa_to_gnu_property_isa (unsigned int isa)
+{
+  unsigned int result = 0;
+
+  if (isa & OPTION_MASK_ISA_SSE)
+    result |= GNU_PROPERTY_X86_ISA_1_SSE;
+  if (isa & OPTION_MASK_ISA_SSE2)
+    result |= GNU_PROPERTY_X86_ISA_1_SSE2;
+  if (isa & OPTION_MASK_ISA_SSE3)
+    result |= GNU_PROPERTY_X86_ISA_1_SSSE3;
+  if (isa & OPTION_MASK_ISA_SSE4_1)
+    result |= GNU_PROPERTY_X86_ISA_1_SSE4_1;
+  if (isa & OPTION_MASK_ISA_SSE4_2)
+    result |= GNU_PROPERTY_X86_ISA_1_SSE4_2;
+  if (isa & OPTION_MASK_ISA_AVX)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX;
+  if (isa & OPTION_MASK_ISA_AVX2)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX2;
+#ifdef OPTION_MASK_ISA_AVX512F
+  if (isa & OPTION_MASK_ISA_AVX512F)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX512F;
+  if (isa & OPTION_MASK_ISA_AVX512CD)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX512CD;
+  if (isa & OPTION_MASK_ISA_AVX512ER)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX512ER;
+  if (isa & OPTION_MASK_ISA_AVX512PF)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX512PF;
+  if (isa & OPTION_MASK_ISA_AVX512VL)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX512VL;
+  if (isa & OPTION_MASK_ISA_AVX512DQ)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX512DQ;
+  if (isa & OPTION_MASK_ISA_AVX512BW)
+    result |= GNU_PROPERTY_X86_ISA_1_AVX512BW;
+#endif
+  return result;
+}
+
+typedef struct
+{
+  Elf32_Word   pr_type;
+  Elf32_Word   pr_datasz;
+  Elf32_Word   pr_data;
+} Elf32_loader_note;
+
+typedef struct
+{
+  Elf32_Word    pr_type;
+  Elf32_Word    pr_datasz;
+  Elf64_Xword   pr_data;
+} Elf64_loader_note;
+
+typedef struct
+{
+  Elf32_Word   pr_type;
+  Elf32_Word   pr_datasz;
+  Elf32_Word   pr_data;
+  Elf32_Word   pr_pad;
+} Elf64_32_loader_note;
+
+void
+annobin_target_specific_loader_notes (void)
+{
+  char   buffer [1024]; /* FIXME: Is this enough ?  */
+  char * ptr;
+
+  annobin_inform (1, "Creating notes for the dynamic loader");
+
+  fprintf (asm_out_file, "\t.pushsection %s, \"a\", %%note\n", NOTE_GNU_PROPERTY_SECTION_NAME);
+  fprintf (asm_out_file, "\t.balign 4\n");
+
+  ptr = buffer;
+
+  if (annobin_is_64bit)
+    {
+      Elf64_32_loader_note note32;
+      
+      note32.pr_datasz = sizeof (note32.pr_data);
+      note32.pr_pad = 0;
+
+      if (annobin_enable_stack_size_notes)
+	{
+	  Elf64_loader_note note64;
+
+	  note64.pr_type   = GNU_PROPERTY_STACK_SIZE;
+	  note64.pr_datasz = sizeof (note64.pr_data);
+	  note64.pr_data   = annobin_max_stack_size;
+	  memcpy (ptr, & note64, sizeof note64);
+	  ptr += sizeof (note64);
+	}
+      
+      note32.pr_type = GNU_PROPERTY_X86_ISA_1_USED;
+      note32.pr_data = convert_gcc_isa_to_gnu_property_isa (max_x86_isa);
+      memcpy (ptr, & note32, sizeof note32);
+      ptr += sizeof (note32);
+
+      note32.pr_type = GNU_PROPERTY_X86_ISA_1_NEEDED;
+      note32.pr_data = convert_gcc_isa_to_gnu_property_isa (min_x86_isa);
+      memcpy (ptr, & note32, sizeof note32);
+      ptr += sizeof (note32);
+    }
+  else
+    {
+      Elf32_loader_note note32;
+
+      note32.pr_datasz = sizeof (note32.pr_data);
+
+      if (annobin_enable_stack_size_notes)
+	{
+	  note32.pr_type = GNU_PROPERTY_STACK_SIZE;
+	  note32.pr_data = annobin_max_stack_size;
+	  memcpy (ptr, & note32, sizeof note32);
+	  ptr += sizeof (note32);
+	}
+
+      note32.pr_type = GNU_PROPERTY_X86_ISA_1_USED;
+      note32.pr_data = convert_gcc_isa_to_gnu_property_isa (max_x86_isa);
+      memcpy (ptr, & note32, sizeof note32);
+      ptr += sizeof (note32);
+
+      note32.pr_type = GNU_PROPERTY_X86_ISA_1_NEEDED;
+      note32.pr_data = convert_gcc_isa_to_gnu_property_isa (min_x86_isa);
+      memcpy (ptr, & note32, sizeof note32);
+      ptr += sizeof (note32);
+    }
+
+  annobin_output_note ("GNU", 4, true, "Loader notes", buffer, ptr - buffer,
+		       false, NT_GNU_PROPERTY_TYPE_0);
+  fflush (asm_out_file);
+}
-- 
1.8.5.3

