[PATCH v9 03/19] Object Attributes v2: new abstractions for subsections and attributes

Matthieu Longo matthieu.longo@arm.com
Mon Sep 1 16:56:10 GMT 2025


From: Richard Ball <richard.ball@arm.com>

This patch lays the groundwork for the support of Object Attributes v2 (OAv2).
OAv2 is an enhancement of OAv1. They retain successful aspects of OAv1, define
the relationship between object attributes and existing GNU properties, separate
architectural requirements from software ABI requirements, and simplify the
format to make it easier for OAv2 consumers to parse, and skip subsections and
attributes. Interestingly, OAv2 have only one scope: the whole relocatable file
where they were specified. For the reason behind this choice, see [1], "Build
attributes at file scope only". This document also provides more insights into
the design rationale for OAv2.

Even if OAv2 was designed primarily for AArch64, this implementation splits the
generic core logic from the backend-specific one, and aims at facilitating OAv2
adoption by others backend. This logic will apply for any subsequent OAv2 patch.

New abstractions for attributes and subsections are introduced in bfd/elf-attrs.h
Those align with the format of OAv2 proposed in [2].

An object attribute obj_attr_v2 is a tag-value pair:
 - tag: a key, i.e. a unique identifier for the attribute in the
   subsection.
 - value: a variant for which the interpretation depends on the encoding
   set in the subsection it was stored in. 2 types of values are possible:
   ULEB128 (Unsigned Little Endian Base 128) or a string encoded as NTBS
   (Null-Terminated Byte String).

A subsection obj_attr_subsection_v2 has the following members:
 - name: the name of this subsection.
 - scope: the prefix in the subsection name determines whether the
   subsection is public or private.
 - optionality: is this subsection optional or required ? Depending on
   whether the subsection is public or private, it can be ignored by the
   consumer.
 - encoding: see previous note regarding the value of an attribute. This
   encoding applies to all the attributes in this subsection.
 - list of object attributes.

Even if OAv1 and OAv2 data structures are similar, their processing is
different. Thus refactoring the code of OAv1 and OAv2 to share it does not
seem the right approach for clarity and maintainability, and minimalization
of the risk of introducing regressions.
Consequently, utility functions to initialize, copy, swap, free, compare,
mutate, and sort those structures won't be shared between OAv1 and OAv2.

Finally, the version ID used to identify the storage format of the object
attributes is object and backend dependent. This approach allows mixing
OAv1 and OAv2 in input objects. Then the deserializer translates the input
data to the internal model (currently OAv2, but it could be a more generic
one in the future) to perform the merge. In the end, the output format is
set by the backend: OAv2 for AArch64, OAv1 for others. The only exception
for this is objcopy, which won't change the format of the object attributes,
and will preserve the format of the data during the copy.
Hopefully, this mechanism will make easy the migration from OAv1 to OAv2 if
anyone is interested.

[1]: [Design Rationale for Build Attributes for the Arm 64-bit Architecture (AARCH64)]
     (https://github.com/ARM-software/abi-aa/blob/eec881270d5e3b23e58a6250640d06ff545ec1fc
      /design-documents/buildattr64-rationale.rst)
[2]: [Build Attributes for the Arm® 64-bit Architecture (AArch64)](https://github.com
      /ARM-software/abi-aa/blob/eec881270d5e3b23e58a6250640d06ff545ec1fc/buildattr64
      /buildattr64.rst)

Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
---
 bfd/Makefile.am        |   2 +-
 bfd/Makefile.in        |   2 +-
 bfd/elf-attrs.c        | 258 +++++++++++++++++++++++++++++++++++++++--
 bfd/elf-attrs.h        | 116 ++++++++++++++++++
 bfd/elf-bfd.h          |  55 ++++++++-
 bfd/elfnn-aarch64.c    |  17 +++
 bfd/elfxx-aarch64.c    |  19 +++
 bfd/elfxx-aarch64.h    |   6 +
 bfd/elfxx-target.h     |  16 ++-
 bfd/po/SRC-POTFILES.in |   1 +
 gas/config/obj-elf.c   |   5 +
 11 files changed, 480 insertions(+), 17 deletions(-)
 create mode 100644 bfd/elf-attrs.h

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 3c3243269f1..bedd6100f6f 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -705,7 +705,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-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 4c259682fd0..df205f2173d 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -1168,7 +1168,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-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 57c94777a3a..27c4329daf1 100644
--- a/bfd/elf-attrs.c
+++ b/bfd/elf-attrs.c
@@ -20,10 +20,30 @@
 
 #include "sysdep.h"
 #include "bfd.h"
+#include "doubly-linked-list.h"
 #include "libiberty.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 
+/* Decode the encoded version number corresponding to the Object Attribute
+   version.  Return the version on success, UNSUPPORTED on failure.  */
+obj_attr_version_t
+_bfd_obj_attrs_version_dec (uint8_t encoded_version)
+{
+  if (encoded_version == 'A')
+    return OBJ_ATTR_V1;
+  return OBJ_ATTR_VERSION_UNSUPPORTED;
+}
+
+/* Encode the Object Attribute version into a byte.  */
+uint8_t
+_bfd_obj_attrs_version_enc (obj_attr_version_t version)
+{
+  if (version == OBJ_ATTR_V1)
+    return 'A';
+  abort ();
+}
+
 /* Return the number of bytes needed by I in uleb128 format.  */
 static uint32_t
 uleb128_size (uint32_t i)
@@ -212,8 +232,9 @@ write_obj_attr_section_v1 (bfd *abfd, bfd_byte *buffer, bfd_vma size)
 {
   bfd_byte *p = buffer;
 
-  /* <format-version: ‘A’>  */
-  *(p++) = 'A';
+  const struct elf_backend_data *be = get_elf_backend_data (abfd);
+  /* <format-version: uint8>  */
+  *(p++) = be->obj_attrs_version_enc (elf_obj_attr_version (abfd));
 
   for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor)
     {
@@ -421,6 +442,12 @@ _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd)
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return;
 
+  obj_attr_version_t version = elf_obj_attr_version (ibfd);
+  elf_obj_attr_version (obfd) = version;
+
+  if (version == OBJ_ATTR_VERSION_NONE)
+    return;
+
   for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
     {
       in_attr
@@ -492,6 +519,8 @@ _bfd_elf_obj_attrs_arg_type (bfd *abfd,
 			     obj_attr_vendor_t vendor,
 			     obj_attr_tag_t tag)
 {
+  BFD_ASSERT (elf_obj_attr_version (abfd) == OBJ_ATTR_V1);
+  /* This function should only be called for object attributes version 1.  */
   switch (vendor)
     {
     case OBJ_ATTR_PROC:
@@ -629,6 +658,8 @@ bfd_elf_parse_attr_section_v1 (bfd *abfd, bfd_byte *p, bfd_byte *p_end)
 void
 _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
 {
+  elf_obj_attr_version (abfd) = OBJ_ATTR_VERSION_NONE;
+
   /* PR 17512: file: 2844a11d.  */
   if (hdr->sh_size == 0)
     return;
@@ -651,18 +682,20 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
 
   unsigned char *cursor = data;
 
-  /* The first character is the version of the attributes.
-     Currently only version 'A' is recognised here.  */
-  if (*cursor != 'A')
+  /* The first character is the version of the attributes.  */
+  obj_attr_version_t version
+    = get_elf_backend_data (abfd)->obj_attrs_version_dec (*cursor);
+  if (version == OBJ_ATTR_VERSION_UNSUPPORTED || version > OBJ_ATTR_MAX_V)
     {
-      _bfd_error_handler (_("%pB: error: unknown attributes version '%c'(%d) "
-			    "- expecting 'A'\n"), abfd, *cursor, *cursor);
+      _bfd_error_handler (_("%pB: error: unknown attributes version '%c'(%d)\n"),
+			  abfd, *cursor, *cursor);
       bfd_set_error (bfd_error_wrong_format);
       goto free_data;
     }
 
   ++cursor;
 
+  elf_obj_attr_version (abfd) = version;
   bfd_elf_parse_attr_section_v1 (abfd, cursor, data + hdr->sh_size);
 
  free_data:
@@ -834,8 +867,215 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
   return result;
 }
 
-bool _bfd_elf_write_section_build_attributes (bfd *abfd,
-					      struct bfd_link_info *info ATTRIBUTE_UNUSED)
+/* Create a new object attribute with key TAG and value VALS.
+   Return a pointer to it.  */
+
+obj_attr_v2 *
+_bfd_elf_obj_attr_v2_init (obj_attr_tag_t tag,
+			   union obj_attr_value_v2 val)
+{
+  obj_attr_v2 *attr = XCNEW (obj_attr_v2);
+  attr->tag = tag;
+  attr->val = val;
+  return attr;
+}
+
+/* Free memory allocated by the object attribute ATTR.  */
+
+void
+_bfd_elf_obj_attr_v2_free (obj_attr_v2 *attr, obj_attr_encoding_v2 encoding)
+{
+  if (encoding == OA_ENC_NTBS)
+    free ((char *) attr->val.string_val);
+  free (attr);
+}
+
+/* Copy an object attribute OTHER, and return a pointer to the copy.  */
+
+obj_attr_v2 *
+_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *other,
+			   obj_attr_encoding_v2 encoding)
+{
+  union obj_attr_value_v2 val;
+  if (encoding == OA_ENC_NTBS)
+    val.string_val
+      = (other->val.string_val != NULL
+	 ? xstrdup (other->val.string_val)
+	 : NULL);
+  else
+    val.uint_val = other->val.uint_val;
+
+  return _bfd_elf_obj_attr_v2_init (other->tag, val);
+}
+
+/* Compare two object attributes based on their TAG value only (partial
+   ordering), and return an integer indicating the result of the comparison,
+   as follows:
+   - 0, if A1 and A2 are equal.
+   - a negative value if A1 is less than A2.
+   - a positive value if A1 is greater than A2.  */
+
+int
+_bfd_elf_obj_attr_v2_cmp (const obj_attr_v2 *a1, const obj_attr_v2 *a2)
+{
+  if (a1->tag < a2->tag)
+    return -1;
+  else if (a1->tag > a2->tag)
+    return 1;
+  return 0;
+}
+
+/* Return an object attribute in SUBSEC matching TAG or NULL if one is not
+   found.  SORTED specifies whether the given list is ordered by tag number.
+   This allows an early return if we find a higher numbered tag.  */
+
+obj_attr_v2 *
+obj_attr_v2_find_by_tag (const obj_attr_subsection_v2 *subsec,
+			 obj_attr_tag_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;
+}
+
+/* Sort the object attributes inside a subsection.
+   Note: since a subsection is a list of attributes, the sorting algorithm is
+   implemented with a merge sort.
+   See more details in libiberty/doubly-linked-list.h  */
+
+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 */)
+
+/* Create a new object attribute subsection with the following properties:
+   - NAME: the name of the subsection.
+   - SCOPE: the scope of the subsection (public or private).
+   - OPTIONAL: whether this subsection is optional (true) or required (false).
+   - ENCODING: the expected encoding for the attributes values (ULEB128 or NTBS).
+   Return a pointer to it.  */
+
+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 = XCNEW (obj_attr_subsection_v2);
+  subsection->name = name;
+  subsection->scope = scope;
+  subsection->optional = optional;
+  subsection->encoding = encoding;
+  return subsection;
+}
+
+/* Free memory allocated by the object attribute subsection SUBSEC.  */
+
+void
+_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *subsec)
+{
+  obj_attr_v2 *attr = subsec->first;
+  while (attr != NULL)
+    {
+      obj_attr_v2 *a = attr;
+      attr = attr->next;
+      _bfd_elf_obj_attr_v2_free (a, subsec->encoding);
+    }
+  free ((void *) subsec->name);
+  free (subsec);
+}
+
+/* Deep copy an object attribute subsection OTHER, and return a pointer to the
+   copy.  */
+
+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 (xstrdup (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;
+}
+
+/* Compare two object attributes based on all the attributes (scope is computed
+   from the name, so is not used for the comparison) of a subsection (total
+   ordering) , and return an integer indicating the result of the comparison,
+   as follows:
+   - 0, if S1 and S2 are equal.
+   - a negative value if S1 is less than S2.
+   - a positive value if S1 is greater than S2.  */
+
+int
+_bfd_elf_obj_attr_subsection_v2_cmp (const obj_attr_subsection_v2 *s1,
+				     const obj_attr_subsection_v2 *s2)
+{
+  int res = strcmp (s1->name, s2->name);
+  if (res != 0)
+    return res;
+
+  /* Giving to the optionality a higher priority than the encoding is
+     artificial.  Its only purpose is to give a total ordering to a
+     collection of subsections.  */
+  if (!s1->optional && s2->optional)
+    return -1;
+  else if (s1->optional && !s2->optional)
+    return 1;
+
+  if (s1->encoding < s2->encoding)
+    return -1;
+  else if (s1->encoding > s2->encoding)
+    return 1;
+
+  return 0;
+}
+
+/* Return a subsection in the list FIRST matching NAME or NULL if one is not
+   found.  SORTED specifies whether the given list is ordered by name.
+   This allows an early return if we find a alphabetically-higher name.  */
+
+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;
+}
+
+/* Sort the subsections in a vendor section.
+   Note: since a section is a list of subsections, the sorting algorithm is
+   implemented with a merge sort.
+   See more details in libiberty/doubly-linked-list.h  */
+
+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 */)
+
+/* Serialize the object attributes in ABFD into the vendor section of
+   OUTPUT_BFD.  */
+
+bool
+_bfd_elf_write_section_build_attributes (bfd *abfd,
+					 struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   asection *sec = elf_obj_build_attributes (abfd);
 
diff --git a/bfd/elf-attrs.h b/bfd/elf-attrs.h
new file mode 100644
index 00000000000..ea4b08694cc
--- /dev/null
+++ b/bfd/elf-attrs.h
@@ -0,0 +1,116 @@
+/* ELF attributes support (based on ARM EABI attributes).
+   Copyright (C) 2025 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 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>
+
+typedef enum obj_attr_version_t {
+  OBJ_ATTR_VERSION_NONE = 0,
+  OBJ_ATTR_VERSION_UNSUPPORTED,
+  OBJ_ATTR_V1,
+  OBJ_ATTR_V2,
+  OBJ_ATTR_MAX_V = OBJ_ATTR_V2,
+} obj_attr_version_t;
+
+/* --------------------
+   Object attributes v2
+   -------------------- */
+
+typedef enum obj_attr_encoding_v2
+{
+  OA_ENC_UNSET   = 0,
+  OA_ENC_ULEB128,
+  OA_ENC_NTBS,
+  OA_ENC_MAX     = OA_ENC_NTBS,
+} obj_attr_encoding_v2;
+
+#define obj_attr_encoding_v2_from_u8(value) \
+  ((enum obj_attr_encoding_v2) (value + 1))
+#define obj_attr_encoding_v2_to_u8(value) \
+  ((uint8_t) (value - 1))
+
+typedef union obj_attr_value_v2 {
+  uint32_t uint_val;
+  const char* string_val;
+} obj_attr_value_v2;
+
+typedef uint32_t obj_attr_tag_t;
+
+typedef struct obj_attr_v2 {
+  /* The name/tag of an attribute.  */
+  obj_attr_tag_t tag;
+
+  /* The value assigned to an attribute, can be ULEB128 or NTBS.  */
+  union obj_attr_value_v2 val;
+
+  /* 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
+{
+  OA_SUBSEC_PUBLIC,
+  OA_SUBSEC_PRIVATE,
+} 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 size of the list.  */
+  unsigned int size;
+
+  /* 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;
+} 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.  */
+  unsigned int size;
+} obj_attr_subsection_list;
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 9d4291bcfb5..4602ffe8a47 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -24,9 +24,11 @@
 
 #include <stdlib.h>
 
+#include "doubly-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
@@ -993,8 +995,6 @@ struct elf_find_verdep_info
 
 struct bfd_elf_section_reloc_data;
 
-typedef uint32_t obj_attr_tag_t;
-
 struct elf_backend_data
 {
   /* The architecture for this backend.  */
@@ -1640,13 +1640,22 @@ 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) (obj_attr_tag_t);
 
   /* The section type to use for an attributes section.  */
   unsigned int obj_attrs_section_type;
 
+  /* The preferred version of object attributes for the output object.  */
+  obj_attr_version_t default_obj_attr_version;
+
+  /* Decode the object attributes version from the version number encoded in
+     the input object.  */
+  obj_attr_version_t (*obj_attrs_version_dec) (uint8_t);
+
+  /* Encode the object attributes version into the output object.  */
+  uint8_t (*obj_attrs_version_enc) (obj_attr_version_t);
+
   /* 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
@@ -2169,9 +2178,19 @@ struct elf_obj_tdata
      after all input GNU properties are merged for output.  */
   elf_property_list *properties;
 
+  /* The version of object attributes for this object.
+     For an input object, the format version used to store the data.
+     For an output object, the targeted format version.  */
+  obj_attr_version_t obj_attr_version;
+
   obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
   obj_attribute_list *other_obj_attributes[2];
 
+  /* Object attributes v2: A subsection can only hold attributes with the
+     same data type (uleb128, NTBS, etc), so each type requires a separate
+     subsection.  */
+  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.  */
@@ -2259,12 +2278,14 @@ struct elf_obj_tdata
 #define elf_bad_symtab(bfd)	(elf_tdata(bfd) -> bad_symtab)
 #define elf_flags_init(bfd)	(elf_tdata(bfd) -> o->flags_init)
 #define elf_use_dt_symtab_p(bfd) (elf_tdata(bfd) -> dt_symtab_count != 0)
+#define elf_obj_attr_version(bfd) (elf_tdata (bfd) -> obj_attr_version)
 #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])
+#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)
@@ -3067,6 +3088,8 @@ extern bfd *_bfd_elf64_bfd_from_remote_memory
   (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep,
    int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type));
 
+extern obj_attr_version_t _bfd_obj_attrs_version_dec (uint8_t);
+extern uint8_t _bfd_obj_attrs_version_enc (obj_attr_version_t);
 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 *, obj_attr_vendor_t, obj_attr_tag_t);
@@ -3097,6 +3120,30 @@ 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 (obj_attr_tag_t,
+  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 int _bfd_elf_obj_attr_v2_cmp (const obj_attr_v2 *, const obj_attr_v2 *);
+extern obj_attr_v2 *
+obj_attr_v2_find_by_tag (const obj_attr_subsection_v2 *, obj_attr_tag_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 int _bfd_elf_obj_attr_subsection_v2_cmp (const obj_attr_subsection_v2 *,
+  const 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 4517567a554..efe554620ef 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -10781,7 +10781,24 @@ 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
 
+/* In OAv2, the presence of a vendor prefix means that the contents (syntax) can
+   be fully parsed, even if the interpretation of each tag is unknown.*/
+#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
+/* In OAv2, the type of an attribute is specified by the subsection that
+   contains it.  */
+#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_default_obj_attr_version
+#define elf_backend_default_obj_attr_version	OBJ_ATTR_V2
+#undef	elf_backend_obj_attrs_version_dec
+#define elf_backend_obj_attrs_version_dec \
+  _bfd_aarch64_obj_attrs_version_dec
+#undef	elf_backend_obj_attrs_version_enc
+#define elf_backend_obj_attrs_version_enc \
+  _bfd_aarch64_obj_attrs_version_enc
 
 #include "elfNN-target.h"
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 551f74e3373..b34ee13a299 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -868,6 +868,25 @@ _bfd_aarch64_elf_check_gnu_properties_linked_dynamic_objects (
 	pbfd);
 }
 
+/* Decode the encoded version number corresponding to the Object Attribute
+   version.  Return the version on success, UNSUPPORTED on failure.  */
+obj_attr_version_t
+_bfd_aarch64_obj_attrs_version_dec (uint8_t encoded_version)
+{
+  if (encoded_version == 'A')
+    return OBJ_ATTR_V2;
+  return OBJ_ATTR_VERSION_UNSUPPORTED;
+}
+
+/* Encode the Object Attribute version into a byte.  */
+uint8_t
+_bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t version)
+{
+  if (version == OBJ_ATTR_V2)
+    return 'A';
+  abort ();
+}
+
 /* Find the first input bfd with GNU property and merge it with GPROP.  If no
    such input is found, add it to a new section at the last input.  Update
    GPROP accordingly.  */
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index bd3642cbefe..d23bd1ee6c2 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -234,6 +234,12 @@ _bfd_aarch64_elf_write_core_note (bfd *, char *, int *, int, ...);
 #define elf_backend_grok_psinfo		_bfd_aarch64_elf_grok_psinfo
 #define elf_backend_write_core_note	_bfd_aarch64_elf_write_core_note
 
+extern obj_attr_version_t
+_bfd_aarch64_obj_attrs_version_dec (uint8_t);
+
+extern uint8_t
+_bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t);
+
 extern bfd *
 _bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *);
 
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 4cf02bbedd7..2b5515d2c0a 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -552,7 +552,16 @@
 #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
+#define elf_backend_obj_attrs_section_type	SHT_GNU_ATTRIBUTES
+#endif
+#ifndef elf_backend_default_obj_attr_version
+#define elf_backend_default_obj_attr_version	OBJ_ATTR_V1
+#endif
+#ifndef elf_backend_obj_attrs_version_dec
+#define elf_backend_obj_attrs_version_dec	_bfd_obj_attrs_version_dec
+#endif
+#ifndef elf_backend_obj_attrs_version_enc
+#define elf_backend_obj_attrs_version_enc	_bfd_obj_attrs_version_enc
 #endif
 #ifndef elf_backend_obj_attrs_order
 #define elf_backend_obj_attrs_order		NULL
@@ -806,7 +815,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)
@@ -932,6 +941,9 @@ 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_default_obj_attr_version,
+  elf_backend_obj_attrs_version_dec,
+  elf_backend_obj_attrs_version_enc,
   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 1ba9cc2fdb1..ba3f8075d57 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
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 0b43f596be2..b1a62ee2831 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -3020,6 +3020,11 @@ elf_begin (void)
   memset (&groups, 0, sizeof (groups));
 
 #ifdef TC_OBJ_ATTR
+  /* Set the object attribute version for the output object to the recommended
+     value by the backend.  */
+  elf_obj_attr_version (stdoutput)
+    = get_elf_backend_data (stdoutput)->default_obj_attr_version;
+
   oav1_attr_info_init ();
 #endif /* TC_OBJ_ATTR */
 }
-- 
2.51.0



More information about the Binutils mailing list