[v0,02/15] Build attributes: add new abstractions for subsections and attributes

Message ID 20250310175131.1217374-3-matthieu.longo@arm.com
State New
Headers
Series AArch64 AEABI build attributes (a.k.a. object attributes v2) |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

Matthieu Longo March 10, 2025, 5:51 p.m. UTC
  From: Richard Ball <richard.ball@arm.com>

Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
---
 bfd/Makefile.am        |   2 +-
 bfd/Makefile.in        |   2 +-
 bfd/elf-attrs.c        | 209 +++++++++++++++++++++++++++++++++++++++++
 bfd/elf-attrs.h        | 102 ++++++++++++++++++++
 bfd/elf-bfd.h          |  42 ++++++++-
 bfd/elfnn-aarch64.c    |  13 +++
 bfd/elfxx-target.h     |   6 +-
 bfd/po/SRC-POTFILES.in |   1 +
 8 files changed, 372 insertions(+), 5 deletions(-)
 create mode 100644 bfd/elf-attrs.h
  

Comments

Jan Beulich March 11, 2025, 7:58 a.m. UTC | #1
On 10.03.2025 18:51, Matthieu Longo wrote:
> From: Richard Ball <richard.ball@arm.com>
> 
> Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
> ---
>  bfd/Makefile.am        |   2 +-
>  bfd/Makefile.in        |   2 +-
>  bfd/elf-attrs.c        | 209 +++++++++++++++++++++++++++++++++++++++++
>  bfd/elf-attrs.h        | 102 ++++++++++++++++++++
>  bfd/elf-bfd.h          |  42 ++++++++-
>  bfd/elfnn-aarch64.c    |  13 +++
>  bfd/elfxx-target.h     |   6 +-
>  bfd/po/SRC-POTFILES.in |   1 +
>  8 files changed, 372 insertions(+), 5 deletions(-)
>  create mode 100644 bfd/elf-attrs.h

Please can we have a proper description for such newly added functionality?

Jan

> --- a/bfd/Makefile.am
> +++ b/bfd/Makefile.am
> @@ -707,7 +707,7 @@ SOURCE_HFILES = \
>  	elf32-metag.h elf32-nds32.h elf32-ppc.h \
>  	elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
>  	elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
> -	elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
> +	elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
>  	elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
>  	elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
>  	elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
> diff --git a/bfd/Makefile.in b/bfd/Makefile.in
> index 1543af7984a..ecc91d733af 100644
> --- a/bfd/Makefile.in
> +++ b/bfd/Makefile.in
> @@ -1171,7 +1171,7 @@ SOURCE_HFILES = \
>  	elf32-metag.h elf32-nds32.h elf32-ppc.h \
>  	elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
>  	elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
> -	elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
> +	elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
>  	elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
>  	elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
>  	elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
> diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
> index a6a72369afd..634843b5162 100644
> --- a/bfd/elf-attrs.c
> +++ b/bfd/elf-attrs.c
> @@ -20,6 +20,7 @@
>  
>  #include "sysdep.h"
>  #include "bfd.h"
> +#include "double-linked-list.h"
>  #include "libiberty.h"
>  #include "libbfd.h"
>  #include "elf-bfd.h"
> @@ -476,6 +477,19 @@ gnu_obj_attrs_arg_type (unsigned int tag)
>  int
>  _bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag)
>  {
> +  if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
> +    {
> +      BFD_ASSERT (elf_obj_attr_subsections (abfd).last_ != NULL);
> +      switch (elf_obj_attr_subsections (abfd).last_->encoding)
> +	{
> +	case ULEB128:
> +	  return ATTR_TYPE_FLAG_INT_VAL;
> +	case NTBS:
> +	  return ATTR_TYPE_FLAG_STR_VAL;
> +	}
> +    }
> +
> +  /* Version 1.  */
>    switch (vendor)
>      {
>      case OBJ_ATTR_PROC:
> @@ -822,6 +836,201 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
>    return result;
>  }
>  
> +obj_attr_v2 *
> +_bfd_elf_obj_attr_v2_init (unsigned int tag,
> +			   union obj_attr_value_v2 vals)
> +{
> +  obj_attr_v2 *attr = (obj_attr_v2*) malloc (sizeof (obj_attr_v2));
> +  memset ((void *) attr, 0, sizeof (obj_attr_v2));
> +  attr->tag = tag;
> +  attr->vals = vals;
> +  return attr;
> +}
> +
> +void
> +_bfd_elf_obj_attr_v2_free (obj_attr_v2 * attr, obj_attr_encoding_v2 encoding)
> +{
> +  if (encoding == NTBS && attr->vals.string_val != NULL)
> +    free ((void *) attr->vals.string_val);
> +  free (attr);
> +}
> +
> +obj_attr_v2 *
> +_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *other,
> +			   obj_attr_encoding_v2 encoding)
> +{
> +  union obj_attr_value_v2 vals;
> +  if (encoding == NTBS)
> +    vals.string_val =
> +      (other->vals.string_val != NULL)
> +      ? strdup (other->vals.string_val)
> +      : NULL;
> +  else
> +    vals.uint_val = other->vals.uint_val;
> +
> +  obj_attr_v2 *copy =_bfd_elf_obj_attr_v2_init (other->tag, vals);
> +  copy->status = other->status;
> +  return copy;
> +}
> +
> +#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
> +
> +void
> +_bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *s,
> +			   obj_attr_v2 *a1, obj_attr_v2 *a2)
> +{
> +  SWAP (a1->next, a2->next);
> +  SWAP (a1->prev, a2->prev);
> +
> +  if (s->first_ == a1)
> +    s->first_ = a2;
> +  else if (s->first_ == a2)
> +    s->first_ = a1;
> +
> +  if (s->last_ == a1)
> +    s->last_ = a2;
> +  else if (s->last_ == a2)
> +    s->last_ = a1;
> +}
> +
> +int
> +_bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *a1, obj_attr_v2 *a2)
> +{
> +  if (a1->tag < a2->tag)
> +    return -1;
> +  else if (a1->tag > a2->tag)
> +    return 1;
> +  else
> +    return 0;
> +}
> +
> +/* Find the object attribute matching the given tag (object attributes v2 only).
> +   Note: The parameter 'sorted' specifies whether the given list is sorted or
> +   not. If the list of attributes is sorted, the linear search stops as soon as
> +   it finds an attribute with a greater tag.  */
> +obj_attr_v2 *
> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *subsec,
> +			 uint32_t tag,
> +			 bool sorted)
> +{
> +  for (obj_attr_v2 *attr = subsec->first_;
> +       attr != NULL;
> +       attr = attr->next)
> +    if (attr->tag == tag)
> +      return attr;
> +    else if (sorted && attr->tag > tag)
> +      break;
> +  return NULL;
> +}
> +
> +LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_v2, obj_attr_v2, /* public */)
> +LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_v2, obj_attr_v2, /* public */)
> +
> +obj_attr_subsection_v2 *
> +_bfd_elf_obj_attr_subsection_v2_init (const char* name,
> +				      obj_attr_subsection_scope_v2 scope,
> +				      bool optional,
> +				      obj_attr_encoding_v2 encoding)
> +{
> +  obj_attr_subsection_v2* subsection = (obj_attr_subsection_v2*)
> +    malloc (sizeof (obj_attr_subsection_v2));
> +  memset ((void *) subsection, 0, sizeof (obj_attr_subsection_v2));
> +  subsection->name = name;
> +  subsection->scope = scope;
> +  subsection->optional = optional;
> +  subsection->encoding = encoding;
> +  return subsection;
> +}
> +
> +void
> +_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *subsec)
> +{
> +  for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
> +    _bfd_elf_obj_attr_v2_free (attr, subsec->encoding);
> +  free (subsec);
> +}
> +
> +obj_attr_subsection_v2 *
> +_bfd_elf_obj_attr_subsection_v2_copy (obj_attr_subsection_v2 const *other)
> +{
> +  obj_attr_subsection_v2* new_subsec =
> +    _bfd_elf_obj_attr_subsection_v2_init (other->name, other->scope,
> +					  other->optional, other->encoding);
> +  for (obj_attr_v2* attr = other->first_;
> +       attr != NULL;
> +       attr = attr->next)
> +    {
> +      obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
> +      LINKED_LIST_APPEND(obj_attr_v2) (new_subsec, new_attr);
> +    }
> +  return new_subsec;
> +}
> +
> +void
> +_bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *plist,
> +				      obj_attr_subsection_v2 *s1,
> +				      obj_attr_subsection_v2 *s2)
> +{
> +  SWAP (s1->next, s2->next);
> +  SWAP (s1->prev, s2->prev);
> +
> +  if (plist->first_ == s1)
> +    plist->first_ = s2;
> +  else if (plist->first_ == s2)
> +    plist->first_ = s1;
> +
> +  if (plist->last_ == s1)
> +    plist->last_ = s2;
> +  else if (plist->last_ == s2)
> +    plist->last_ = s1;
> +}
> +
> +int
> +_bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *s1,
> +				     obj_attr_subsection_v2 *s2)
> +{
> +  int res = strcmp (s1->name, s2->name);
> +  if (res != 0)
> +    return res;
> +
> +  if (s1->optional < s2->optional)
> +    return -1;
> +  else if (s1->optional > s2->optional)
> +    return 1;
> +
> +  if (s1->encoding < s2->encoding)
> +    return -1;
> +  if (s1->encoding > s2->encoding)
> +    return 1;
> +  else
> +    return 0;
> +}
> +
> +/* Find the subsection matching the given name.
> +   Note: The parameter sorted specified whether the given list is sorted or not.
> +   If the list of subsections is sorted, the linear search stops as soon as it
> +   finds a subsection name with a greater order.  */
> +obj_attr_subsection_v2 *
> +obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2 *first,
> +				     const char *name,
> +				     bool sorted)
> +{
> +  for (obj_attr_subsection_v2 *s = first;
> +       s != NULL;
> +       s = s->next)
> +    {
> +      int cmp = strcmp (s->name, name);
> +      if (cmp == 0)
> +	return s;
> +      else if (sorted && cmp > 0)
> +	break;
> +    }
> +  return NULL;
> +}
> +
> +LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
> +LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
> +
>  bool _bfd_elf_write_section_build_attributes (bfd *abfd,
>  					      struct bfd_link_info *info ATTRIBUTE_UNUSED)
>  {
> diff --git a/bfd/elf-attrs.h b/bfd/elf-attrs.h
> new file mode 100644
> index 00000000000..5d41bb98538
> --- /dev/null
> +++ b/bfd/elf-attrs.h
> @@ -0,0 +1,102 @@
> +/* ELF attributes support (based on ARM EABI attributes).
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +   Written by Cygnus Support.
> +
> +   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 3 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.  */
> +
> +#pragma once
> +
> +#include <stdint.h>
> +
> +/* --------------------
> +   Object attributes v2
> +   -------------------- */
> +
> +typedef enum obj_attr_encoding_v2
> +{
> +  ULEB128 = 0,
> +  NTBS    = 1,
> +} obj_attr_encoding_v2;
> +
> +typedef union obj_attr_value_v2 {
> +  uint32_t uint_val;
> +  const char* string_val;
> +} obj_attr_value_v2;
> +
> +typedef struct obj_attr_v2 {
> +  /* The name/tag of an attribute.  */
> +  uint32_t tag;
> +
> +  /* The value assigned to an attribute, can be ULEB128 or NTBS.  */
> +  union obj_attr_value_v2 vals;
> +
> +  /* The next attribute in the list or NULL.  */
> +  struct obj_attr_v2 *next;
> +
> +  /* The previous attribute in the list or NULL.  */
> +  struct obj_attr_v2 *prev;
> +
> +} obj_attr_v2;
> +
> +typedef enum obj_attr_subsection_scope_v2
> +{
> +  SUBSEC_PUBLIC = 0,
> +  SUBSEC_PRIVATE = 1,
> +} obj_attr_subsection_scope_v2;
> +
> +typedef struct obj_attr_subsection_v2 {
> +  /* The name of the subsection.  */
> +  const char *name;
> +
> +  /* The scope of the subsection.  */
> +  obj_attr_subsection_scope_v2 scope;
> +
> +  /* Is this subsection optional ? Can it be skipped ?  */
> +  bool optional;
> +
> +  /* The value encoding of attributes in this subsection.  */
> +  obj_attr_encoding_v2 encoding;
> +
> +  /* The next subsection in the list, or NULL.  */
> +  struct obj_attr_subsection_v2 *next;
> +
> +  /* The previous subsection in the list, or NULL.  */
> +  struct obj_attr_subsection_v2 *prev;
> +
> +  /* A pointer to the first node of the list.  */
> +  struct obj_attr_v2* first_;
> +
> +  /* A pointer to the last node of the list.  */
> +  struct obj_attr_v2* last_;
> +
> +  /* The size of the list.  */
> +  uint32_t size;
> +
> +} obj_attr_subsection_v2;
> +
> +typedef struct obj_attr_subsection_list
> +{
> +  /* A pointer to the first node of the list.  */
> +  obj_attr_subsection_v2 *first_;
> +
> +  /* A pointer to the last node of the list.  */
> +  obj_attr_subsection_v2 *last_;
> +
> +  /* The size of the list.  */
> +  uint64_t size;
> +} obj_attr_subsection_list;
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 5903d857faa..6c326d5db72 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -24,9 +24,11 @@
>  
>  #include <stdlib.h>
>  
> +#include "double-linked-list.h"
>  #include "elf/common.h"
>  #include "elf/external.h"
>  #include "elf/internal.h"
> +#include "elf-attrs.h"
>  #include "bfdlink.h"
>  
>  #ifndef ENABLE_CHECKING
> @@ -1630,13 +1632,15 @@ struct elf_backend_data
>    /* 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.  */
> +  /* Return 1, 2 or 3 to indicate what type of arguments a tag takes.  */
>    int (*obj_attrs_arg_type) (int);
>  
>    /* The section type to use for an attributes section.  */
>    unsigned int obj_attrs_section_type;
>  
> +  /* The version of object attributes (1 or 2).  */
> +  unsigned int obj_attrs_version;
> +
>    /* This function determines the order in which any attributes are
>       written.  It must be defined for input in the range
>       LEAST_KNOWN_OBJ_ATTRIBUTE..NUM_KNOWN_OBJ_ATTRIBUTES-1 (this range
> @@ -2160,6 +2164,11 @@ struct elf_obj_tdata
>    obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
>    obj_attribute_list *other_obj_attributes[2];
>  
> +  /* Object attributes v2: attributes of the same category are stored inside
> +     the same subsection. A subsection can only hold attributes with the same
> +     data type.  */
> +  obj_attr_subsection_list obj_attr_subsections;
> +
>    /* Linked-list containing information about every Systemtap section
>       found in the object file.  Each section corresponds to one entry
>       in the list.  */
> @@ -2253,6 +2262,7 @@ struct elf_obj_tdata
>    (elf_known_obj_attributes (bfd) [OBJ_ATTR_PROC])
>  #define elf_other_obj_attributes_proc(bfd) \
>    (elf_other_obj_attributes (bfd) [OBJ_ATTR_PROC])
> +#define elf_obj_attr_subsections(bfd) (elf_tdata (bfd) -> obj_attr_subsections)
>  #define elf_properties(bfd) (elf_tdata (bfd) -> properties)
>  #define elf_has_no_copy_on_protected(bfd) \
>    (elf_tdata(bfd) -> has_no_copy_on_protected)
> @@ -3083,6 +3093,34 @@ extern bool _bfd_elf_merge_unknown_attribute_list (bfd *, bfd *);
>  extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr (asection *sec);
>  extern bool elf_read_notes (bfd *, file_ptr, bfd_size_type, size_t);
>  
> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_init (unsigned int,
> +  union obj_attr_value_v2);
> +extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2 *, obj_attr_encoding_v2);
> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *,
> +  obj_attr_encoding_v2);
> +extern void _bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *,
> +  obj_attr_v2 *, obj_attr_v2 *);
> +extern int _bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *, obj_attr_v2 *);
> +extern obj_attr_v2 *
> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *, uint32_t, bool);
> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_v2, extern);
> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_init (const char*,
> +  obj_attr_subsection_scope_v2, bool, obj_attr_encoding_v2);
> +extern void _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *);
> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_copy
> +  (obj_attr_subsection_v2 const*);
> +extern void _bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *,
> +  obj_attr_subsection_v2 *, obj_attr_subsection_v2 *);
> +extern int _bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *,
> +  obj_attr_subsection_v2 *s2);
> +extern obj_attr_subsection_v2 * obj_attr_subsection_v2_find_by_name
> +  (obj_attr_subsection_v2 *, const char *, bool);
> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, extern);
> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
> +
>  extern bool _bfd_elf_parse_gnu_properties
>    (bfd *, Elf_Internal_Note *);
>  extern elf_property_list * _bfd_elf_find_property
> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
> index 548da1f8b30..21fc99c4c98 100644
> --- a/bfd/elfnn-aarch64.c
> +++ b/bfd/elfnn-aarch64.c
> @@ -10760,8 +10760,21 @@ const struct elf_size_info elfNN_aarch64_size_info =
>  #define elf_backend_extern_protected_data 0
>  #define elf_backend_hash_symbol elf_aarch64_hash_symbol
>  
> +/* elf_backend_obj_attrs_vendor is unused for AArch64. It is replaced by the
> +   concept of subsections, each one having its own name defined by the
> +   assembly directive "aeabi_subsection".  */
> +#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		SEC_AARCH64_ATTRIBUTES
> +/* elf_backend_obj_attrs_arg_type is unused as the type of an attribute is
> +   determined by looking up at the current subsection, not the value of the
> +   tag.  */
> +#define elf_backend_obj_attrs_arg_type		NULL
> +#undef	elf_backend_obj_attrs_section_type
> +#define elf_backend_obj_attrs_section_type	SHT_AARCH64_ATTRIBUTES
> +#undef	elf_backend_obj_attrs_version
> +#define elf_backend_obj_attrs_version		2
>  
>  #include "elfNN-target.h"
>  
> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
> index 625243cac94..cff508dbbce 100644
> --- a/bfd/elfxx-target.h
> +++ b/bfd/elfxx-target.h
> @@ -556,6 +556,9 @@
>  #ifndef elf_backend_obj_attrs_section_type
>  #define elf_backend_obj_attrs_section_type		SHT_GNU_ATTRIBUTES
>  #endif
> +#ifndef elf_backend_obj_attrs_version
> +#define elf_backend_obj_attrs_version		1 /* Default version.  */
> +#endif
>  #ifndef elf_backend_obj_attrs_order
>  #define elf_backend_obj_attrs_order		NULL
>  #endif
> @@ -808,7 +811,7 @@
>  #ifndef elf_backend_symbol_section_index
>  #define elf_backend_symbol_section_index NULL
>  #endif
> - 
> +
>  #ifndef elf_match_priority
>  #define elf_match_priority \
>    (ELF_ARCH == bfd_arch_unknown ? 2 : ELF_OSABI == ELFOSABI_NONE ? 1 : 0)
> @@ -934,6 +937,7 @@ static const struct elf_backend_data elfNN_bed =
>    elf_backend_obj_attrs_section,
>    elf_backend_obj_attrs_arg_type,
>    elf_backend_obj_attrs_section_type,
> +  elf_backend_obj_attrs_version,
>    elf_backend_obj_attrs_order,
>    elf_backend_obj_attrs_handle_unknown,
>    elf_backend_parse_gnu_properties,
> diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in
> index 54b078b8295..4b8ccfbe2c8 100644
> --- a/bfd/po/SRC-POTFILES.in
> +++ b/bfd/po/SRC-POTFILES.in
> @@ -132,6 +132,7 @@ ecoff.c
>  ecofflink.c
>  ecoffswap.h
>  elf-attrs.c
> +elf-attrs.h
>  elf-bfd.h
>  elf-eh-frame.c
>  elf-hppa.h
  
Matthieu Longo March 20, 2025, 2:06 p.m. UTC | #2
On 2025-03-11 07:58, Jan Beulich wrote:
> On 10.03.2025 18:51, Matthieu Longo wrote:
>> From: Richard Ball <richard.ball@arm.com>
>>
>> Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
>> ---
>>   bfd/Makefile.am        |   2 +-
>>   bfd/Makefile.in        |   2 +-
>>   bfd/elf-attrs.c        | 209 +++++++++++++++++++++++++++++++++++++++++
>>   bfd/elf-attrs.h        | 102 ++++++++++++++++++++
>>   bfd/elf-bfd.h          |  42 ++++++++-
>>   bfd/elfnn-aarch64.c    |  13 +++
>>   bfd/elfxx-target.h     |   6 +-
>>   bfd/po/SRC-POTFILES.in |   1 +
>>   8 files changed, 372 insertions(+), 5 deletions(-)
>>   create mode 100644 bfd/elf-attrs.h
> 
> Please can we have a proper description for such newly added functionality?
> 
> Jan
> 

I apologize for this. The next revision will have hopefully a useful 
description in all the commits.

Matthieu

>> --- a/bfd/Makefile.am
>> +++ b/bfd/Makefile.am
>> @@ -707,7 +707,7 @@ SOURCE_HFILES = \
>>   	elf32-metag.h elf32-nds32.h elf32-ppc.h \
>>   	elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
>>   	elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
>> -	elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
>> +	elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
>>   	elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
>>   	elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
>>   	elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
>> diff --git a/bfd/Makefile.in b/bfd/Makefile.in
>> index 1543af7984a..ecc91d733af 100644
>> --- a/bfd/Makefile.in
>> +++ b/bfd/Makefile.in
>> @@ -1171,7 +1171,7 @@ SOURCE_HFILES = \
>>   	elf32-metag.h elf32-nds32.h elf32-ppc.h \
>>   	elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
>>   	elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
>> -	elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
>> +	elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
>>   	elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
>>   	elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
>>   	elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
>> diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
>> index a6a72369afd..634843b5162 100644
>> --- a/bfd/elf-attrs.c
>> +++ b/bfd/elf-attrs.c
>> @@ -20,6 +20,7 @@
>>   
>>   #include "sysdep.h"
>>   #include "bfd.h"
>> +#include "double-linked-list.h"
>>   #include "libiberty.h"
>>   #include "libbfd.h"
>>   #include "elf-bfd.h"
>> @@ -476,6 +477,19 @@ gnu_obj_attrs_arg_type (unsigned int tag)
>>   int
>>   _bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag)
>>   {
>> +  if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
>> +    {
>> +      BFD_ASSERT (elf_obj_attr_subsections (abfd).last_ != NULL);
>> +      switch (elf_obj_attr_subsections (abfd).last_->encoding)
>> +	{
>> +	case ULEB128:
>> +	  return ATTR_TYPE_FLAG_INT_VAL;
>> +	case NTBS:
>> +	  return ATTR_TYPE_FLAG_STR_VAL;
>> +	}
>> +    }
>> +
>> +  /* Version 1.  */
>>     switch (vendor)
>>       {
>>       case OBJ_ATTR_PROC:
>> @@ -822,6 +836,201 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
>>     return result;
>>   }
>>   
>> +obj_attr_v2 *
>> +_bfd_elf_obj_attr_v2_init (unsigned int tag,
>> +			   union obj_attr_value_v2 vals)
>> +{
>> +  obj_attr_v2 *attr = (obj_attr_v2*) malloc (sizeof (obj_attr_v2));
>> +  memset ((void *) attr, 0, sizeof (obj_attr_v2));
>> +  attr->tag = tag;
>> +  attr->vals = vals;
>> +  return attr;
>> +}
>> +
>> +void
>> +_bfd_elf_obj_attr_v2_free (obj_attr_v2 * attr, obj_attr_encoding_v2 encoding)
>> +{
>> +  if (encoding == NTBS && attr->vals.string_val != NULL)
>> +    free ((void *) attr->vals.string_val);
>> +  free (attr);
>> +}
>> +
>> +obj_attr_v2 *
>> +_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *other,
>> +			   obj_attr_encoding_v2 encoding)
>> +{
>> +  union obj_attr_value_v2 vals;
>> +  if (encoding == NTBS)
>> +    vals.string_val =
>> +      (other->vals.string_val != NULL)
>> +      ? strdup (other->vals.string_val)
>> +      : NULL;
>> +  else
>> +    vals.uint_val = other->vals.uint_val;
>> +
>> +  obj_attr_v2 *copy =_bfd_elf_obj_attr_v2_init (other->tag, vals);
>> +  copy->status = other->status;
>> +  return copy;
>> +}
>> +
>> +#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
>> +
>> +void
>> +_bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *s,
>> +			   obj_attr_v2 *a1, obj_attr_v2 *a2)
>> +{
>> +  SWAP (a1->next, a2->next);
>> +  SWAP (a1->prev, a2->prev);
>> +
>> +  if (s->first_ == a1)
>> +    s->first_ = a2;
>> +  else if (s->first_ == a2)
>> +    s->first_ = a1;
>> +
>> +  if (s->last_ == a1)
>> +    s->last_ = a2;
>> +  else if (s->last_ == a2)
>> +    s->last_ = a1;
>> +}
>> +
>> +int
>> +_bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *a1, obj_attr_v2 *a2)
>> +{
>> +  if (a1->tag < a2->tag)
>> +    return -1;
>> +  else if (a1->tag > a2->tag)
>> +    return 1;
>> +  else
>> +    return 0;
>> +}
>> +
>> +/* Find the object attribute matching the given tag (object attributes v2 only).
>> +   Note: The parameter 'sorted' specifies whether the given list is sorted or
>> +   not. If the list of attributes is sorted, the linear search stops as soon as
>> +   it finds an attribute with a greater tag.  */
>> +obj_attr_v2 *
>> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *subsec,
>> +			 uint32_t tag,
>> +			 bool sorted)
>> +{
>> +  for (obj_attr_v2 *attr = subsec->first_;
>> +       attr != NULL;
>> +       attr = attr->next)
>> +    if (attr->tag == tag)
>> +      return attr;
>> +    else if (sorted && attr->tag > tag)
>> +      break;
>> +  return NULL;
>> +}
>> +
>> +LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_v2, obj_attr_v2, /* public */)
>> +LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_v2, obj_attr_v2, /* public */)
>> +
>> +obj_attr_subsection_v2 *
>> +_bfd_elf_obj_attr_subsection_v2_init (const char* name,
>> +				      obj_attr_subsection_scope_v2 scope,
>> +				      bool optional,
>> +				      obj_attr_encoding_v2 encoding)
>> +{
>> +  obj_attr_subsection_v2* subsection = (obj_attr_subsection_v2*)
>> +    malloc (sizeof (obj_attr_subsection_v2));
>> +  memset ((void *) subsection, 0, sizeof (obj_attr_subsection_v2));
>> +  subsection->name = name;
>> +  subsection->scope = scope;
>> +  subsection->optional = optional;
>> +  subsection->encoding = encoding;
>> +  return subsection;
>> +}
>> +
>> +void
>> +_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *subsec)
>> +{
>> +  for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
>> +    _bfd_elf_obj_attr_v2_free (attr, subsec->encoding);
>> +  free (subsec);
>> +}
>> +
>> +obj_attr_subsection_v2 *
>> +_bfd_elf_obj_attr_subsection_v2_copy (obj_attr_subsection_v2 const *other)
>> +{
>> +  obj_attr_subsection_v2* new_subsec =
>> +    _bfd_elf_obj_attr_subsection_v2_init (other->name, other->scope,
>> +					  other->optional, other->encoding);
>> +  for (obj_attr_v2* attr = other->first_;
>> +       attr != NULL;
>> +       attr = attr->next)
>> +    {
>> +      obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
>> +      LINKED_LIST_APPEND(obj_attr_v2) (new_subsec, new_attr);
>> +    }
>> +  return new_subsec;
>> +}
>> +
>> +void
>> +_bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *plist,
>> +				      obj_attr_subsection_v2 *s1,
>> +				      obj_attr_subsection_v2 *s2)
>> +{
>> +  SWAP (s1->next, s2->next);
>> +  SWAP (s1->prev, s2->prev);
>> +
>> +  if (plist->first_ == s1)
>> +    plist->first_ = s2;
>> +  else if (plist->first_ == s2)
>> +    plist->first_ = s1;
>> +
>> +  if (plist->last_ == s1)
>> +    plist->last_ = s2;
>> +  else if (plist->last_ == s2)
>> +    plist->last_ = s1;
>> +}
>> +
>> +int
>> +_bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *s1,
>> +				     obj_attr_subsection_v2 *s2)
>> +{
>> +  int res = strcmp (s1->name, s2->name);
>> +  if (res != 0)
>> +    return res;
>> +
>> +  if (s1->optional < s2->optional)
>> +    return -1;
>> +  else if (s1->optional > s2->optional)
>> +    return 1;
>> +
>> +  if (s1->encoding < s2->encoding)
>> +    return -1;
>> +  if (s1->encoding > s2->encoding)
>> +    return 1;
>> +  else
>> +    return 0;
>> +}
>> +
>> +/* Find the subsection matching the given name.
>> +   Note: The parameter sorted specified whether the given list is sorted or not.
>> +   If the list of subsections is sorted, the linear search stops as soon as it
>> +   finds a subsection name with a greater order.  */
>> +obj_attr_subsection_v2 *
>> +obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2 *first,
>> +				     const char *name,
>> +				     bool sorted)
>> +{
>> +  for (obj_attr_subsection_v2 *s = first;
>> +       s != NULL;
>> +       s = s->next)
>> +    {
>> +      int cmp = strcmp (s->name, name);
>> +      if (cmp == 0)
>> +	return s;
>> +      else if (sorted && cmp > 0)
>> +	break;
>> +    }
>> +  return NULL;
>> +}
>> +
>> +LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
>> +LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
>> +
>>   bool _bfd_elf_write_section_build_attributes (bfd *abfd,
>>   					      struct bfd_link_info *info ATTRIBUTE_UNUSED)
>>   {
>> diff --git a/bfd/elf-attrs.h b/bfd/elf-attrs.h
>> new file mode 100644
>> index 00000000000..5d41bb98538
>> --- /dev/null
>> +++ b/bfd/elf-attrs.h
>> @@ -0,0 +1,102 @@
>> +/* ELF attributes support (based on ARM EABI attributes).
>> +   Copyright (C) 2025 Free Software Foundation, Inc.
>> +   Written by Cygnus Support.
>> +
>> +   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 3 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.  */
>> +
>> +#pragma once
>> +
>> +#include <stdint.h>
>> +
>> +/* --------------------
>> +   Object attributes v2
>> +   -------------------- */
>> +
>> +typedef enum obj_attr_encoding_v2
>> +{
>> +  ULEB128 = 0,
>> +  NTBS    = 1,
>> +} obj_attr_encoding_v2;
>> +
>> +typedef union obj_attr_value_v2 {
>> +  uint32_t uint_val;
>> +  const char* string_val;
>> +} obj_attr_value_v2;
>> +
>> +typedef struct obj_attr_v2 {
>> +  /* The name/tag of an attribute.  */
>> +  uint32_t tag;
>> +
>> +  /* The value assigned to an attribute, can be ULEB128 or NTBS.  */
>> +  union obj_attr_value_v2 vals;
>> +
>> +  /* The next attribute in the list or NULL.  */
>> +  struct obj_attr_v2 *next;
>> +
>> +  /* The previous attribute in the list or NULL.  */
>> +  struct obj_attr_v2 *prev;
>> +
>> +} obj_attr_v2;
>> +
>> +typedef enum obj_attr_subsection_scope_v2
>> +{
>> +  SUBSEC_PUBLIC = 0,
>> +  SUBSEC_PRIVATE = 1,
>> +} obj_attr_subsection_scope_v2;
>> +
>> +typedef struct obj_attr_subsection_v2 {
>> +  /* The name of the subsection.  */
>> +  const char *name;
>> +
>> +  /* The scope of the subsection.  */
>> +  obj_attr_subsection_scope_v2 scope;
>> +
>> +  /* Is this subsection optional ? Can it be skipped ?  */
>> +  bool optional;
>> +
>> +  /* The value encoding of attributes in this subsection.  */
>> +  obj_attr_encoding_v2 encoding;
>> +
>> +  /* The next subsection in the list, or NULL.  */
>> +  struct obj_attr_subsection_v2 *next;
>> +
>> +  /* The previous subsection in the list, or NULL.  */
>> +  struct obj_attr_subsection_v2 *prev;
>> +
>> +  /* A pointer to the first node of the list.  */
>> +  struct obj_attr_v2* first_;
>> +
>> +  /* A pointer to the last node of the list.  */
>> +  struct obj_attr_v2* last_;
>> +
>> +  /* The size of the list.  */
>> +  uint32_t size;
>> +
>> +} obj_attr_subsection_v2;
>> +
>> +typedef struct obj_attr_subsection_list
>> +{
>> +  /* A pointer to the first node of the list.  */
>> +  obj_attr_subsection_v2 *first_;
>> +
>> +  /* A pointer to the last node of the list.  */
>> +  obj_attr_subsection_v2 *last_;
>> +
>> +  /* The size of the list.  */
>> +  uint64_t size;
>> +} obj_attr_subsection_list;
>> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
>> index 5903d857faa..6c326d5db72 100644
>> --- a/bfd/elf-bfd.h
>> +++ b/bfd/elf-bfd.h
>> @@ -24,9 +24,11 @@
>>   
>>   #include <stdlib.h>
>>   
>> +#include "double-linked-list.h"
>>   #include "elf/common.h"
>>   #include "elf/external.h"
>>   #include "elf/internal.h"
>> +#include "elf-attrs.h"
>>   #include "bfdlink.h"
>>   
>>   #ifndef ENABLE_CHECKING
>> @@ -1630,13 +1632,15 @@ struct elf_backend_data
>>     /* 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.  */
>> +  /* Return 1, 2 or 3 to indicate what type of arguments a tag takes.  */
>>     int (*obj_attrs_arg_type) (int);
>>   
>>     /* The section type to use for an attributes section.  */
>>     unsigned int obj_attrs_section_type;
>>   
>> +  /* The version of object attributes (1 or 2).  */
>> +  unsigned int obj_attrs_version;
>> +
>>     /* This function determines the order in which any attributes are
>>        written.  It must be defined for input in the range
>>        LEAST_KNOWN_OBJ_ATTRIBUTE..NUM_KNOWN_OBJ_ATTRIBUTES-1 (this range
>> @@ -2160,6 +2164,11 @@ struct elf_obj_tdata
>>     obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
>>     obj_attribute_list *other_obj_attributes[2];
>>   
>> +  /* Object attributes v2: attributes of the same category are stored inside
>> +     the same subsection. A subsection can only hold attributes with the same
>> +     data type.  */
>> +  obj_attr_subsection_list obj_attr_subsections;
>> +
>>     /* Linked-list containing information about every Systemtap section
>>        found in the object file.  Each section corresponds to one entry
>>        in the list.  */
>> @@ -2253,6 +2262,7 @@ struct elf_obj_tdata
>>     (elf_known_obj_attributes (bfd) [OBJ_ATTR_PROC])
>>   #define elf_other_obj_attributes_proc(bfd) \
>>     (elf_other_obj_attributes (bfd) [OBJ_ATTR_PROC])
>> +#define elf_obj_attr_subsections(bfd) (elf_tdata (bfd) -> obj_attr_subsections)
>>   #define elf_properties(bfd) (elf_tdata (bfd) -> properties)
>>   #define elf_has_no_copy_on_protected(bfd) \
>>     (elf_tdata(bfd) -> has_no_copy_on_protected)
>> @@ -3083,6 +3093,34 @@ extern bool _bfd_elf_merge_unknown_attribute_list (bfd *, bfd *);
>>   extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr (asection *sec);
>>   extern bool elf_read_notes (bfd *, file_ptr, bfd_size_type, size_t);
>>   
>> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_init (unsigned int,
>> +  union obj_attr_value_v2);
>> +extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2 *, obj_attr_encoding_v2);
>> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *,
>> +  obj_attr_encoding_v2);
>> +extern void _bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *,
>> +  obj_attr_v2 *, obj_attr_v2 *);
>> +extern int _bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *, obj_attr_v2 *);
>> +extern obj_attr_v2 *
>> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *, uint32_t, bool);
>> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
>> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_v2, extern);
>> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
>> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_init (const char*,
>> +  obj_attr_subsection_scope_v2, bool, obj_attr_encoding_v2);
>> +extern void _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *);
>> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_copy
>> +  (obj_attr_subsection_v2 const*);
>> +extern void _bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *,
>> +  obj_attr_subsection_v2 *, obj_attr_subsection_v2 *);
>> +extern int _bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *,
>> +  obj_attr_subsection_v2 *s2);
>> +extern obj_attr_subsection_v2 * obj_attr_subsection_v2_find_by_name
>> +  (obj_attr_subsection_v2 *, const char *, bool);
>> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
>> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, extern);
>> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
>> +
>>   extern bool _bfd_elf_parse_gnu_properties
>>     (bfd *, Elf_Internal_Note *);
>>   extern elf_property_list * _bfd_elf_find_property
>> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
>> index 548da1f8b30..21fc99c4c98 100644
>> --- a/bfd/elfnn-aarch64.c
>> +++ b/bfd/elfnn-aarch64.c
>> @@ -10760,8 +10760,21 @@ const struct elf_size_info elfNN_aarch64_size_info =
>>   #define elf_backend_extern_protected_data 0
>>   #define elf_backend_hash_symbol elf_aarch64_hash_symbol
>>   
>> +/* elf_backend_obj_attrs_vendor is unused for AArch64. It is replaced by the
>> +   concept of subsections, each one having its own name defined by the
>> +   assembly directive "aeabi_subsection".  */
>> +#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		SEC_AARCH64_ATTRIBUTES
>> +/* elf_backend_obj_attrs_arg_type is unused as the type of an attribute is
>> +   determined by looking up at the current subsection, not the value of the
>> +   tag.  */
>> +#define elf_backend_obj_attrs_arg_type		NULL
>> +#undef	elf_backend_obj_attrs_section_type
>> +#define elf_backend_obj_attrs_section_type	SHT_AARCH64_ATTRIBUTES
>> +#undef	elf_backend_obj_attrs_version
>> +#define elf_backend_obj_attrs_version		2
>>   
>>   #include "elfNN-target.h"
>>   
>> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
>> index 625243cac94..cff508dbbce 100644
>> --- a/bfd/elfxx-target.h
>> +++ b/bfd/elfxx-target.h
>> @@ -556,6 +556,9 @@
>>   #ifndef elf_backend_obj_attrs_section_type
>>   #define elf_backend_obj_attrs_section_type		SHT_GNU_ATTRIBUTES
>>   #endif
>> +#ifndef elf_backend_obj_attrs_version
>> +#define elf_backend_obj_attrs_version		1 /* Default version.  */
>> +#endif
>>   #ifndef elf_backend_obj_attrs_order
>>   #define elf_backend_obj_attrs_order		NULL
>>   #endif
>> @@ -808,7 +811,7 @@
>>   #ifndef elf_backend_symbol_section_index
>>   #define elf_backend_symbol_section_index NULL
>>   #endif
>> -
>> +
>>   #ifndef elf_match_priority
>>   #define elf_match_priority \
>>     (ELF_ARCH == bfd_arch_unknown ? 2 : ELF_OSABI == ELFOSABI_NONE ? 1 : 0)
>> @@ -934,6 +937,7 @@ static const struct elf_backend_data elfNN_bed =
>>     elf_backend_obj_attrs_section,
>>     elf_backend_obj_attrs_arg_type,
>>     elf_backend_obj_attrs_section_type,
>> +  elf_backend_obj_attrs_version,
>>     elf_backend_obj_attrs_order,
>>     elf_backend_obj_attrs_handle_unknown,
>>     elf_backend_parse_gnu_properties,
>> diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in
>> index 54b078b8295..4b8ccfbe2c8 100644
>> --- a/bfd/po/SRC-POTFILES.in
>> +++ b/bfd/po/SRC-POTFILES.in
>> @@ -132,6 +132,7 @@ ecoff.c
>>   ecofflink.c
>>   ecoffswap.h
>>   elf-attrs.c
>> +elf-attrs.h
>>   elf-bfd.h
>>   elf-eh-frame.c
>>   elf-hppa.h
>
  

Patch

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 4987ac9cccc..0339db6b2b6 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -707,7 +707,7 @@  SOURCE_HFILES = \
 	elf32-metag.h elf32-nds32.h elf32-ppc.h \
 	elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
 	elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
-	elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
+	elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
 	elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
 	elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
 	elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 1543af7984a..ecc91d733af 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -1171,7 +1171,7 @@  SOURCE_HFILES = \
 	elf32-metag.h elf32-nds32.h elf32-ppc.h \
 	elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
 	elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
-	elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
+	elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
 	elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
 	elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
 	elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
index a6a72369afd..634843b5162 100644
--- a/bfd/elf-attrs.c
+++ b/bfd/elf-attrs.c
@@ -20,6 +20,7 @@ 
 
 #include "sysdep.h"
 #include "bfd.h"
+#include "double-linked-list.h"
 #include "libiberty.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
@@ -476,6 +477,19 @@  gnu_obj_attrs_arg_type (unsigned int tag)
 int
 _bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag)
 {
+  if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
+    {
+      BFD_ASSERT (elf_obj_attr_subsections (abfd).last_ != NULL);
+      switch (elf_obj_attr_subsections (abfd).last_->encoding)
+	{
+	case ULEB128:
+	  return ATTR_TYPE_FLAG_INT_VAL;
+	case NTBS:
+	  return ATTR_TYPE_FLAG_STR_VAL;
+	}
+    }
+
+  /* Version 1.  */
   switch (vendor)
     {
     case OBJ_ATTR_PROC:
@@ -822,6 +836,201 @@  _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
   return result;
 }
 
+obj_attr_v2 *
+_bfd_elf_obj_attr_v2_init (unsigned int tag,
+			   union obj_attr_value_v2 vals)
+{
+  obj_attr_v2 *attr = (obj_attr_v2*) malloc (sizeof (obj_attr_v2));
+  memset ((void *) attr, 0, sizeof (obj_attr_v2));
+  attr->tag = tag;
+  attr->vals = vals;
+  return attr;
+}
+
+void
+_bfd_elf_obj_attr_v2_free (obj_attr_v2 * attr, obj_attr_encoding_v2 encoding)
+{
+  if (encoding == NTBS && attr->vals.string_val != NULL)
+    free ((void *) attr->vals.string_val);
+  free (attr);
+}
+
+obj_attr_v2 *
+_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *other,
+			   obj_attr_encoding_v2 encoding)
+{
+  union obj_attr_value_v2 vals;
+  if (encoding == NTBS)
+    vals.string_val =
+      (other->vals.string_val != NULL)
+      ? strdup (other->vals.string_val)
+      : NULL;
+  else
+    vals.uint_val = other->vals.uint_val;
+
+  obj_attr_v2 *copy =_bfd_elf_obj_attr_v2_init (other->tag, vals);
+  copy->status = other->status;
+  return copy;
+}
+
+#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
+
+void
+_bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *s,
+			   obj_attr_v2 *a1, obj_attr_v2 *a2)
+{
+  SWAP (a1->next, a2->next);
+  SWAP (a1->prev, a2->prev);
+
+  if (s->first_ == a1)
+    s->first_ = a2;
+  else if (s->first_ == a2)
+    s->first_ = a1;
+
+  if (s->last_ == a1)
+    s->last_ = a2;
+  else if (s->last_ == a2)
+    s->last_ = a1;
+}
+
+int
+_bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *a1, obj_attr_v2 *a2)
+{
+  if (a1->tag < a2->tag)
+    return -1;
+  else if (a1->tag > a2->tag)
+    return 1;
+  else
+    return 0;
+}
+
+/* Find the object attribute matching the given tag (object attributes v2 only).
+   Note: The parameter 'sorted' specifies whether the given list is sorted or
+   not. If the list of attributes is sorted, the linear search stops as soon as
+   it finds an attribute with a greater tag.  */
+obj_attr_v2 *
+obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *subsec,
+			 uint32_t tag,
+			 bool sorted)
+{
+  for (obj_attr_v2 *attr = subsec->first_;
+       attr != NULL;
+       attr = attr->next)
+    if (attr->tag == tag)
+      return attr;
+    else if (sorted && attr->tag > tag)
+      break;
+  return NULL;
+}
+
+LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_v2, obj_attr_v2, /* public */)
+LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_v2, obj_attr_v2, /* public */)
+
+obj_attr_subsection_v2 *
+_bfd_elf_obj_attr_subsection_v2_init (const char* name,
+				      obj_attr_subsection_scope_v2 scope,
+				      bool optional,
+				      obj_attr_encoding_v2 encoding)
+{
+  obj_attr_subsection_v2* subsection = (obj_attr_subsection_v2*)
+    malloc (sizeof (obj_attr_subsection_v2));
+  memset ((void *) subsection, 0, sizeof (obj_attr_subsection_v2));
+  subsection->name = name;
+  subsection->scope = scope;
+  subsection->optional = optional;
+  subsection->encoding = encoding;
+  return subsection;
+}
+
+void
+_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *subsec)
+{
+  for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
+    _bfd_elf_obj_attr_v2_free (attr, subsec->encoding);
+  free (subsec);
+}
+
+obj_attr_subsection_v2 *
+_bfd_elf_obj_attr_subsection_v2_copy (obj_attr_subsection_v2 const *other)
+{
+  obj_attr_subsection_v2* new_subsec =
+    _bfd_elf_obj_attr_subsection_v2_init (other->name, other->scope,
+					  other->optional, other->encoding);
+  for (obj_attr_v2* attr = other->first_;
+       attr != NULL;
+       attr = attr->next)
+    {
+      obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
+      LINKED_LIST_APPEND(obj_attr_v2) (new_subsec, new_attr);
+    }
+  return new_subsec;
+}
+
+void
+_bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *plist,
+				      obj_attr_subsection_v2 *s1,
+				      obj_attr_subsection_v2 *s2)
+{
+  SWAP (s1->next, s2->next);
+  SWAP (s1->prev, s2->prev);
+
+  if (plist->first_ == s1)
+    plist->first_ = s2;
+  else if (plist->first_ == s2)
+    plist->first_ = s1;
+
+  if (plist->last_ == s1)
+    plist->last_ = s2;
+  else if (plist->last_ == s2)
+    plist->last_ = s1;
+}
+
+int
+_bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *s1,
+				     obj_attr_subsection_v2 *s2)
+{
+  int res = strcmp (s1->name, s2->name);
+  if (res != 0)
+    return res;
+
+  if (s1->optional < s2->optional)
+    return -1;
+  else if (s1->optional > s2->optional)
+    return 1;
+
+  if (s1->encoding < s2->encoding)
+    return -1;
+  if (s1->encoding > s2->encoding)
+    return 1;
+  else
+    return 0;
+}
+
+/* Find the subsection matching the given name.
+   Note: The parameter sorted specified whether the given list is sorted or not.
+   If the list of subsections is sorted, the linear search stops as soon as it
+   finds a subsection name with a greater order.  */
+obj_attr_subsection_v2 *
+obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2 *first,
+				     const char *name,
+				     bool sorted)
+{
+  for (obj_attr_subsection_v2 *s = first;
+       s != NULL;
+       s = s->next)
+    {
+      int cmp = strcmp (s->name, name);
+      if (cmp == 0)
+	return s;
+      else if (sorted && cmp > 0)
+	break;
+    }
+  return NULL;
+}
+
+LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
+LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
+
 bool _bfd_elf_write_section_build_attributes (bfd *abfd,
 					      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
diff --git a/bfd/elf-attrs.h b/bfd/elf-attrs.h
new file mode 100644
index 00000000000..5d41bb98538
--- /dev/null
+++ b/bfd/elf-attrs.h
@@ -0,0 +1,102 @@ 
+/* ELF attributes support (based on ARM EABI attributes).
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   Written by Cygnus Support.
+
+   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 3 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.  */
+
+#pragma once
+
+#include <stdint.h>
+
+/* --------------------
+   Object attributes v2
+   -------------------- */
+
+typedef enum obj_attr_encoding_v2
+{
+  ULEB128 = 0,
+  NTBS    = 1,
+} obj_attr_encoding_v2;
+
+typedef union obj_attr_value_v2 {
+  uint32_t uint_val;
+  const char* string_val;
+} obj_attr_value_v2;
+
+typedef struct obj_attr_v2 {
+  /* The name/tag of an attribute.  */
+  uint32_t tag;
+
+  /* The value assigned to an attribute, can be ULEB128 or NTBS.  */
+  union obj_attr_value_v2 vals;
+
+  /* The next attribute in the list or NULL.  */
+  struct obj_attr_v2 *next;
+
+  /* The previous attribute in the list or NULL.  */
+  struct obj_attr_v2 *prev;
+
+} obj_attr_v2;
+
+typedef enum obj_attr_subsection_scope_v2
+{
+  SUBSEC_PUBLIC = 0,
+  SUBSEC_PRIVATE = 1,
+} obj_attr_subsection_scope_v2;
+
+typedef struct obj_attr_subsection_v2 {
+  /* The name of the subsection.  */
+  const char *name;
+
+  /* The scope of the subsection.  */
+  obj_attr_subsection_scope_v2 scope;
+
+  /* Is this subsection optional ? Can it be skipped ?  */
+  bool optional;
+
+  /* The value encoding of attributes in this subsection.  */
+  obj_attr_encoding_v2 encoding;
+
+  /* The next subsection in the list, or NULL.  */
+  struct obj_attr_subsection_v2 *next;
+
+  /* The previous subsection in the list, or NULL.  */
+  struct obj_attr_subsection_v2 *prev;
+
+  /* A pointer to the first node of the list.  */
+  struct obj_attr_v2* first_;
+
+  /* A pointer to the last node of the list.  */
+  struct obj_attr_v2* last_;
+
+  /* The size of the list.  */
+  uint32_t size;
+
+} obj_attr_subsection_v2;
+
+typedef struct obj_attr_subsection_list
+{
+  /* A pointer to the first node of the list.  */
+  obj_attr_subsection_v2 *first_;
+
+  /* A pointer to the last node of the list.  */
+  obj_attr_subsection_v2 *last_;
+
+  /* The size of the list.  */
+  uint64_t size;
+} obj_attr_subsection_list;
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 5903d857faa..6c326d5db72 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -24,9 +24,11 @@ 
 
 #include <stdlib.h>
 
+#include "double-linked-list.h"
 #include "elf/common.h"
 #include "elf/external.h"
 #include "elf/internal.h"
+#include "elf-attrs.h"
 #include "bfdlink.h"
 
 #ifndef ENABLE_CHECKING
@@ -1630,13 +1632,15 @@  struct elf_backend_data
   /* 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.  */
+  /* Return 1, 2 or 3 to indicate what type of arguments a tag takes.  */
   int (*obj_attrs_arg_type) (int);
 
   /* The section type to use for an attributes section.  */
   unsigned int obj_attrs_section_type;
 
+  /* The version of object attributes (1 or 2).  */
+  unsigned int obj_attrs_version;
+
   /* This function determines the order in which any attributes are
      written.  It must be defined for input in the range
      LEAST_KNOWN_OBJ_ATTRIBUTE..NUM_KNOWN_OBJ_ATTRIBUTES-1 (this range
@@ -2160,6 +2164,11 @@  struct elf_obj_tdata
   obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
   obj_attribute_list *other_obj_attributes[2];
 
+  /* Object attributes v2: attributes of the same category are stored inside
+     the same subsection. A subsection can only hold attributes with the same
+     data type.  */
+  obj_attr_subsection_list obj_attr_subsections;
+
   /* Linked-list containing information about every Systemtap section
      found in the object file.  Each section corresponds to one entry
      in the list.  */
@@ -2253,6 +2262,7 @@  struct elf_obj_tdata
   (elf_known_obj_attributes (bfd) [OBJ_ATTR_PROC])
 #define elf_other_obj_attributes_proc(bfd) \
   (elf_other_obj_attributes (bfd) [OBJ_ATTR_PROC])
+#define elf_obj_attr_subsections(bfd) (elf_tdata (bfd) -> obj_attr_subsections)
 #define elf_properties(bfd) (elf_tdata (bfd) -> properties)
 #define elf_has_no_copy_on_protected(bfd) \
   (elf_tdata(bfd) -> has_no_copy_on_protected)
@@ -3083,6 +3093,34 @@  extern bool _bfd_elf_merge_unknown_attribute_list (bfd *, bfd *);
 extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr (asection *sec);
 extern bool elf_read_notes (bfd *, file_ptr, bfd_size_type, size_t);
 
+extern obj_attr_v2 *_bfd_elf_obj_attr_v2_init (unsigned int,
+  union obj_attr_value_v2);
+extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2 *, obj_attr_encoding_v2);
+extern obj_attr_v2 *_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *,
+  obj_attr_encoding_v2);
+extern void _bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *,
+  obj_attr_v2 *, obj_attr_v2 *);
+extern int _bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *, obj_attr_v2 *);
+extern obj_attr_v2 *
+obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *, uint32_t, bool);
+LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
+_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_v2, extern);
+LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
+extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_init (const char*,
+  obj_attr_subsection_scope_v2, bool, obj_attr_encoding_v2);
+extern void _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *);
+extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_copy
+  (obj_attr_subsection_v2 const*);
+extern void _bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *,
+  obj_attr_subsection_v2 *, obj_attr_subsection_v2 *);
+extern int _bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *,
+  obj_attr_subsection_v2 *s2);
+extern obj_attr_subsection_v2 * obj_attr_subsection_v2_find_by_name
+  (obj_attr_subsection_v2 *, const char *, bool);
+LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
+_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, extern);
+LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
+
 extern bool _bfd_elf_parse_gnu_properties
   (bfd *, Elf_Internal_Note *);
 extern elf_property_list * _bfd_elf_find_property
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 548da1f8b30..21fc99c4c98 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -10760,8 +10760,21 @@  const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_extern_protected_data 0
 #define elf_backend_hash_symbol elf_aarch64_hash_symbol
 
+/* elf_backend_obj_attrs_vendor is unused for AArch64. It is replaced by the
+   concept of subsections, each one having its own name defined by the
+   assembly directive "aeabi_subsection".  */
+#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		SEC_AARCH64_ATTRIBUTES
+/* elf_backend_obj_attrs_arg_type is unused as the type of an attribute is
+   determined by looking up at the current subsection, not the value of the
+   tag.  */
+#define elf_backend_obj_attrs_arg_type		NULL
+#undef	elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type	SHT_AARCH64_ATTRIBUTES
+#undef	elf_backend_obj_attrs_version
+#define elf_backend_obj_attrs_version		2
 
 #include "elfNN-target.h"
 
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 625243cac94..cff508dbbce 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -556,6 +556,9 @@ 
 #ifndef elf_backend_obj_attrs_section_type
 #define elf_backend_obj_attrs_section_type		SHT_GNU_ATTRIBUTES
 #endif
+#ifndef elf_backend_obj_attrs_version
+#define elf_backend_obj_attrs_version		1 /* Default version.  */
+#endif
 #ifndef elf_backend_obj_attrs_order
 #define elf_backend_obj_attrs_order		NULL
 #endif
@@ -808,7 +811,7 @@ 
 #ifndef elf_backend_symbol_section_index
 #define elf_backend_symbol_section_index NULL
 #endif
- 
+
 #ifndef elf_match_priority
 #define elf_match_priority \
   (ELF_ARCH == bfd_arch_unknown ? 2 : ELF_OSABI == ELFOSABI_NONE ? 1 : 0)
@@ -934,6 +937,7 @@  static const struct elf_backend_data elfNN_bed =
   elf_backend_obj_attrs_section,
   elf_backend_obj_attrs_arg_type,
   elf_backend_obj_attrs_section_type,
+  elf_backend_obj_attrs_version,
   elf_backend_obj_attrs_order,
   elf_backend_obj_attrs_handle_unknown,
   elf_backend_parse_gnu_properties,
diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in
index 54b078b8295..4b8ccfbe2c8 100644
--- a/bfd/po/SRC-POTFILES.in
+++ b/bfd/po/SRC-POTFILES.in
@@ -132,6 +132,7 @@  ecoff.c
 ecofflink.c
 ecoffswap.h
 elf-attrs.c
+elf-attrs.h
 elf-bfd.h
 elf-eh-frame.c
 elf-hppa.h