This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Generic object attributes patch


In <http://sourceware.org/ml/binutils/2007-06/msg00156.html>, I proposed 
making the ARM EABI object attribute tagging mechanism available on all 
ELF targets, as a means of providing both GNU-specific and ABI-defined 
information about objects, sections or symbols, and merging it on linking, 
without the limitations of the other ad hoc mechanisms such as special 
sections or ELF header flags used on various targets.  There were no 
objections to this proposal and some support for using it for x86 and 
x86_64.

This patch implements making the mechanism generic, with a .gnu.attributes 
section (to go along with other .gnu.* sections) where the target ABI 
doesn't specify another section such as .ARM.attributes, and a "gnu" 
vendor within such a section.  The following principles apply:

* The ARM EABI object attribute syntax is used on all targets.

* Tag values 0-3 and 32 (identifying whether tags apply to a whole file, 
sections, etc., and Tag_compatibility) are considered generic to all 
targets and to both processor and GNU attributes.  (Tag_compatibility is 
of no real significance in a "gnu" section, only in vendor sections; but 
as the only case taking both string and integer arguments it seemed 
simplest for it to be considered generic.)

* Attributes may be in either a target-specific section such as 
.ARM.attributes (preferred if available), or .gnu.attributes (used if no 
target-specific section specified, and accepted in input files even if 
there is a target-specific section).

* The section has a target-specific section type such as 
SHT_ARM_ATTRIBUTES if possible, or SHT_GNU_ATTRIBUTES if no 
target-specific section type is available.

* Within the section, any standard vendor name such as "aeabi" is 
accepted, and "gnu" is accepted for GNU-specific attributes on all 
platforms.

* "gnu" attributes have fixed rules for which take integer or string 
arguments, and which are target-generic or target-specific.  (I have no 
immediate plans for target-generic GNU-specific attributes, but they could 
for example be of use in implementing math_errhandling.)

Specific points on the implementation:

* I left the readelf handling of attributes as target-specific, with the 
expectation that as individual targets get "gnu" attributes it will be 
updated to call that handling for those targets as well, and generic "gnu" 
attributes can be handled in due course as they are created.

* Since armelf.sh put the attributes in OTHER_SECTIONS, when separating it 
out into ATTRS_SECTIONS (so this can default separately for targets 
without their own attributes section) I updated the various elf*.sc 
scripts that used OTHER_SECTIONS.  It's possible that others should be 
updated as well - or that only elf.sc should be updated, and other scripts 
updated when attributes are added for those targets.

I have a patch adding attributes for Power and MIPS targets to distinguish 
hard float and soft float ABIs, which will be submitted separately, with 
an accompanying GCC patch.  The motivation for this is for GDB (see 
<http://sourceware.org/ml/binutils/2007-04/msg00208.html>); I expect we'll 
have a GDB patch to use the attributes in due course, as well as Power 
tagging for vector ABIs (-mabi=altivec, -mabi=spe).

Tested with cross to arm-none-eabi.  OK to commit?

bfd:
2007-06-26  Joseph Myers  <joseph@codesourcery.com>

	* elf-attrs.c: New.
	* Makefile.am (BFD32_BACKENDS): Add elf-attrs.lo.
	(BFD32_BACKENDS_CFILES): Add elf-attrs.c.
	(elf-attrs.lo): Generate dependencies.
	* Makefile.in: Regenerate.
	* configure.in (elf): Add elf-attrs.lo.
	* configure: Regenerate.
	* elf-bfd.h (struct elf_backend_data): Add entries for object
	attributes.
	(NUM_KNOWN_OBJ_ATTRIBUTES, obj_attribute, obj_attribute_list,
	OBJ_ATTR_PROC, OBJ_ATTR_GNU, OBJ_ATTR_FIRST, OBJ_ATTR_LAST,
	Tag_NULL, Tag_File, Tag_Section, Tag_Symbol, Tag_compatibility):
	New.
	(struct elf_obj_tdata): Add entries for object attributes.
	(elf_known_obj_attributes, elf_other_obj_attributes,
	elf_known_obj_attributes_proc, elf_other_obj_attributes_proc):
	New.
	(bfd_elf_obj_attr_size, bfd_elf_set_obj_attr_contents,
	bfd_elf_get_obj_attr_int, bfd_elf_add_obj_attr_int,
	bfd_elf_add_proc_attr_int, bfd_elf_add_obj_attr_string,
	bfd_elf_add_proc_attr_string, bfd_elf_add_obj_attr_compat,
	bfd_elf_add_proc_attr_compat, _bfd_elf_attr_strdup,
	_bfd_elf_copy_obj_attributes, _bfd_elf_obj_attrs_arg_type,
	_bfd_elf_parse_attributes, _bfd_elf_merge_object_attributes): New.
	* elf.c (_bfd_elf_copy_private_bfd_data): Copy object attributes.
	(bfd_section_from_shdr): Handle attributes sections.
	* elflink.c (bfd_elf_final_link): Handle attributes sections.
	* elfxx-target.h (elf_backend_obj_attrs_vendor,
	elf_backend_obj_attrs_section, elf_backend_obj_attrs_arg_type,
	elf_backend_obj_attrs_section_type): New.
	(elfNN_bed): Update.
	* elf32-arm.c (NUM_KNOWN_ATTRIBUTES, aeabi_attribute,
	aeabi_attribute_list): Remove.
	(struct elf32_arm_obj_tdata): Remove object attributes fields.
	(check_use_blx, bfd_elf32_arm_set_vfp11_fix, using_thumb2,
	elf32_arm_copy_private_bfd_data, elf32_arm_merge_eabi_attributes):
	Update for new object attributes interfaces.
	(uleb128_size, is_default_attr, eabi_attr_size,
	elf32_arm_eabi_attr_size, write_uleb128, write_eabi_attribute,
	elf32_arm_set_eabi_attr_contents, elf32_arm_bfd_final_link,
	elf32_arm_new_eabi_attr, elf32_arm_get_eabi_attr_int,
	elf32_arm_add_eabi_attr_int, attr_strdup,
	elf32_arm_add_eabi_attr_string, elf32_arm_add_eabi_attr_compat,
	copy_eabi_attributes, elf32_arm_parse_attributes): Remove.  Moved
	to generic code in elf-attrs.c.
	(elf32_arm_obj_attrs_arg_type): New.
	(elf32_arm_fake_sections): Do not handle .ARM.attributes.
	(elf32_arm_section_from_shdr): Do not handle SHT_ARM_ATTRIBUTES.
	(bfd_elf32_bfd_final_link): Remove.
	(elf_backend_obj_attrs_vendor, elf_backend_obj_attrs_section,
	elf_backend_obj_attrs_arg_type,
	elf_backend_obj_attrs_section_type): New.
	* elf32-bfin.c (bfin_elf_copy_private_bfd_data): Copy object
	attributes.
	* elf32-frv.c (frv_elf_copy_private_bfd_data): Likewise.
	* elf32-iq2000.c (iq2000_elf_copy_private_bfd_data): Likewise.
	* elf32-mep.c (mep_elf_copy_private_bfd_data): Likewise.
	* elf32-mt.c (mt_elf_copy_private_bfd_data): Likewise.
	* elf32-sh.c (sh_elf_copy_private_data): Likewise.
	* elf64-sh64.c (sh_elf64_copy_private_data_internal): Likewise.

binutils:
2007-06-26  Joseph Myers  <joseph@codesourcery.com>

	* readelf.c (display_gnu_attribute): New.
	(process_arm_specific): Rearrange as process_attributes.
	(process_arm_specific): Replace by wrapper of process_attributes.

gas:
2007-06-26  Joseph Myers  <joseph@codesourcery.com>

	* as.c (create_obj_attrs_section): New.
	(main): Call create_obj_attrs_section for ELF.
	* read.c (s_gnu_attribute, skip_whitespace, skip_past_char,
	skip_past_comma, s_vendor_attribute): New.
	(potable): Add gnu_attribute for ELF.
	* read.h (s_vendor_attribute): Declare.
	* config/tc-arm.c (s_arm_eabi_attribute): Replace by wrapper
	round s_vendor_attribute.
	(aeabi_set_public_attributes): Update for new attributes
	interfaces.
	(arm_md_end): Remove attributes contents setting now done
	generically.

include/elf:
2007-06-26  Joseph Myers  <joseph@codesourcery.com>

	* arm.h (elf32_arm_add_eabi_attr_int,
	elf32_arm_add_eabi_attr_string, elf32_arm_add_eabi_attr_compat,
	elf32_arm_get_eabi_attr_int, elf32_arm_set_eabi_attr_contents,
	elf32_arm_eabi_attr_size, Tag_NULL, Tag_File, Tag_Section,
	Tag_Symbol, Tag_compatibility): Remove.
	* common.h (SHT_GNU_ATTRIBUTES): Define.

ld:
2007-06-26  Joseph Myers  <joseph@codesourcery.com>

	* emulparams/armelf.sh (OTHER_SECTIONS): Remove .ARM.attributes.
	(ATTRS_SECTIONS): Define.
	* scripttempl/elf.sc, scripttempl/elf32sh-symbian.sc,
	scripttempl/elf_chaos.sc, scripttempl/elfi370.sc,
	scripttempl/elfxtensa.sc: Handle ATTRS_SECTIONS.

diff -rupN binutils-mainline-fix1/bfd/Makefile.am binutils-mainline-attrgen/bfd/Makefile.am
--- binutils-mainline-fix1/bfd/Makefile.am	2007-06-14 15:30:59.000000000 +0000
+++ binutils-mainline-attrgen/bfd/Makefile.am	2007-06-21 23:06:49.000000000 +0000
@@ -294,6 +294,7 @@ BFD32_BACKENDS = \
 	elf32-xc16x.lo \
 	elf32.lo \
 	elflink.lo \
+	elf-attrs.lo \
 	elf-strtab.lo \
 	elf-eh-frame.lo \
 	elf-vxworks.lo \
@@ -471,6 +472,7 @@ BFD32_BACKENDS_CFILES = \
 	elf32-xc16x.c \
 	elf32.c \
 	elflink.c \
+	elf-attrs.c \
 	elf-strtab.c \
 	elf-eh-frame.c \
 	elf-vxworks.c \
@@ -1548,6 +1550,9 @@ elflink.lo: elflink.c $(INCDIR)/filename
   $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
   $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/safe-ctype.h \
   $(INCDIR)/libiberty.h $(INCDIR)/objalloc.h
+elf-attrs.lo: elf-attrs.c $(INCDIR)/filenames.h $(INCDIR)/libiberty.h \
+  $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
+  $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h
 elf-strtab.lo: elf-strtab.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
   elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
   $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(INCDIR)/libiberty.h
diff -rupN binutils-mainline-fix1/bfd/configure.in binutils-mainline-attrgen/bfd/configure.in
--- binutils-mainline-fix1/bfd/configure.in	2007-04-24 04:05:03.000000000 +0000
+++ binutils-mainline-attrgen/bfd/configure.in	2007-06-21 22:38:36.000000000 +0000
@@ -561,7 +561,7 @@ selarchs="$f"
 # Target backend .o files.
 tb=
 
-elf="elf.lo elflink.lo elf-strtab.lo elf-eh-frame.lo dwarf1.lo"
+elf="elf.lo elflink.lo elf-attrs.lo elf-strtab.lo elf-eh-frame.lo dwarf1.lo"
 
 for vec in $selvecs
 do
diff -rupN binutils-mainline-fix1/bfd/elf-attrs.c binutils-mainline-attrgen/bfd/elf-attrs.c
--- binutils-mainline-fix1/bfd/elf-attrs.c	1970-01-01 00:00:00.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf-attrs.c	2007-06-25 23:04:01.000000000 +0000
@@ -0,0 +1,628 @@
+/* ELF attributes support (based on ARM EABI attributes).
+   Copyright 2005, 2006, 2007
+   Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program 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 2 of the License, or
+   (at your option) any later version.
+
+   This program 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.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libiberty.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+
+/* Return the number of bytes needed by I in uleb128 format.  */
+static int
+uleb128_size (unsigned int i)
+{
+  int size;
+  size = 1;
+  while (i >= 0x80)
+    {
+      i >>= 7;
+      size++;
+    }
+  return size;
+}
+
+/* Return TRUE if the attribute has the default value (0/"").  */
+static bfd_boolean
+is_default_attr (obj_attribute *attr)
+{
+  if ((attr->type & 1) && attr->i != 0)
+    return FALSE;
+  if ((attr->type & 2) && attr->s && *attr->s)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return the size of a single attribute.  */
+static bfd_vma
+obj_attr_size (int tag, obj_attribute *attr)
+{
+  bfd_vma size;
+
+  if (is_default_attr (attr))
+    return 0;
+
+  size = uleb128_size (tag);
+  if (attr->type & 1)
+    size += uleb128_size (attr->i);
+  if (attr->type & 2)
+    size += strlen ((char *)attr->s) + 1;
+  return size;
+}
+
+/* Return the vendor name for a given object attributes section.  */
+static const char *
+vendor_obj_attr_name (bfd *abfd, int vendor)
+{
+  return (vendor == OBJ_ATTR_PROC
+	  ? get_elf_backend_data (abfd)->obj_attrs_vendor
+	  : "gnu");
+}
+
+/* Return the size of the object attributes section for VENDOR
+   (OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes
+   for that vendor to record and the vendor is OBJ_ATTR_GNU.  */
+static bfd_vma
+vendor_obj_attr_size (bfd *abfd, int vendor)
+{
+  bfd_vma size;
+  obj_attribute *attr;
+  obj_attribute_list *list;
+  int i;
+  const char *vendor_name = vendor_obj_attr_name (abfd, vendor);
+
+  if (!vendor_name)
+    return 0;
+
+  attr = elf_known_obj_attributes (abfd)[vendor];
+  size = 0;
+  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+    size += obj_attr_size (i, &attr[i]);
+
+  for (list = elf_other_obj_attributes (abfd)[vendor];
+       list;
+       list = list->next)
+    size += obj_attr_size (list->tag, &list->attr);
+
+  /* <size> <vendor_name> NUL 0x1 <size> */
+  return ((size || vendor == OBJ_ATTR_PROC)
+	  ? size + 10 + strlen (vendor_name)
+	  : 0);
+}
+
+/* Return the size of the object attributes section.  */
+bfd_vma
+bfd_elf_obj_attr_size (bfd *abfd)
+{
+  bfd_vma size;
+
+  size = vendor_obj_attr_size (abfd, OBJ_ATTR_PROC);
+  size += vendor_obj_attr_size (abfd, OBJ_ATTR_GNU);
+
+  /* 'A' <sections for each vendor> */
+  return (size ? size + 1 : 0);
+}
+
+/* Write VAL in uleb128 format to P, returning a pointer to the
+   following byte.  */
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+	c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
+/* Write attribute ATTR to butter P, and return a pointer to the following
+   byte.  */
+static bfd_byte *
+write_obj_attribute (bfd_byte *p, int tag, obj_attribute *attr)
+{
+  /* Suppress default entries.  */
+  if (is_default_attr (attr))
+    return p;
+
+  p = write_uleb128 (p, tag);
+  if (attr->type & 1)
+    p = write_uleb128 (p, attr->i);
+  if (attr->type & 2)
+    {
+      int len;
+
+      len = strlen (attr->s) + 1;
+      memcpy (p, attr->s, len);
+      p += len;
+    }
+
+  return p;
+}
+
+/* Write the contents of the object attributes section (length SIZE)
+   for VENDOR to CONTENTS.  */
+static void
+vendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size,
+			      int vendor)
+{
+  bfd_byte *p;
+  obj_attribute *attr;
+  obj_attribute_list *list;
+  int i;
+  const char *vendor_name = vendor_obj_attr_name (abfd, vendor);
+  size_t vendor_length = strlen (vendor_name) + 1;
+
+  p = contents;
+  bfd_put_32 (abfd, size, p);
+  p += 4;
+  memcpy (p, vendor_name, vendor_length);
+  p += vendor_length;
+  *(p++) = Tag_File;
+  bfd_put_32 (abfd, size - 4 - vendor_length, p);
+  p += 4;
+
+  attr = elf_known_obj_attributes (abfd)[vendor];
+  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+    p = write_obj_attribute (p, i, &attr[i]);
+
+  for (list = elf_other_obj_attributes (abfd)[vendor];
+       list;
+       list = list->next)
+    p = write_obj_attribute (p, list->tag, &list->attr);
+}
+
+/* Write the contents of the object attributes section to CONTENTS.  */
+void
+bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size)
+{
+  bfd_byte *p;
+  int vendor;
+  bfd_vma my_size;
+
+  p = contents;
+  *(p++) = 'A';
+  my_size = 1;
+  for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
+    {
+      bfd_vma vendor_size = vendor_obj_attr_size (abfd, vendor);
+      if (vendor_size)
+	vendor_set_obj_attr_contents (abfd, p, vendor_size, vendor);
+      p += vendor_size;
+      my_size += vendor_size;
+    }
+
+  if (size != my_size)
+    abort ();
+}
+
+/* Allocate/find an object attribute.  */
+static obj_attribute *
+elf_new_obj_attr (bfd *abfd, int vendor, int tag)
+{
+  obj_attribute *attr;
+  obj_attribute_list *list;
+  obj_attribute_list *p;
+  obj_attribute_list **lastp;
+
+
+  if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
+    {
+      /* Knwon tags are preallocated.  */
+      attr = &elf_known_obj_attributes (abfd)[vendor][tag];
+    }
+  else
+    {
+      /* Create a new tag.  */
+      list = (obj_attribute_list *)
+	bfd_alloc (abfd, sizeof (obj_attribute_list));
+      memset (list, 0, sizeof (obj_attribute_list));
+      list->tag = tag;
+      /* Keep the tag list in order.  */
+      lastp = &elf_other_obj_attributes (abfd)[vendor];
+      for (p = *lastp; p; p = p->next)
+	{
+	  if (tag < p->tag)
+	    break;
+	  lastp = &p->next;
+	}
+      list->next = *lastp;
+      *lastp = list;
+      attr = &list->attr;
+    }
+
+  return attr;
+}
+
+/* Return the value of an integer object attribute.  */
+int
+bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag)
+{
+  obj_attribute_list *p;
+
+  if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
+    {
+      /* Knwon tags are preallocated.  */
+      return elf_known_obj_attributes (abfd)[vendor][tag].i;
+    }
+  else
+    {
+      for (p = elf_other_obj_attributes (abfd)[vendor];
+	   p;
+	   p = p->next)
+	{
+	  if (tag == p->tag)
+	    return p->attr.i;
+	  if (tag < p->tag)
+	    break;
+	}
+      return 0;
+    }
+}
+
+/* Add an integer object attribute.  */
+void
+bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, int tag, unsigned int i)
+{
+  obj_attribute *attr;
+
+  attr = elf_new_obj_attr (abfd, vendor, tag);
+  attr->type = 1;
+  attr->i = i;
+}
+
+/* Duplicate an object attribute string value.  */
+char *
+_bfd_elf_attr_strdup (bfd *abfd, const char * s)
+{
+  char * p;
+  int len;
+  
+  len = strlen (s) + 1;
+  p = (char *) bfd_alloc (abfd, len);
+  return memcpy (p, s, len);
+}
+
+/* Add a string object attribute.  */
+void
+bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s)
+{
+  obj_attribute *attr;
+
+  attr = elf_new_obj_attr (abfd, vendor, tag);
+  attr->type = 2;
+  attr->s = _bfd_elf_attr_strdup (abfd, s);
+}
+
+/* Add a Tag_compatibility object attribute.  */
+void
+bfd_elf_add_obj_attr_compat (bfd *abfd, int vendor, unsigned int i,
+			     const char *s)
+{
+  obj_attribute_list *list;
+  obj_attribute_list *p;
+  obj_attribute_list **lastp;
+
+  list = (obj_attribute_list *)
+    bfd_alloc (abfd, sizeof (obj_attribute_list));
+  memset (list, 0, sizeof (obj_attribute_list));
+  list->tag = Tag_compatibility;
+  list->attr.type = 3;
+  list->attr.i = i;
+  list->attr.s = _bfd_elf_attr_strdup (abfd, s);
+
+  lastp = &elf_other_obj_attributes (abfd)[vendor];
+  for (p = *lastp; p; p = p->next)
+    {
+      int cmp;
+      if (p->tag != Tag_compatibility)
+	break;
+      cmp = strcmp(s, p->attr.s);
+      if (cmp < 0 || (cmp == 0 && i < p->attr.i))
+	break;
+      lastp = &p->next;
+    }
+  list->next = *lastp;
+  *lastp = list;
+}
+
+/* Copy the object attributes from IBFD to OBFD.  */
+void
+_bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd)
+{
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  obj_attribute_list *list;
+  int i;
+  int vendor;
+
+  for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
+    {
+      in_attr = &elf_known_obj_attributes (ibfd)[vendor][4];
+      out_attr = &elf_known_obj_attributes (obfd)[vendor][4];
+      for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+	{
+	  out_attr->type = in_attr->type;
+	  out_attr->i = in_attr->i;
+	  if (in_attr->s && *in_attr->s)
+	    out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s);
+	  in_attr++;
+	  out_attr++;
+	}
+
+      for (list = elf_other_obj_attributes (ibfd)[vendor];
+	   list;
+	   list = list->next)
+	{
+	  in_attr = &list->attr;
+	  switch (in_attr->type)
+	    {
+	    case 1:
+	      bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i);
+	      break;
+	    case 2:
+	      bfd_elf_add_obj_attr_string (obfd, vendor, list->tag,
+					   in_attr->s);
+	      break;
+	    case 3:
+	      bfd_elf_add_obj_attr_compat (obfd, vendor, in_attr->i,
+					   in_attr->s);
+	      break;
+	    default:
+	      abort ();
+	    }
+	}
+    }
+}
+
+/* Determine whether a GNU object attribute tag takes an integer, a
+   string or both.  */
+static int
+gnu_obj_attrs_arg_type (int tag)
+{
+  /* Except for Tag_compatibility, for GNU attributes we follow the
+     same rule ARM ones > 32 follow: odd-numbered tags take strings
+     and even-numbered tags take integers.  In addition, tag & 2 is
+     nonzero for architecture-independent tags and zero for
+     architecture-dependent ones.  */
+  if (tag == Tag_compatibility)
+    return 3;
+  else
+    return (tag & 1) != 0 ? 2 : 1;
+}
+
+/* Determine what arguments an attribute tag takes.  */
+int
+_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, int tag)
+{
+  switch (vendor)
+    {
+    case OBJ_ATTR_PROC:
+      return get_elf_backend_data (abfd)->obj_attrs_arg_type (tag);
+      break;
+    case OBJ_ATTR_GNU:
+      return gnu_obj_attrs_arg_type (tag);
+      break;
+    default:
+      abort ();
+    }
+}
+
+/* Parse an object attributes section.  */
+void
+_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
+{
+  bfd_byte *contents;
+  bfd_byte *p;
+  bfd_vma len;
+  const char *std_section;
+
+  contents = bfd_malloc (hdr->sh_size);
+  if (!contents)
+    return;
+  if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
+				 hdr->sh_size))
+    {
+      free (contents);
+      return;
+    }
+  p = contents;
+  std_section = get_elf_backend_data (abfd)->obj_attrs_vendor;
+  if (*(p++) == 'A')
+    {
+      len = hdr->sh_size - 1;
+      while (len > 0)
+	{
+	  int namelen;
+	  bfd_vma section_len;
+	  int vendor;
+
+	  section_len = bfd_get_32 (abfd, p);
+	  p += 4;
+	  if (section_len > len)
+	    section_len = len;
+	  len -= section_len;
+	  namelen = strlen ((char *)p) + 1;
+	  section_len -= namelen + 4;
+	  if (std_section && strcmp ((char *)p, std_section) == 0)
+	    vendor = OBJ_ATTR_PROC;
+	  else if (strcmp ((char *)p, "gnu") == 0)
+	    vendor = OBJ_ATTR_GNU;
+	  else
+	    {
+	      /* Other vendor section.  Ignore it.  */
+	      p += namelen + section_len;
+	      continue;
+	    }
+
+	  p += namelen;
+	  while (section_len > 0)
+	    {
+	      int tag;
+	      unsigned int n;
+	      unsigned int val;
+	      bfd_vma subsection_len;
+	      bfd_byte *end;
+
+	      tag = read_unsigned_leb128 (abfd, p, &n);
+	      p += n;
+	      subsection_len = bfd_get_32 (abfd, p);
+	      p += 4;
+	      if (subsection_len > section_len)
+		subsection_len = section_len;
+	      section_len -= subsection_len;
+	      subsection_len -= n + 4;
+	      end = p + subsection_len;
+	      switch (tag)
+		{
+		case Tag_File:
+		  while (p < end)
+		    {
+		      int type;
+
+		      tag = read_unsigned_leb128 (abfd, p, &n);
+		      p += n;
+		      type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
+		      switch (type)
+			{
+			case 3:
+			  val = read_unsigned_leb128 (abfd, p, &n);
+			  p += n;
+			  bfd_elf_add_obj_attr_compat (abfd, vendor, val,
+						       (char *)p);
+			  p += strlen ((char *)p) + 1;
+			  break;
+			case 2:
+			  bfd_elf_add_obj_attr_string (abfd, vendor, tag,
+						       (char *)p);
+			  p += strlen ((char *)p) + 1;
+			  break;
+			case 1:
+			  val = read_unsigned_leb128 (abfd, p, &n);
+			  p += n;
+			  bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
+			  break;
+			default:
+			  abort ();
+			}
+		    }
+		  break;
+		case Tag_Section:
+		case Tag_Symbol:
+		  /* Don't have anywhere convenient to attach these.
+		     Fall through for now.  */
+		default:
+		  /* Ignore things we don't kow about.  */
+		  p += subsection_len;
+		  subsection_len = 0;
+		  break;
+		}
+	    }
+	}
+    }
+  free (contents);
+}
+
+/* Merge common object attributes from IBFD into OBFD.  Raise an error
+   if there are conflicting attributes.  Any processor-specific
+   attributes have already been merged.  This must be called from the
+   bfd_elfNN_bfd_merge_private_bfd_data hook for each individual
+   target, along with any target-specific merging.  Because there are
+   no common attributes other than Tag_compatibility at present, and
+   non-"gnu" Tag_compatibility is not expected in "gnu" sections, this
+   is not presently called for targets without their own
+   attributes.  */
+
+bfd_boolean
+_bfd_elf_merge_object_attributes (bfd *ibfd, bfd *obfd)
+{
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  obj_attribute_list *in_list;
+  obj_attribute_list *out_list;
+  int vendor;
+
+  /* The only common attribute is currently Tag_compatibility,
+     accepted in both processor and "gnu" sections.  */
+  for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
+    {
+      in_list = elf_other_obj_attributes (ibfd)[vendor];
+      out_list = elf_other_obj_attributes (ibfd)[vendor];
+      while (in_list && in_list->tag == Tag_compatibility)
+	{
+	  in_attr = &in_list->attr;
+	  if (in_attr->i == 0)
+	    continue;
+	  if (in_attr->i == 1 && strcmp (in_attr->s, "gnu") != 0)
+	    {
+	      _bfd_error_handler
+		(_("ERROR: %B: Must be processed by '%s' toolchain"),
+		 ibfd, in_attr->s);
+	      return FALSE;
+	    }
+	  if (!out_list || out_list->tag != Tag_compatibility
+	      || strcmp (in_attr->s, out_list->attr.s) != 0)
+	    {
+	      /* Add this compatibility tag to the output.  */
+	      bfd_elf_add_proc_attr_compat (obfd, in_attr->i, in_attr->s);
+	      continue;
+	    }
+	  out_attr = &out_list->attr;
+	  /* Check all the input tags with the same identifier.  */
+	  for (;;)
+	    {
+	      if (out_list->tag != Tag_compatibility
+		  || in_attr->i != out_attr->i
+		  || strcmp (in_attr->s, out_attr->s) != 0)
+		{
+		  _bfd_error_handler
+		    (_("ERROR: %B: Incompatible object tag '%s':%d"),
+		     ibfd, in_attr->s, in_attr->i);
+		  return FALSE;
+		}
+	      in_list = in_list->next;
+	      if (in_list->tag != Tag_compatibility
+		  || strcmp (in_attr->s, in_list->attr.s) != 0)
+		break;
+	      in_attr = &in_list->attr;
+	      out_list = out_list->next;
+	      if (out_list)
+		out_attr = &out_list->attr;
+	    }
+
+	  /* Check the output doesn't have extra tags with this identifier.  */
+	  if (out_list && out_list->tag == Tag_compatibility
+	      && strcmp (in_attr->s, out_list->attr.s) == 0)
+	    {
+	      _bfd_error_handler
+		(_("ERROR: %B: Incompatible object tag '%s':%d"),
+		 ibfd, in_attr->s, out_list->attr.i);
+	      return FALSE;
+	    }
+	}
+    }
+
+  return TRUE;
+}
diff -rupN binutils-mainline-fix1/bfd/elf-bfd.h binutils-mainline-attrgen/bfd/elf-bfd.h
--- binutils-mainline-fix1/bfd/elf-bfd.h	2007-05-15 13:55:53.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf-bfd.h	2007-06-21 23:06:10.000000000 +0000
@@ -1075,6 +1075,19 @@ struct elf_backend_data
      so-called reserved entries on some systems.  */
   bfd_vma got_header_size;
 
+  /* The vendor name to use for a processor-standard attributes section.  */
+  const char *obj_attrs_vendor;
+
+  /* The section name to use for a processor-standard attributes section.  */
+  const char *obj_attrs_section;
+
+  /* Return 1, 2 or 3 to indicate what type of arguments a
+     processor-specific tag takes.  */
+  int (*obj_attrs_arg_type) (int);
+
+  /* The section type to use for an attributes section.  */
+  unsigned int obj_attrs_section_type;
+
   /* This is TRUE if the linker should act like collect and gather
      global constructors and destructors by name.  This is TRUE for
      MIPS ELF because the Irix 5 tools can not handle the .init
@@ -1268,6 +1281,46 @@ struct elf_find_verdep_info
   bfd_boolean failed;
 };
 
+/* The maximum number of known object attributes for any target.  */
+#define NUM_KNOWN_OBJ_ATTRIBUTES 32
+
+/* The value of an object attribute.  type & 1 indicates whether there
+   is an integer value; type & 2 indicates whether there is a string
+   value.  */
+
+typedef struct obj_attribute
+{
+  int type;
+  unsigned int i;
+  char *s;
+} obj_attribute;
+
+typedef struct obj_attribute_list
+{
+  struct obj_attribute_list *next;
+  int tag;
+  obj_attribute attr;
+} obj_attribute_list;
+
+/* Object attributes may either be defined by the processor ABI, index
+   OBJ_ATTR_PROC in the *_obj_attributes arrays, or be GNU-specific
+   (and possibly also processor-specific), index OBJ_ATTR_GNU.  */
+#define OBJ_ATTR_PROC 0
+#define OBJ_ATTR_GNU 1
+#define OBJ_ATTR_FIRST OBJ_ATTR_PROC
+#define OBJ_ATTR_LAST OBJ_ATTR_GNU
+
+/* The following object attribute tags are taken as generic, for all
+   targets and for "gnu" where there is no target standard.  */
+enum
+{
+  Tag_NULL = 0,
+  Tag_File = 1,
+  Tag_Section = 2,
+  Tag_Symbol = 3,
+  Tag_compatibility = 32
+};
+
 /* Some private data is stashed away for future use using the tdata pointer
    in the bfd structure.  */
 
@@ -1409,6 +1462,9 @@ struct elf_obj_tdata
 
   /* Symbol buffer.  */
   void *symbuf;
+
+  obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
+  obj_attribute_list *other_obj_attributes[2];
 };
 
 #define elf_tdata(bfd)		((bfd) -> tdata.elf_obj_data)
@@ -1438,6 +1494,12 @@ struct elf_obj_tdata
 #define elf_dyn_lib_class(bfd)	(elf_tdata(bfd) -> dyn_lib_class)
 #define elf_bad_symtab(bfd)	(elf_tdata(bfd) -> bad_symtab)
 #define elf_flags_init(bfd)	(elf_tdata(bfd) -> flags_init)
+#define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attributes)
+#define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attributes)
+#define elf_known_obj_attributes_proc(bfd) \
+  (elf_known_obj_attributes (bfd) [OBJ_ATTR_PROC])
+#define elf_other_obj_attributes_proc(bfd) \
+  (elf_other_obj_attributes (bfd) [OBJ_ATTR_PROC])
 
 extern void _bfd_elf_swap_verdef_in
   (bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *);
@@ -1953,6 +2015,26 @@ extern bfd *_bfd_elf64_bfd_from_remote_m
   (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep,
    int (*target_read_memory) (bfd_vma, bfd_byte *, int));
 
+extern bfd_vma bfd_elf_obj_attr_size (bfd *);
+extern void bfd_elf_set_obj_attr_contents (bfd *, bfd_byte *, bfd_vma);
+extern int bfd_elf_get_obj_attr_int (bfd *, int, int);
+extern void bfd_elf_add_obj_attr_int (bfd *, int, int, unsigned int);
+#define bfd_elf_add_proc_attr_int(BFD, TAG, VALUE) \
+  bfd_elf_add_obj_attr_int ((BFD), OBJ_ATTR_PROC, (TAG), (VALUE))
+extern void bfd_elf_add_obj_attr_string (bfd *, int, int, const char *);
+#define bfd_elf_add_proc_attr_string(BFD, TAG, VALUE) \
+  bfd_elf_add_obj_attr_string ((BFD), OBJ_ATTR_PROC, (TAG), (VALUE))
+extern void bfd_elf_add_obj_attr_compat (bfd *, int, unsigned int,
+					 const char *);
+#define bfd_elf_add_proc_attr_compat(BFD, INTVAL, STRVAL) \
+  bfd_elf_add_obj_attr_compat ((BFD), OBJ_ATTR_PROC, (INTVAL), (STRVAL))
+
+extern char *_bfd_elf_attr_strdup (bfd *, const char *);
+extern void _bfd_elf_copy_obj_attributes (bfd *, bfd *);
+extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int);
+extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
+extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
+
 /* Large common section.  */
 extern asection _bfd_elf_large_com_section;
 
diff -rupN binutils-mainline-fix1/bfd/elf.c binutils-mainline-attrgen/bfd/elf.c
--- binutils-mainline-fix1/bfd/elf.c	2007-05-30 14:29:27.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf.c	2007-06-24 18:28:31.000000000 +0000
@@ -1113,6 +1113,10 @@ _bfd_elf_copy_private_bfd_data (bfd *ibf
   elf_gp (obfd) = elf_gp (ibfd);
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = TRUE;
+
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return TRUE;
 }
 
@@ -2195,6 +2199,16 @@ bfd_section_from_shdr (bfd *abfd, unsign
       break;
 
     default:
+      /* Possibly an attributes section.  */
+      if (hdr->sh_type == SHT_GNU_ATTRIBUTES
+	  || hdr->sh_type == bed->obj_attrs_section_type)
+	{
+	  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+	    return FALSE;
+	  _bfd_elf_parse_attributes (abfd, hdr);
+	  return TRUE;
+	}
+
       /* Check for any processor-specific section types.  */
       if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex))
 	return TRUE;
diff -rupN binutils-mainline-fix1/bfd/elf32-arm.c binutils-mainline-attrgen/bfd/elf32-arm.c
--- binutils-mainline-fix1/bfd/elf32-arm.c	2007-06-19 20:25:20.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf32-arm.c	2007-06-21 23:36:36.000000000 +0000
@@ -2064,22 +2064,6 @@ _arm_elf_section_data;
 /* The size of the thread control block.  */
 #define TCB_SIZE	8
 
-#define NUM_KNOWN_ATTRIBUTES 32
-
-typedef struct aeabi_attribute
-{
-  int type;
-  unsigned int i;
-  char *s;
-} aeabi_attribute;
-
-typedef struct aeabi_attribute_list
-{
-  struct aeabi_attribute_list *next;
-  int tag;
-  aeabi_attribute attr;
-} aeabi_attribute_list;
-
 struct elf32_arm_obj_tdata
 {
   struct elf_obj_tdata root;
@@ -2087,9 +2071,6 @@ struct elf32_arm_obj_tdata
   /* tls_type for each local got entry.  */
   char *local_got_tls_type;
 
-  aeabi_attribute known_eabi_attributes[NUM_KNOWN_ATTRIBUTES];
-  aeabi_attribute_list *other_eabi_attributes;
-
   /* Zero to warn when linking objects with incompatible enum sizes.  */
   int no_enum_size_warning;
 };
@@ -3103,7 +3084,8 @@ bfd_elf32_arm_get_bfd_for_interworking (
 
 static void check_use_blx(struct elf32_arm_link_hash_table *globals)
 {
-  if (elf32_arm_get_eabi_attr_int (globals->obfd, Tag_CPU_arch) > 2)
+  if (bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+				Tag_CPU_arch) > 2)
     globals->use_blx = 1;
 }
 
@@ -3320,7 +3302,7 @@ void
 bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
 {
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
-  aeabi_attribute *out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes;
+  obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd);
   
   /* We assume that ARMv7+ does not need the VFP11 denorm erratum fix.  */
   if (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V7)
@@ -4487,7 +4469,8 @@ identify_add_or_sub(bfd_vma insn)
 
 static int using_thumb2 (struct elf32_arm_link_hash_table *globals)
 {
-  int arch = elf32_arm_get_eabi_attr_int (globals->obfd, Tag_CPU_arch);
+  int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+				       Tag_CPU_arch);
   return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7;
 }
 
@@ -6260,194 +6243,6 @@ elf32_arm_final_link_relocate (reloc_how
     }
 }
 
-
-static int
-uleb128_size (unsigned int i)
-{
-  int size;
-  size = 1;
-  while (i >= 0x80)
-    {
-      i >>= 7;
-      size++;
-    }
-  return size;
-}
-
-/* Return TRUE if the attribute has the default value (0/"").  */
-static bfd_boolean
-is_default_attr (aeabi_attribute *attr)
-{
-  if ((attr->type & 1) && attr->i != 0)
-    return FALSE;
-  if ((attr->type & 2) && attr->s && *attr->s)
-    return FALSE;
-
-  return TRUE;
-}
-
-/* Return the size of a single attribute.  */
-static bfd_vma
-eabi_attr_size(int tag, aeabi_attribute *attr)
-{
-  bfd_vma size;
-
-  if (is_default_attr (attr))
-    return 0;
-
-  size = uleb128_size (tag);
-  if (attr->type & 1)
-    size += uleb128_size (attr->i);
-  if (attr->type & 2)
-    size += strlen ((char *)attr->s) + 1;
-  return size;
-}
-  
-/* Returns the size of the eabi object attributess section.  */
-bfd_vma
-elf32_arm_eabi_attr_size (bfd *abfd)
-{
-  bfd_vma size;
-  aeabi_attribute *attr;
-  aeabi_attribute_list *list;
-  int i;
-
-  attr = elf32_arm_tdata (abfd)->known_eabi_attributes;
-  size = 16; /* 'A' <size> "aeabi" 0x1 <size>.  */
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
-    size += eabi_attr_size (i, &attr[i]);
-
-  for (list = elf32_arm_tdata (abfd)->other_eabi_attributes;
-       list;
-       list = list->next)
-    size += eabi_attr_size (list->tag, &list->attr);
-
-  return size;
-}
-
-static bfd_byte *
-write_uleb128 (bfd_byte *p, unsigned int val)
-{
-  bfd_byte c;
-  do
-    {
-      c = val & 0x7f;
-      val >>= 7;
-      if (val)
-	c |= 0x80;
-      *(p++) = c;
-    }
-  while (val);
-  return p;
-}
-
-/* Write attribute ATTR to butter P, and return a pointer to the following
-   byte.  */
-static bfd_byte *
-write_eabi_attribute (bfd_byte *p, int tag, aeabi_attribute *attr)
-{
-  /* Suppress default entries.  */
-  if (is_default_attr(attr))
-    return p;
-
-  p = write_uleb128 (p, tag);
-  if (attr->type & 1)
-    p = write_uleb128 (p, attr->i);
-  if (attr->type & 2)
-    {
-      int len;
-
-      len = strlen (attr->s) + 1;
-      memcpy (p, attr->s, len);
-      p += len;
-    }
-
-  return p;
-}
-
-/* Write the contents of the eabi attributes section to p.  */
-void
-elf32_arm_set_eabi_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size)
-{
-  bfd_byte *p;
-  aeabi_attribute *attr;
-  aeabi_attribute_list *list;
-  int i;
-
-  p = contents;
-  *(p++) = 'A';
-  bfd_put_32 (abfd, size - 1, p);
-  p += 4;
-  memcpy (p, "aeabi", 6);
-  p += 6;
-  *(p++) = Tag_File;
-  bfd_put_32 (abfd, size - 11, p);
-  p += 4;
-
-  attr = elf32_arm_tdata (abfd)->known_eabi_attributes;
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
-    p = write_eabi_attribute (p, i, &attr[i]);
-
-  for (list = elf32_arm_tdata (abfd)->other_eabi_attributes;
-       list;
-       list = list->next)
-    p = write_eabi_attribute (p, list->tag, &list->attr);
-}
-
-/* Override final_link to handle EABI object attribute sections.  */
-
-static bfd_boolean
-elf32_arm_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
-{
-  asection *o;
-  struct bfd_link_order *p;
-  asection *attr_section = NULL;
-  bfd_byte *contents;
-  bfd_vma size = 0;
-
-  /* elf32_arm_merge_private_bfd_data will already have merged the
-     object attributes.  Remove the input sections from the link, and set
-     the contents of the output secton.  */
-  for (o = abfd->sections; o != NULL; o = o->next)
-    {
-      if (strcmp (o->name, ".ARM.attributes") == 0)
-	{
-	  for (p = o->map_head.link_order; p != NULL; p = p->next)
-	    {
-	      asection *input_section;
-
-	      if (p->type != bfd_indirect_link_order)
-		continue;
-	      input_section = p->u.indirect.section;
-	      /* Hack: reset the SEC_HAS_CONTENTS flag so that
-		 elf_link_input_bfd ignores this section.  */
-	      input_section->flags &= ~SEC_HAS_CONTENTS;
-	    }
-	    
-	  size = elf32_arm_eabi_attr_size (abfd);
-	  bfd_set_section_size (abfd, o, size);
-	  attr_section = o;
-	  /* Skip this section later on.  */
-	  o->map_head.link_order = NULL;
-	}
-    }
-  /* Invoke the ELF linker to do all the work.  */
-  if (!bfd_elf_final_link (abfd, info))
-    return FALSE;
-
-  if (attr_section)
-    {
-      contents = bfd_malloc(size);
-      if (contents == NULL)
-	return FALSE;
-      elf32_arm_set_eabi_attr_contents (abfd, contents, size);
-      bfd_set_section_contents (abfd, attr_section, contents, 0, size);
-      free (contents);
-    }
-  return TRUE;
-}
-
-
 /* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
 static void
 arm_add_to_rel (bfd *              abfd,
@@ -6782,130 +6577,6 @@ elf32_arm_relocate_section (bfd *       
   return TRUE;
 }
 
-/* Allocate/find an object attribute.  */
-static aeabi_attribute *
-elf32_arm_new_eabi_attr (bfd *abfd, int tag)
-{
-  aeabi_attribute *attr;
-  aeabi_attribute_list *list;
-  aeabi_attribute_list *p;
-  aeabi_attribute_list **lastp;
-
-
-  if (tag < NUM_KNOWN_ATTRIBUTES)
-    {
-      /* Knwon tags are preallocated.  */
-      attr = &elf32_arm_tdata (abfd)->known_eabi_attributes[tag];
-    }
-  else
-    {
-      /* Create a new tag.  */
-      list = (aeabi_attribute_list *)
-	bfd_alloc (abfd, sizeof (aeabi_attribute_list));
-      memset (list, 0, sizeof (aeabi_attribute_list));
-      list->tag = tag;
-      /* Keep the tag list in order.  */
-      lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes;
-      for (p = *lastp; p; p = p->next)
-	{
-	  if (tag < p->tag)
-	    break;
-	  lastp = &p->next;
-	}
-      list->next = *lastp;
-      *lastp = list;
-      attr = &list->attr;
-    }
-
-  return attr;
-}
-
-int
-elf32_arm_get_eabi_attr_int (bfd *abfd, int tag)
-{
-  aeabi_attribute_list *p;
-
-  if (tag < NUM_KNOWN_ATTRIBUTES)
-    {
-      /* Knwon tags are preallocated.  */
-      return elf32_arm_tdata (abfd)->known_eabi_attributes[tag].i;
-    }
-  else
-    {
-      for (p = elf32_arm_tdata (abfd)->other_eabi_attributes;
-	   p;
-	   p = p->next)
-	{
-	  if (tag == p->tag)
-	    return p->attr.i;
-	  if (tag < p->tag)
-	    break;
-	}
-      return 0;
-    }
-}
-
-void
-elf32_arm_add_eabi_attr_int (bfd *abfd, int tag, unsigned int i)
-{
-  aeabi_attribute *attr;
-
-  attr = elf32_arm_new_eabi_attr (abfd, tag);
-  attr->type = 1;
-  attr->i = i;
-}
-
-static char *
-attr_strdup (bfd *abfd, const char * s)
-{
-  char * p;
-  int len;
-  
-  len = strlen (s) + 1;
-  p = (char *)bfd_alloc(abfd, len);
-  return memcpy (p, s, len);
-}
-
-void
-elf32_arm_add_eabi_attr_string (bfd *abfd, int tag, const char *s)
-{
-  aeabi_attribute *attr;
-
-  attr = elf32_arm_new_eabi_attr (abfd, tag);
-  attr->type = 2;
-  attr->s = attr_strdup (abfd, s);
-}
-
-void
-elf32_arm_add_eabi_attr_compat (bfd *abfd, unsigned int i, const char *s)
-{
-  aeabi_attribute_list *list;
-  aeabi_attribute_list *p;
-  aeabi_attribute_list **lastp;
-
-  list = (aeabi_attribute_list *)
-    bfd_alloc (abfd, sizeof (aeabi_attribute_list));
-  memset (list, 0, sizeof (aeabi_attribute_list));
-  list->tag = Tag_compatibility;
-  list->attr.type = 3;
-  list->attr.i = i;
-  list->attr.s = attr_strdup (abfd, s);
-
-  lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes;
-  for (p = *lastp; p; p = p->next)
-    {
-      int cmp;
-      if (p->tag != Tag_compatibility)
-	break;
-      cmp = strcmp(s, p->attr.s);
-      if (cmp < 0 || (cmp == 0 && i < p->attr.i))
-	break;
-      lastp = &p->next;
-    }
-  list->next = *lastp;
-  *lastp = list;
-}
-
 /* Set the right machine number.  */
 
 static bfd_boolean
@@ -6956,50 +6627,6 @@ elf32_arm_set_private_flags (bfd *abfd, 
   return TRUE;
 }
 
-/* Copy the eabi object attribute from IBFD to OBFD.  */
-static void
-copy_eabi_attributes (bfd *ibfd, bfd *obfd)
-{
-  aeabi_attribute *in_attr;
-  aeabi_attribute *out_attr;
-  aeabi_attribute_list *list;
-  int i;
-
-  in_attr = &elf32_arm_tdata (ibfd)->known_eabi_attributes[4];
-  out_attr = &elf32_arm_tdata (obfd)->known_eabi_attributes[4];
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
-    {
-      out_attr->type = in_attr->type;
-      out_attr->i = in_attr->i;
-      if (in_attr->s && *in_attr->s)
-	out_attr->s = attr_strdup (obfd, in_attr->s);
-      in_attr++;
-      out_attr++;
-    }
-
-  for (list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
-       list;
-       list = list->next)
-    {
-      in_attr = &list->attr;
-      switch (in_attr->type)
-	{
-	case 1:
-	  elf32_arm_add_eabi_attr_int (obfd, list->tag, in_attr->i);
-	  break;
-	case 2:
-	  elf32_arm_add_eabi_attr_string (obfd, list->tag, in_attr->s);
-	  break;
-	case 3:
-	  elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s);
-	  break;
-	default:
-	  abort();
-	}
-    }
-}
-
-
 /* Copy backend specific data from one object module to another.  */
 
 static bfd_boolean
@@ -7051,8 +6678,8 @@ elf32_arm_copy_private_bfd_data (bfd *ib
   elf_elfheader (obfd)->e_ident[EI_OSABI] =
     elf_elfheader (ibfd)->e_ident[EI_OSABI];
 
-  /* Copy EABI object attributes.  */
-  copy_eabi_attributes (ibfd, obfd);
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
 
   return TRUE;
 }
@@ -7084,34 +6711,48 @@ enum
   AEABI_enum_forced_wide
 };
 
+/* Determine whether an object attribute tag takes an integer, a
+   string or both.  */
+static int
+elf32_arm_obj_attrs_arg_type (int tag)
+{
+  if (tag == Tag_compatibility)
+    return 3;
+  else if (tag == 4 || tag == 5)
+    return 2;
+  else if (tag < 32)
+    return 1;
+  else
+    return (tag & 1) != 0 ? 2 : 1;
+}
+
 /* Merge EABI object attributes from IBFD into OBFD.  Raise an error if there
    are conflicting attributes.  */
 static bfd_boolean
 elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
 {
-  aeabi_attribute *in_attr;
-  aeabi_attribute *out_attr;
-  aeabi_attribute_list *in_list;
-  aeabi_attribute_list *out_list;
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  obj_attribute_list *in_list;
   /* Some tags have 0 = don't care, 1 = strong requirement,
      2 = weak requirement.  */
   static const int order_312[3] = {3, 1, 2};
   int i;
 
-  if (!elf32_arm_tdata (obfd)->known_eabi_attributes[0].i)
+  if (!elf_known_obj_attributes_proc (obfd)[0].i)
     {
       /* This is the first object.  Copy the attributes.  */
-      copy_eabi_attributes (ibfd, obfd);
+      _bfd_elf_copy_obj_attributes (ibfd, obfd);
 
       /* Use the Tag_null value to indicate the attributes have been
 	 initialized.  */
-      elf32_arm_tdata (obfd)->known_eabi_attributes[0].i = 1;
+      elf_known_obj_attributes_proc (obfd)[0].i = 1;
 
       return TRUE;
     }
 
-  in_attr = elf32_arm_tdata (ibfd)->known_eabi_attributes;
-  out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes;
+  in_attr = elf_known_obj_attributes_proc (ibfd);
+  out_attr = elf_known_obj_attributes_proc (obfd);
   /* This needs to happen before Tag_ABI_FP_number_model is merged.  */
   if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i)
     {
@@ -7127,7 +6768,7 @@ elf32_arm_merge_eabi_attributes (bfd *ib
 	}
     }
 
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
+  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
     {
       /* Merge this attribute with existing attributes.  */
       switch (i)
@@ -7139,7 +6780,7 @@ elf32_arm_merge_eabi_attributes (bfd *ib
 	     name is non-NULL.  */
 	  if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i
 	      && in_attr[i].s)
-	    out_attr[i].s = attr_strdup(obfd, in_attr[i].s);
+	    out_attr[i].s = _bfd_elf_attr_strdup (obfd, in_attr[i].s);
 	  break;
 
 	case Tag_ABI_optimization_goals:
@@ -7281,60 +6922,13 @@ elf32_arm_merge_eabi_attributes (bfd *ib
 	}
     }
 
-  in_list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
-  out_list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
-  while (in_list && in_list->tag == Tag_compatibility)
-    {
-      in_attr = &in_list->attr;
-      if (in_attr->i == 0)
-	continue;
-      if (in_attr->i == 1)
-	{
-	  _bfd_error_handler
-	    (_("ERROR: %B: Must be processed by '%s' toolchain"),
-	     ibfd, in_attr->s);
-	  return FALSE;
-	}
-      if (!out_list || out_list->tag != Tag_compatibility
-	  || strcmp (in_attr->s, out_list->attr.s) != 0)
-	{
-	  /* Add this compatibility tag to the output.  */
-	  elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s);
-	  continue;
-	}
-      out_attr = &out_list->attr;
-      /* Check all the input tags with the same identifier.  */
-      for (;;)
-	{
-	  if (out_list->tag != Tag_compatibility
-	      || in_attr->i != out_attr->i
-	      || strcmp (in_attr->s, out_attr->s) != 0)
-	    {
-	      _bfd_error_handler
-		(_("ERROR: %B: Incompatible object tag '%s':%d"),
-		 ibfd, in_attr->s, in_attr->i);
-	      return FALSE;
-	    }
-	  in_list = in_list->next;
-	  if (in_list->tag != Tag_compatibility
-	      || strcmp (in_attr->s, in_list->attr.s) != 0)
-	    break;
-	  in_attr = &in_list->attr;
-	  out_list = out_list->next;
-	  if (out_list)
-	    out_attr = &out_list->attr;
-	}
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  _bfd_elf_merge_object_attributes (ibfd, obfd);
 
-      /* Check the output doesn't have extra tags with this identifier.  */
-      if (out_list && out_list->tag == Tag_compatibility
-	  && strcmp (in_attr->s, out_list->attr.s) == 0)
-	{
-	  _bfd_error_handler
-	    (_("ERROR: %B: Incompatible object tag '%s':%d"),
-	     ibfd, in_attr->s, out_list->attr.i);
-	  return FALSE;
-	}
-    }
+  /* Check for any attributes not known on ARM.  */
+  in_list = elf_other_obj_attributes_proc (ibfd);
+  while (in_list && in_list->tag == Tag_compatibility)
+    in_list = in_list->next;
 
   for (; in_list; in_list = in_list->next)
     {
@@ -9787,125 +9381,9 @@ elf32_arm_fake_sections (bfd * abfd, Elf
       hdr->sh_type = SHT_ARM_EXIDX;
       hdr->sh_flags |= SHF_LINK_ORDER;
     }
-  else if (strcmp(name, ".ARM.attributes") == 0)
-    {
-      hdr->sh_type = SHT_ARM_ATTRIBUTES;
-    }
   return TRUE;
 }
 
-/* Parse an Arm EABI attributes section.  */
-static void
-elf32_arm_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
-{
-  bfd_byte *contents;
-  bfd_byte *p;
-  bfd_vma len;
-
-  contents = bfd_malloc (hdr->sh_size);
-  if (!contents)
-    return;
-  if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
-				 hdr->sh_size))
-    {
-      free (contents);
-      return;
-    }
-  p = contents;
-  if (*(p++) == 'A')
-    {
-      len = hdr->sh_size - 1;
-      while (len > 0)
-	{
-	  int namelen;
-	  bfd_vma section_len;
-
-	  section_len = bfd_get_32 (abfd, p);
-	  p += 4;
-	  if (section_len > len)
-	    section_len = len;
-	  len -= section_len;
-	  namelen = strlen ((char *)p) + 1;
-	  section_len -= namelen + 4;
-	  if (strcmp((char *)p, "aeabi") != 0)
-	    {
-	      /* Vendor section.  Ignore it.  */
-	      p += namelen + section_len;
-	    }
-	  else
-	    {
-	      p += namelen;
-	      while (section_len > 0)
-		{
-		  int tag;
-		  unsigned int n;
-		  unsigned int val;
-		  bfd_vma subsection_len;
-		  bfd_byte *end;
-
-		  tag = read_unsigned_leb128 (abfd, p, &n);
-		  p += n;
-		  subsection_len = bfd_get_32 (abfd, p);
-		  p += 4;
-		  if (subsection_len > section_len)
-		    subsection_len = section_len;
-		  section_len -= subsection_len;
-		  subsection_len -= n + 4;
-		  end = p + subsection_len;
-		  switch (tag)
-		    {
-		    case Tag_File:
-		      while (p < end)
-			{
-			  bfd_boolean is_string;
-
-			  tag = read_unsigned_leb128 (abfd, p, &n);
-			  p += n;
-			  if (tag == 4 || tag == 5)
-			    is_string = 1;
-			  else if (tag < 32)
-			    is_string = 0;
-			  else
-			    is_string = (tag & 1) != 0;
-			  if (tag == Tag_compatibility)
-			    {
-			      val = read_unsigned_leb128 (abfd, p, &n);
-			      p += n;
-			      elf32_arm_add_eabi_attr_compat (abfd, val,
-							      (char *)p);
-			      p += strlen ((char *)p) + 1;
-			    }
-			  else if (is_string)
-			    {
-			      elf32_arm_add_eabi_attr_string (abfd, tag,
-							      (char *)p);
-			      p += strlen ((char *)p) + 1;
-			    }
-			  else
-			    {
-			      val = read_unsigned_leb128 (abfd, p, &n);
-			      p += n;
-			      elf32_arm_add_eabi_attr_int (abfd, tag, val);
-			    }
-			}
-		      break;
-		    case Tag_Section:
-		    case Tag_Symbol:
-		      /* Don't have anywhere convenient to attach these.
-		         Fall through for now.  */
-		    default:
-		      /* Ignore things we don't kow about.  */
-		      p += subsection_len;
-		      subsection_len = 0;
-		      break;
-		    }
-		}
-	    }
-	}
-    }
-  free (contents);
-}
-
 /* Handle an ARM specific section when reading an object file.  This is
    called when bfd_section_from_shdr finds a section with an unknown
    type.  */
@@ -9935,8 +9413,6 @@ elf32_arm_section_from_shdr (bfd *abfd,
   if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
     return FALSE;
 
-  if (hdr->sh_type == SHT_ARM_ATTRIBUTES)
-    elf32_arm_parse_attributes(abfd, hdr);
   return TRUE;
 }
 
@@ -10664,7 +10140,6 @@ const struct elf_size_info elf32_arm_siz
 #define bfd_elf32_bfd_is_target_special_symbol	elf32_arm_is_target_special_symbol
 #define bfd_elf32_close_and_cleanup             elf32_arm_close_and_cleanup
 #define bfd_elf32_bfd_free_cached_info          elf32_arm_bfd_free_cached_info
-#define bfd_elf32_bfd_final_link		elf32_arm_bfd_final_link
 
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
 #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
@@ -10709,6 +10184,15 @@ const struct elf_size_info elf32_arm_siz
 
 #define elf_backend_got_header_size	12
 
+#undef elf_backend_obj_attrs_vendor
+#define elf_backend_obj_attrs_vendor	"aeabi"
+#undef elf_backend_obj_attrs_section
+#define elf_backend_obj_attrs_section	".ARM.attributes"
+#undef elf_backend_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type	elf32_arm_obj_attrs_arg_type
+#undef elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type	SHT_ARM_ATTRIBUTES
+
 #include "elf32-target.h"
 
 /* VxWorks Targets */
diff -rupN binutils-mainline-fix1/bfd/elf32-bfin.c binutils-mainline-attrgen/bfd/elf32-bfin.c
--- binutils-mainline-fix1/bfd/elf32-bfin.c	2007-04-26 14:46:56.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf32-bfin.c	2007-06-20 01:02:21.000000000 +0000
@@ -4725,6 +4725,10 @@ bfin_elf_copy_private_bfd_data (bfd *ibf
 
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = TRUE;
+
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return TRUE;
 }
 
diff -rupN binutils-mainline-fix1/bfd/elf32-frv.c binutils-mainline-attrgen/bfd/elf32-frv.c
--- binutils-mainline-fix1/bfd/elf32-frv.c	2007-05-10 05:18:42.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf32-frv.c	2007-06-20 01:03:31.000000000 +0000
@@ -6490,6 +6490,10 @@ frv_elf_copy_private_bfd_data (ibfd, obf
 
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = TRUE;
+
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return TRUE;
 }
 
diff -rupN binutils-mainline-fix1/bfd/elf32-iq2000.c binutils-mainline-attrgen/bfd/elf32-iq2000.c
--- binutils-mainline-fix1/bfd/elf32-iq2000.c	2007-04-26 14:46:56.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf32-iq2000.c	2007-06-20 01:03:42.000000000 +0000
@@ -736,6 +736,10 @@ iq2000_elf_copy_private_bfd_data (bfd *i
 
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = TRUE;
+
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return TRUE;
 }
 
diff -rupN binutils-mainline-fix1/bfd/elf32-mep.c binutils-mainline-attrgen/bfd/elf32-mep.c
--- binutils-mainline-fix1/bfd/elf32-mep.c	2007-04-26 14:46:56.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf32-mep.c	2007-06-20 01:03:50.000000000 +0000
@@ -750,6 +750,10 @@ mep_elf_copy_private_bfd_data (bfd * ibf
 
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = TRUE;
+
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return TRUE;
 }
 
diff -rupN binutils-mainline-fix1/bfd/elf32-mt.c binutils-mainline-attrgen/bfd/elf32-mt.c
--- binutils-mainline-fix1/bfd/elf32-mt.c	2007-04-26 14:46:56.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf32-mt.c	2007-06-20 01:03:59.000000000 +0000
@@ -515,6 +515,10 @@ mt_elf_copy_private_bfd_data (bfd * ibfd
 
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = TRUE;
+
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return TRUE;
 }
 
diff -rupN binutils-mainline-fix1/bfd/elf32-sh.c binutils-mainline-attrgen/bfd/elf32-sh.c
--- binutils-mainline-fix1/bfd/elf32-sh.c	2007-05-15 13:55:53.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf32-sh.c	2007-06-20 01:05:22.000000000 +0000
@@ -5356,6 +5356,9 @@ sh_elf_copy_private_data (bfd * ibfd, bf
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return TRUE;
 
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return sh_elf_set_private_flags (obfd, elf_elfheader (ibfd)->e_flags);
 }
 #endif /* not sh_elf_copy_private_data */
diff -rupN binutils-mainline-fix1/bfd/elf64-sh64.c binutils-mainline-attrgen/bfd/elf64-sh64.c
--- binutils-mainline-fix1/bfd/elf64-sh64.c	2007-05-15 13:55:54.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elf64-sh64.c	2007-06-20 01:05:51.000000000 +0000
@@ -2316,6 +2316,9 @@ sh_elf64_copy_private_data_internal (bfd
 	}
     }
 
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return sh_elf64_set_private_flags (obfd, elf_elfheader (ibfd)->e_flags);
 }
 
diff -rupN binutils-mainline-fix1/bfd/elflink.c binutils-mainline-attrgen/bfd/elflink.c
--- binutils-mainline-fix1/bfd/elflink.c	2007-05-16 12:52:03.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elflink.c	2007-06-21 00:39:52.000000000 +0000
@@ -9266,6 +9266,9 @@ bfd_elf_final_link (bfd *abfd, struct bf
   size_t relativecount = 0;
   asection *reldyn = 0;
   bfd_size_type amt;
+  asection *attr_section = NULL;
+  bfd_vma attr_size = 0;
+  const char *std_attrs_section;
 
   if (! is_elf_hash_table (info->hash))
     return FALSE;
@@ -9313,6 +9316,40 @@ bfd_elf_final_link (bfd *abfd, struct bf
   finfo.symbuf_count = 0;
   finfo.shndxbuf_size = 0;
 
+  /* The object attributes have been merged.  Remove the input
+     sections from the link, and set the contents of the output
+     secton.  */
+  std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section;
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if ((std_attrs_section && strcmp (o->name, std_attrs_section) == 0)
+	  || strcmp (o->name, ".gnu.attributes") == 0)
+	{
+	  for (p = o->map_head.link_order; p != NULL; p = p->next)
+	    {
+	      asection *input_section;
+
+	      if (p->type != bfd_indirect_link_order)
+		continue;
+	      input_section = p->u.indirect.section;
+	      /* Hack: reset the SEC_HAS_CONTENTS flag so that
+		 elf_link_input_bfd ignores this section.  */
+	      input_section->flags &= ~SEC_HAS_CONTENTS;
+	    }
+	    
+	  attr_size = bfd_elf_obj_attr_size (abfd);
+	  if (attr_size)
+	    {
+	      bfd_set_section_size (abfd, o, attr_size);
+	      attr_section = o;
+	      /* Skip this section later on.  */
+	      o->map_head.link_order = NULL;
+	    }
+	  else
+	    o->flags |= SEC_EXCLUDE;
+	}
+    }
+
   /* Count up the number of relocations we will output for each output
      section, so that we know the sizes of the reloc sections.  We
      also figure out some maximum sizes.  */
@@ -10257,6 +10294,16 @@ bfd_elf_final_link (bfd *abfd, struct bf
 
   elf_tdata (abfd)->linker = TRUE;
 
+  if (attr_section)
+    {
+      bfd_byte *contents = bfd_malloc (attr_size);
+      if (contents == NULL)
+	goto error_return;
+      bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
+      bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
+      free (contents);
+    }
+
   return TRUE;
 
  error_return:
diff -rupN binutils-mainline-fix1/bfd/elfxx-target.h binutils-mainline-attrgen/bfd/elfxx-target.h
--- binutils-mainline-fix1/bfd/elfxx-target.h	2007-04-17 20:09:51.000000000 +0000
+++ binutils-mainline-attrgen/bfd/elfxx-target.h	2007-06-21 22:29:03.000000000 +0000
@@ -431,6 +431,18 @@
 #ifndef elf_backend_got_header_size
 #define elf_backend_got_header_size	0
 #endif
+#ifndef elf_backend_obj_attrs_vendor
+#define elf_backend_obj_attrs_vendor		NULL
+#endif
+#ifndef elf_backend_obj_attrs_section
+#define elf_backend_obj_attrs_section		NULL
+#endif
+#ifndef elf_backend_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type		NULL
+#endif
+#ifndef elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type		SHT_GNU_ATTRIBUTES
+#endif
 #ifndef elf_backend_post_process_headers
 #define elf_backend_post_process_headers	NULL
 #endif
@@ -684,6 +696,10 @@ static struct elf_backend_data elfNN_bed
   &elf_backend_size_info,
   elf_backend_special_sections,
   elf_backend_got_header_size,
+  elf_backend_obj_attrs_vendor,
+  elf_backend_obj_attrs_section,
+  elf_backend_obj_attrs_arg_type,
+  elf_backend_obj_attrs_section_type,
   elf_backend_collect,
   elf_backend_type_change_ok,
   elf_backend_may_use_rel_p,
diff -rupN binutils-mainline-fix1/binutils/readelf.c binutils-mainline-attrgen/binutils/readelf.c
--- binutils-mainline-fix1/binutils/readelf.c	2007-05-30 14:29:27.000000000 +0000
+++ binutils-mainline-attrgen/binutils/readelf.c	2007-06-21 23:08:00.000000000 +0000
@@ -8297,8 +8297,61 @@ display_arm_attribute (unsigned char *p)
   return p;
 }
 
+
+static unsigned char *
+display_gnu_attribute (unsigned char *p,
+		       unsigned char *(*display_proc_gnu_attribute)
+			    (unsigned char *, int))
+{
+  int tag;
+  unsigned int len;
+  int val;
+  int type;
+
+  tag = read_uleb128 (p, &len);
+  p += len;
+
+  /* Tag_compatibility is the only generic GNU attribute defined at
+     present.  */
+  if (tag == 32)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("flag = %d, vendor = %s\n", val, p);
+      p += strlen((char *)p) + 1;
+      return p;
+    }
+
+  if ((tag & 2) == 0 && display_proc_gnu_attribute)
+    return display_proc_gnu_attribute (p, tag);
+
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
+
+  if (type == 1)
+    {
+      printf ("\"%s\"\n", p);
+      p += strlen ((char *)p) + 1;
+    }
+  else
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("%d (0x%x)\n", val, val);
+    }
+
+  return p;
+}
+
 static int
-process_arm_specific (FILE *file)
+process_attributes (FILE *file, const char *public_name,
+		    unsigned int proc_type,
+		    unsigned char *(*display_pub_attribute) (unsigned char *),
+		    unsigned char *(*display_proc_gnu_attribute)
+			 (unsigned char *, int))
 {
   Elf_Internal_Shdr *sect;
   unsigned char *contents;
@@ -8313,7 +8366,7 @@ process_arm_specific (FILE *file)
        i < elf_header.e_shnum;
        i++, sect++)
     {
-      if (sect->sh_type != SHT_ARM_ATTRIBUTES)
+      if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES)
 	continue;
 
       contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size,
@@ -8330,6 +8383,7 @@ process_arm_specific (FILE *file)
 	    {
 	      int namelen;
 	      bfd_boolean public_section;
+	      bfd_boolean gnu_section;
 
 	      section_len = byte_get (p, 4);
 	      p += 4;
@@ -8341,10 +8395,14 @@ process_arm_specific (FILE *file)
 		}
 	      len -= section_len;
 	      printf ("Attribute Section: %s\n", p);
-	      if (strcmp ((char *)p, "aeabi") == 0)
+	      if (public_name && strcmp ((char *)p, public_name) == 0)
 		public_section = TRUE;
 	      else
 		public_section = FALSE;
+	      if (strcmp ((char *)p, "gnu") == 0)
+		gnu_section = TRUE;
+	      else
+		gnu_section = FALSE;
 	      namelen = strlen ((char *)p) + 1;
 	      p += namelen;
 	      section_len -= namelen + 4;
@@ -8393,7 +8451,13 @@ process_arm_specific (FILE *file)
 		  if (public_section)
 		    {
 		      while (p < end)
-			p = display_arm_attribute(p);
+			p = display_pub_attribute (p);
+		    }
+		  else if (gnu_section)
+		    {
+		      while (p < end)
+			p = display_gnu_attribute (p,
+						   display_proc_gnu_attribute);
 		    }
 		  else
 		    {
@@ -8415,6 +8479,13 @@ process_arm_specific (FILE *file)
 }
 
 static int
+process_arm_specific (FILE *file)
+{
+  return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES,
+			     display_arm_attribute, NULL);
+}
+
+static int
 process_mips_specific (FILE *file)
 {
   Elf_Internal_Dyn *entry;
diff -rupN binutils-mainline-fix1/gas/as.c binutils-mainline-attrgen/gas/as.c
--- binutils-mainline-fix1/gas/as.c	2007-03-01 15:48:36.000000000 +0000
+++ binutils-mainline-attrgen/gas/as.c	2007-06-24 18:27:34.000000000 +0000
@@ -1031,6 +1031,33 @@ perform_an_assembly_pass (int argc, char
     read_a_source_file ("");
 }
 
+#ifdef OBJ_ELF
+static void
+create_obj_attrs_section (void)
+{
+  segT s;
+  char *p;
+  addressT addr;
+  offsetT size;
+  const char *name;
+
+  size = bfd_elf_obj_attr_size (stdoutput);
+  if (size)
+    {
+      name = get_elf_backend_data (stdoutput)->obj_attrs_section;
+      if (!name)
+	name = ".gnu.attributes";
+      s = subseg_new (name, 0);
+      elf_section_type (s)
+	= get_elf_backend_data (stdoutput)->obj_attrs_section_type;
+      bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
+      addr = frag_now_fix ();
+      p = frag_more (size);
+      bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size);
+    }
+}
+#endif
+
 
 int
 main (int argc, char ** argv)
@@ -1146,6 +1173,10 @@ main (int argc, char ** argv)
   md_end ();
 #endif
 
+#ifdef OBJ_ELF
+  create_obj_attrs_section ();
+#endif
+
 #if defined OBJ_ELF || defined OBJ_MAYBE_ELF
   if ((flag_execstack || flag_noexecstack)
       && OUTPUT_FLAVOR == bfd_target_elf_flavour)
diff -rupN binutils-mainline-fix1/gas/config/tc-arm.c binutils-mainline-attrgen/gas/config/tc-arm.c
--- binutils-mainline-fix1/gas/config/tc-arm.c	2007-06-14 22:06:19.000000000 +0000
+++ binutils-mainline-attrgen/gas/config/tc-arm.c	2007-06-21 16:40:20.000000000 +0000
@@ -3829,84 +3829,7 @@ s_arm_unwind_raw (int ignored ATTRIBUTE_
 static void
 s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
 {
-  expressionS exp;
-  bfd_boolean is_string;
-  int tag;
-  unsigned int i = 0;
-  char *s = NULL;
-  char saved_char;
-
-  expression (& exp);
-  if (exp.X_op != O_constant)
-    goto bad;
-
-  tag = exp.X_add_number;
-  if (tag == 4 || tag == 5 || tag == 32 || (tag > 32 && (tag & 1) != 0))
-    is_string = 1;
-  else
-    is_string = 0;
-
-  if (skip_past_comma (&input_line_pointer) == FAIL)
-    goto bad;
-  if (tag == 32 || !is_string)
-    {
-      expression (& exp);
-      if (exp.X_op != O_constant)
-	{
-	  as_bad (_("expected numeric constant"));
-	  ignore_rest_of_line ();
-	  return;
-	}
-      i = exp.X_add_number;
-    }
-  if (tag == Tag_compatibility
-      && skip_past_comma (&input_line_pointer) == FAIL)
-    {
-      as_bad (_("expected comma"));
-      ignore_rest_of_line ();
-      return;
-    }
-  if (is_string)
-    {
-      skip_whitespace(input_line_pointer);
-      if (*input_line_pointer != '"')
-	goto bad_string;
-      input_line_pointer++;
-      s = input_line_pointer;
-      while (*input_line_pointer && *input_line_pointer != '"')
-	input_line_pointer++;
-      if (*input_line_pointer != '"')
-	goto bad_string;
-      saved_char = *input_line_pointer;
-      *input_line_pointer = 0;
-    }
-  else
-    {
-      s = NULL;
-      saved_char = 0;
-    }
-  
-  if (tag == Tag_compatibility)
-    elf32_arm_add_eabi_attr_compat (stdoutput, i, s);
-  else if (is_string)
-    elf32_arm_add_eabi_attr_string (stdoutput, tag, s);
-  else
-    elf32_arm_add_eabi_attr_int (stdoutput, tag, i);
-
-  if (s)
-    {
-      *input_line_pointer = saved_char;
-      input_line_pointer++;
-    }
-  demand_empty_rest_of_line ();
-  return;
-bad_string:
-  as_bad (_("bad string constant"));
-  ignore_rest_of_line ();
-  return;
-bad:
-  as_bad (_("expected <tag> , <value>"));
-  ignore_rest_of_line ();
+  s_vendor_attribute (OBJ_ATTR_PROC);
 }
 #endif /* OBJ_ELF */
 
@@ -20599,65 +20522,54 @@ aeabi_set_public_attributes (void)
 	  for (i = 0; p[i]; i++)
 	    p[i] = TOUPPER (p[i]);
 	}
-      elf32_arm_add_eabi_attr_string (stdoutput, 5, p);
+      bfd_elf_add_proc_attr_string (stdoutput, 5, p);
     }
   /* Tag_CPU_arch.  */
-  elf32_arm_add_eabi_attr_int (stdoutput, 6, arch);
+  bfd_elf_add_proc_attr_int (stdoutput, 6, arch);
   /* Tag_CPU_arch_profile.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
-    elf32_arm_add_eabi_attr_int (stdoutput, 7, 'A');
+    bfd_elf_add_proc_attr_int (stdoutput, 7, 'A');
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
-    elf32_arm_add_eabi_attr_int (stdoutput, 7, 'R');
+    bfd_elf_add_proc_attr_int (stdoutput, 7, 'R');
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m))
-    elf32_arm_add_eabi_attr_int (stdoutput, 7, 'M');
+    bfd_elf_add_proc_attr_int (stdoutput, 7, 'M');
   /* Tag_ARM_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full))
-    elf32_arm_add_eabi_attr_int (stdoutput, 8, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 8, 1);
   /* Tag_THUMB_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_full))
-    elf32_arm_add_eabi_attr_int (stdoutput, 9,
+    bfd_elf_add_proc_attr_int (stdoutput, 9,
 	ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1);
   /* Tag_VFP_arch.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
       || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3))
-    elf32_arm_add_eabi_attr_int (stdoutput, 10, 3);
+    bfd_elf_add_proc_attr_int (stdoutput, 10, 3);
   else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2)
            || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v2))
-    elf32_arm_add_eabi_attr_int (stdoutput, 10, 2);
+    bfd_elf_add_proc_attr_int (stdoutput, 10, 2);
   else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1)
            || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1)
            || ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1xd)
            || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1xd))
-    elf32_arm_add_eabi_attr_int (stdoutput, 10, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 10, 1);
   /* Tag_WMMX_arch.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_cext_iwmmxt)
       || ARM_CPU_HAS_FEATURE (arm_arch_used, arm_cext_iwmmxt))
-    elf32_arm_add_eabi_attr_int (stdoutput, 11, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 11, 1);
   /* Tag_NEON_arch.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_neon_ext_v1)
       || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_neon_ext_v1))
-    elf32_arm_add_eabi_attr_int (stdoutput, 12, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 12, 1);
 }
 
-/* Add the .ARM.attributes section.  */
+/* Add the default contents for the .ARM.attributes section.  */
 void
 arm_md_end (void)
 {
-  segT s;
-  char *p;
-  addressT addr;
-  offsetT size;
-  
   if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
     return;
 
   aeabi_set_public_attributes ();
-  size = elf32_arm_eabi_attr_size (stdoutput);
-  s = subseg_new (".ARM.attributes", 0);
-  bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
-  addr = frag_now_fix ();
-  p = frag_more (size);
-  elf32_arm_set_eabi_attr_contents (stdoutput, (bfd_byte *)p, size);
 }
 #endif /* OBJ_ELF */
 
diff -rupN binutils-mainline-fix1/gas/read.c binutils-mainline-attrgen/gas/read.c
--- binutils-mainline-fix1/gas/read.c	2007-04-22 05:27:58.000000000 +0000
+++ binutils-mainline-attrgen/gas/read.c	2007-06-21 23:11:32.000000000 +0000
@@ -213,6 +213,9 @@ static void do_align (int, char *, int, 
 static void s_align (int, int);
 static void s_altmacro (int);
 static void s_bad_end (int);
+#ifdef OBJ_ELF
+static void s_gnu_attribute (int);
+#endif
 static void s_reloc (int);
 static int hex_float (int, char *);
 static segT get_known_segmented_expression (expressionS * expP);
@@ -339,6 +342,9 @@ static const pseudo_typeS potable[] = {
   {"func", s_func, 0},
   {"global", s_globl, 0},
   {"globl", s_globl, 0},
+#ifdef OBJ_ELF
+  {"gnu_attribute", s_gnu_attribute, 0},
+#endif
   {"hword", cons, 2},
   {"if", s_if, (int) O_ne},
   {"ifb", s_ifb, 1},
@@ -2033,6 +2039,120 @@ s_globl (int ignore ATTRIBUTE_UNUSED)
     mri_comment_end (stop, stopc);
 }
 
+#ifdef OBJ_ELF
+#define skip_whitespace(str)  do { if (*(str) == ' ') ++(str); } while (0)
+
+static inline int
+skip_past_char (char ** str, char c)
+{
+  if (**str == c)
+    {
+      (*str)++;
+      return 0;
+    }
+  else
+    return -1;
+}
+#define skip_past_comma(str) skip_past_char (str, ',')
+
+/* Parse an attribute directive for VENDOR.  */
+void
+s_vendor_attribute (int vendor)
+{
+  expressionS exp;
+  int type;
+  int tag;
+  unsigned int i = 0;
+  char *s = NULL;
+  char saved_char;
+
+  expression (& exp);
+  if (exp.X_op != O_constant)
+    goto bad;
+
+  tag = exp.X_add_number;
+  type = _bfd_elf_obj_attrs_arg_type (stdoutput, vendor, tag);
+
+  if (skip_past_comma (&input_line_pointer) == -1)
+    goto bad;
+  if (type & 1)
+    {
+      expression (& exp);
+      if (exp.X_op != O_constant)
+	{
+	  as_bad (_("expected numeric constant"));
+	  ignore_rest_of_line ();
+	  return;
+	}
+      i = exp.X_add_number;
+    }
+  if (type == 3
+      && skip_past_comma (&input_line_pointer) == -1)
+    {
+      as_bad (_("expected comma"));
+      ignore_rest_of_line ();
+      return;
+    }
+  if (type & 2)
+    {
+      skip_whitespace(input_line_pointer);
+      if (*input_line_pointer != '"')
+	goto bad_string;
+      input_line_pointer++;
+      s = input_line_pointer;
+      while (*input_line_pointer && *input_line_pointer != '"')
+	input_line_pointer++;
+      if (*input_line_pointer != '"')
+	goto bad_string;
+      saved_char = *input_line_pointer;
+      *input_line_pointer = 0;
+    }
+  else
+    {
+      s = NULL;
+      saved_char = 0;
+    }
+
+  switch (type)
+    {
+    case 3:
+      bfd_elf_add_obj_attr_compat (stdoutput, vendor, i, s);
+      break;
+    case 2:
+      bfd_elf_add_obj_attr_string (stdoutput, vendor, tag, s);
+      break;
+    case 1:
+      bfd_elf_add_obj_attr_int (stdoutput, vendor, tag, i);
+      break;
+    default:
+      abort ();
+    }
+
+  if (s)
+    {
+      *input_line_pointer = saved_char;
+      input_line_pointer++;
+    }
+  demand_empty_rest_of_line ();
+  return;
+bad_string:
+  as_bad (_("bad string constant"));
+  ignore_rest_of_line ();
+  return;
+bad:
+  as_bad (_("expected <tag> , <value>"));
+  ignore_rest_of_line ();
+}
+
+/* Parse a .gnu_attribute directive.  */
+
+static void
+s_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+  s_vendor_attribute (OBJ_ATTR_GNU);
+}
+#endif /* OBJ_ELF */
+
 /* Handle the MRI IRP and IRPC pseudo-ops.  */
 
 void
diff -rupN binutils-mainline-fix1/gas/read.h binutils-mainline-attrgen/gas/read.h
--- binutils-mainline-fix1/gas/read.h	2005-10-24 17:51:41.000000000 +0000
+++ binutils-mainline-attrgen/gas/read.h	2007-06-21 23:11:59.000000000 +0000
@@ -185,4 +185,5 @@ extern void stringer (int append_zero);
 extern void s_xstab (int what);
 extern void s_rva (int);
 extern void s_incbin (int);
+extern void s_vendor_attribute (int);
 extern void s_weakref (int);
diff -rupN binutils-mainline-fix1/include/elf/arm.h binutils-mainline-attrgen/include/elf/arm.h
--- binutils-mainline-fix1/include/elf/arm.h	2006-10-17 15:46:21.000000000 +0000
+++ binutils-mainline-attrgen/include/elf/arm.h	2007-06-20 17:06:16.000000000 +0000
@@ -237,22 +237,12 @@ START_RELOC_NUMBERS (elf_arm_reloc_type)
 END_RELOC_NUMBERS (R_ARM_max)
 
 #ifdef BFD_ARCH_SIZE
-/* Routines for manipulating EABI object attributes.  */
-void elf32_arm_add_eabi_attr_int (bfd *, int, unsigned int);
-void elf32_arm_add_eabi_attr_string (bfd *, int, const char *);
-void elf32_arm_add_eabi_attr_compat (bfd *, unsigned int, const char *);
-int elf32_arm_get_eabi_attr_int (bfd *, int);
-
-void elf32_arm_set_eabi_attr_contents (bfd *, bfd_byte *, bfd_vma);
-bfd_vma elf32_arm_eabi_attr_size (bfd *);
+/* EABI object attributes.  */
 
 enum
 {
-  Tag_NULL,
-  Tag_File,
-  Tag_Section,
-  Tag_Symbol,
-  Tag_CPU_raw_name,
+  /* 0-3 are generic.  */
+  Tag_CPU_raw_name = 4,
   Tag_CPU_name,
   Tag_CPU_arch,
   Tag_CPU_arch_profile,
@@ -280,7 +270,7 @@ enum
   Tag_ABI_WMMX_args,
   Tag_ABI_optimization_goals,
   Tag_ABI_FP_optimization_goals,
-  Tag_compatibility,
+  /* 32 is generic.  */
 };
 
 #endif
diff -rupN binutils-mainline-fix1/include/elf/common.h binutils-mainline-attrgen/include/elf/common.h
--- binutils-mainline-fix1/include/elf/common.h	2007-04-26 06:59:55.000000000 +0000
+++ binutils-mainline-attrgen/include/elf/common.h	2007-06-19 23:43:28.000000000 +0000
@@ -342,6 +342,7 @@
 #define SHT_LOOS	0x60000000	/* First of OS specific semantics */
 #define SHT_HIOS	0x6fffffff	/* Last of OS specific semantics */
 
+#define SHT_GNU_ATTRIBUTES 0x6ffffff5	/* Object attributes */
 #define SHT_GNU_HASH	0x6ffffff6	/* GNU style symbol hash table */
 #define SHT_GNU_LIBLIST	0x6ffffff7	/* List of prelink dependencies */
 
diff -rupN binutils-mainline-fix1/ld/emulparams/armelf.sh binutils-mainline-attrgen/ld/emulparams/armelf.sh
--- binutils-mainline-fix1/ld/emulparams/armelf.sh	2007-01-29 16:28:40.000000000 +0000
+++ binutils-mainline-attrgen/ld/emulparams/armelf.sh	2007-06-21 23:50:59.000000000 +0000
@@ -10,8 +10,8 @@ OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue
 OTHER_BSS_SYMBOLS='__bss_start__ = .;'
 OTHER_BSS_END_SYMBOLS='_bss_end__ = . ; __bss_end__ = . ;'
 OTHER_END_SYMBOLS='__end__ = . ;'
-OTHER_SECTIONS='.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
-  .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }'
+OTHER_SECTIONS='.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }'
+ATTRS_SECTIONS='.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }'
 OTHER_READONLY_SECTIONS="
   .ARM.extab ${RELOCATING-0} : { *(.ARM.extab${RELOCATING+* .gnu.linkonce.armextab.*}) }
   ${RELOCATING+ __exidx_start = .; }
diff -rupN binutils-mainline-fix1/ld/scripttempl/elf.sc binutils-mainline-attrgen/ld/scripttempl/elf.sc
--- binutils-mainline-fix1/ld/scripttempl/elf.sc	2007-05-03 07:06:13.000000000 +0000
+++ binutils-mainline-attrgen/ld/scripttempl/elf.sc	2007-06-21 23:52:46.000000000 +0000
@@ -15,6 +15,7 @@
 #	OTHER_RELRO_SECTIONS - other than .data.rel.ro ...
 #		(e.g. PPC32 .fixup, .got[12])
 #	OTHER_BSS_SECTIONS - other than .bss .sbss ...
+#	ATTRS_SECTIONS - at the end
 #	OTHER_SECTIONS - at the end
 #	EXECUTABLE_SYMBOLS - symbols that must be defined for an
 #		executable (e.g., _DYNAMIC_LINK)
@@ -96,6 +97,7 @@ test -z "${ETEXT_NAME}" && ETEXT_NAME=et
 test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
 test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
 test -n "$RELRO_NOW" && unset SEPARATE_GOTPLT
+test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }"
 DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
 DATA_SEGMENT_RELRO_END=""
 DATA_SEGMENT_END=""
@@ -513,6 +515,7 @@ cat <<EOF
   ${TINY_BSS_SECTION}
 
   ${STACK_ADDR+${STACK}}
+  ${ATTRS_SECTIONS}
   ${OTHER_SECTIONS}
   ${RELOCATING+${OTHER_SYMBOLS}}
   ${RELOCATING+${STACKNOTE}}
diff -rupN binutils-mainline-fix1/ld/scripttempl/elf32sh-symbian.sc binutils-mainline-attrgen/ld/scripttempl/elf32sh-symbian.sc
--- binutils-mainline-fix1/ld/scripttempl/elf32sh-symbian.sc	2006-08-28 01:52:56.000000000 +0000
+++ binutils-mainline-attrgen/ld/scripttempl/elf32sh-symbian.sc	2007-06-21 23:53:06.000000000 +0000
@@ -8,6 +8,7 @@
 #	OTHER_TEXT_SECTIONS - these get put in .text when relocating
 #	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
 #		(e.g., .PARISC.global)
+#	ATTRS_SECTIONS - at the end
 #	OTHER_SECTIONS - at the end
 #	EXECUTABLE_SYMBOLS - symbols that must be defined for an
 #		executable (e.g., _DYNAMIC_LINK)
@@ -71,6 +72,7 @@ test -z "${ALIGNMENT}" && ALIGNMENT="${E
 test "$LD_FLAG" = "N" && DATA_ADDR=.
 test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
 test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
+test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }"
 DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
 DATA_SEGMENT_END=""
 if test -n "${COMMONPAGESIZE}"; then
@@ -375,6 +377,7 @@ cat <<EOF
   .debug_varnames  0 : { *(.debug_varnames) }
 
   ${STACK_ADDR+${STACK}}
+  ${ATTRS_SECTIONS}
   ${OTHER_SECTIONS}
   ${RELOCATING+${OTHER_SYMBOLS}}
   ${RELOCATING+${STACKNOTE}}
diff -rupN binutils-mainline-fix1/ld/scripttempl/elf_chaos.sc binutils-mainline-attrgen/ld/scripttempl/elf_chaos.sc
--- binutils-mainline-fix1/ld/scripttempl/elf_chaos.sc	2006-08-28 01:52:56.000000000 +0000
+++ binutils-mainline-attrgen/ld/scripttempl/elf_chaos.sc	2007-06-21 23:53:20.000000000 +0000
@@ -10,6 +10,7 @@
 #	OTHER_TEXT_SECTIONS - these get put in .text when relocating
 #	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
 #		(e.g., .PARISC.global)
+#	ATTRS_SECTIONS - at the end
 #	OTHER_SECTIONS - at the end
 #	EXECUTABLE_SYMBOLS - symbols that must be defined for an
 #		executable (e.g., _DYNAMIC_LINK)
@@ -68,6 +69,7 @@ test -z "${LITTLE_OUTPUT_FORMAT}" && LIT
 if [ -z "$MACHINE" ]; then OUTPUT_ARCH=${ARCH}; else OUTPUT_ARCH=${ARCH}:${MACHINE}; fi
 test -z "${ELFSIZE}" && ELFSIZE=32
 test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8"
+test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }"
 test "$LD_FLAG" = "N" && DATA_ADDR=.
 INTERP=".interp       ${RELOCATING-0} : { *(.interp) }"
 PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
@@ -349,6 +351,7 @@ cat <<EOF
   .debug_varnames  0 : { *(.debug_varnames) }
 
   ${STACK_ADDR+${STACK}}
+  ${ATTRS_SECTIONS}
   ${OTHER_SECTIONS}
   ${RELOCATING+${OTHER_SYMBOLS}}
 }
diff -rupN binutils-mainline-fix1/ld/scripttempl/elfi370.sc binutils-mainline-attrgen/ld/scripttempl/elfi370.sc
--- binutils-mainline-fix1/ld/scripttempl/elfi370.sc	2001-11-22 09:08:05.000000000 +0000
+++ binutils-mainline-attrgen/ld/scripttempl/elfi370.sc	2007-06-21 23:53:34.000000000 +0000
@@ -8,6 +8,7 @@
 #		(e.g., .PARISC.milli)
 #	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
 #		(e.g., .PARISC.global)
+#	ATTRS_SECTIONS - at the end
 #	OTHER_SECTIONS - at the end
 #	EXECUTABLE_SYMBOLS - symbols that must be defined for an
 #		executable (e.g., _DYNAMIC_LINK)
@@ -24,6 +25,7 @@
 test -z "$ENTRY" && ENTRY=_start
 test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT}
 test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }"
 test "$LD_FLAG" = "N" && DATA_ADDR=.
 SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2) }"
 SDATA2=".sdata2 ${RELOCATING-0} : { *(.sdata2) }"
@@ -212,6 +214,7 @@ SECTIONS
   .debug_typenames 0 : { *(.debug_typenames) }
   .debug_varnames  0 : { *(.debug_varnames) }
 
+  ${ATTRS_SECTIONS}
   ${OTHER_SECTIONS}
 }
 EOF
diff -rupN binutils-mainline-fix1/ld/scripttempl/elfxtensa.sc binutils-mainline-attrgen/ld/scripttempl/elfxtensa.sc
--- binutils-mainline-fix1/ld/scripttempl/elfxtensa.sc	2007-05-03 19:31:03.000000000 +0000
+++ binutils-mainline-attrgen/ld/scripttempl/elfxtensa.sc	2007-06-21 23:53:47.000000000 +0000
@@ -15,6 +15,7 @@
 #	OTHER_RELRO_SECTIONS - other than .data.rel.ro ...
 #		(e.g. PPC32 .fixup, .got[12])
 #	OTHER_BSS_SECTIONS - other than .bss .sbss ...
+#	ATTRS_SECTIONS - at the end
 #	OTHER_SECTIONS - at the end
 #	EXECUTABLE_SYMBOLS - symbols that must be defined for an
 #		executable (e.g., _DYNAMIC_LINK)
@@ -109,6 +110,7 @@ test -z "${ETEXT_NAME}" && ETEXT_NAME=et
 test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
 test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
 test -n "$RELRO_NOW" && unset SEPARATE_GOTPLT
+test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }"
 DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
 DATA_SEGMENT_RELRO_END=""
 DATA_SEGMENT_END=""
@@ -533,6 +535,7 @@ cat <<EOF
   ${TINY_BSS_SECTION}
 
   ${STACK_ADDR+${STACK}}
+  ${ATTRS_SECTIONS}
   ${OTHER_SECTIONS}
   ${RELOCATING+${OTHER_SYMBOLS}}
   ${RELOCATING+${STACKNOTE}}

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]