[PATCH v1 13/14] aarch64: merge of Object Attributes v2 during linkage

Matthieu Longo matthieu.longo@arm.com
Fri Mar 21 17:14:47 GMT 2025


This patch adds support to AArch64 backend to process AEABI Build
Attributes and raise any compatibility issue.

AArch64 backend declares 2 vendor subsections, and their associated tags:
- aeabi_feature_and_bits: contains tags that describe the same optional
  bits as the GNU_PROPERTY_AARCH64_FEATURE_1_AND. For now, the following
  attributes are recognized:
    - Tag_Feature_BTI: means that all the executable sections are
      compatible with Branch Target Identification (BTI) mechanism.
    - Tag_Feature_PAC: means that all the executable sections have been
      protected with Return Address Signing.
    - Tag_Feature_GCS: means that all the executable sections are
      compatible with the Guarded Control Stack (GCS) extension.
- aeabi_pauthabi: contains information about the Pointer Authentication
  Signing schema when the object uses an extension to ELF, PAUTHABI64,
  which is currently not supported by GCC toolchain. The pointers that
  are signed as well as the modifiers and key used for each type of
  pointer are known as the signing schema. The support of this
  subsection is there for completeness with the AEABI Build Attributes
  document, and allows readelf to dump the data nicely, and the linker
  to detect a use of a signing schema, and error.
    - Tag_PAuth_Paltform: the platform vendor id.
    - Tag_PAuth_Schema: the version numner of the schema.

For backward-compatibilty purpose, AArch64 backend translates
GNU_PROPERTY_AARCH64_FEATURE_1_AND in input files to its OAv2 equivalents.
The frozen set of OAv2 is populated with values derived from command-line
options for BTI (-z force-bti) and GCS (-z gcs=*).
It also reports incompatibilities for BTI and GCS, and set BTI PLT type
depending on the OAv2 merge result.
Regarding incompatibilities, only the ones detected in objects constituting
the output link unit will be reported. Supports for detecting incompatibilities
in shared objects might be a future work to bring it in pair with the GNU
properties merge. However, since OAv2 are translated to GNU properties,
detection will still happen so this feature seems redundant and of little
value given the backward compatibility support for GNU properties is
required (see next paragraph).
Finally, it translates OAv2s in subsection "aeabi_feature_and_bits" to
GNU_PROPERTY_AARCH64_FEATURE_1_AND as GNU properties are required for
the dynamic linker (it does not understand OAv2s yet).
---
 bfd/elfnn-aarch64.c | 101 +++++++++++-
 bfd/elfxx-aarch64.c | 362 ++++++++++++++++++++++++++++++++++++++++++--
 bfd/elfxx-aarch64.h |  36 +++++
 3 files changed, 482 insertions(+), 17 deletions(-)

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 21fc99c4c98..9bb36fd550c 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -5023,27 +5023,54 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
   elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
   elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn;
 
+  /* The global list of build attributes used to save requested features from
+     the command-line options.  */
+  obj_attr_subsection_v2 *attrs_subsection =
+    _bfd_elf_obj_attr_subsection_v2_init ("aeabi_feature_and_bits",
+      SUBSEC_PUBLIC, true, ULEB128);
+
   /* Note: gnu_property_aarch64_feature_1_and was initialized to 0 by
      bfd_zalloc().  */
   if (sw_protections->plt_type & PLT_BTI)
-    elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
-      |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+    {
+      elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
+	|= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+      _bfd_aarch64_record_obj_attr_v2 (attrs_subsection, Tag_Feature_BTI, true);
+    }
+
+  /* Note: Contrarilly to PLT_BTI, (sw_protections->plt_type & PLT_PAC) == true
+     does not mean that Tag_Feature_PAC should also be set to true.  The PAC
+     build attribute is only there to mirror the existing GNU properties.
+     Adding a property for PAC was in retrospect a mistake as it does not carry
+     valuable information.  The only use it does have is informational: if the
+     property is set on the output ELF object, then someone went to the trouble
+     of enabling it on all the input objects.  */
 
   switch (sw_protections->gcs_type)
     {
     case GCS_ALWAYS:
-      elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
-	|= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+      {
+	elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
+	  |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+	_bfd_aarch64_record_obj_attr_v2 (attrs_subsection, Tag_Feature_GCS, true);
+      }
       break;
     case GCS_NEVER:
-      elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
-	&= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+      {
+	elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
+	  &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+	_bfd_aarch64_record_obj_attr_v2 (attrs_subsection, Tag_Feature_GCS, false);
+      }
       break;
     case GCS_IMPLICIT:
       /* GCS feature on the output bfd will be deduced from input objects.  */
       break;
     }
 
+  if (attrs_subsection->size > 0)
+    LINKED_LIST_APPEND(obj_attr_subsection_v2) (
+      &elf_obj_attr_subsections (output_bfd), attrs_subsection);
+
   elf_aarch64_tdata (output_bfd)->sw_protections = *sw_protections;
   /* Inherit the value from '-z gcs-report' if the option '-z gcs-report-dynamic'
      was not set on the command line.  However, the inheritance mechanism is
@@ -10395,7 +10422,8 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
   return true;
 }
 
-/* Check if BTI enabled PLTs are needed.  Returns the type needed.  */
+/* Check if BTI-enabled (and/or PAC-enabled) PLTs are needed.
+   Returns the type needed.  */
 static aarch64_plt_type
 get_plt_type (bfd *abfd)
 {
@@ -10515,6 +10543,41 @@ elfNN_aarch64_backend_symbol_processing (bfd *abfd, asymbol *sym)
     sym->flags |= BSF_KEEP;
 }
 
+/* Implement elf_backend_setup_build_attributes for AArch64.  */
+static bfd *
+elfNN_aarch64_link_setup_build_attributes (struct bfd_link_info *info)
+{
+  bfd *pbfd = _bfd_aarch64_elf_link_setup_build_attributes (info);
+
+  struct elf_aarch64_obj_tdata * tdata = elf_aarch64_tdata (info->output_bfd);
+
+  /* When BTI is forced on the command line, information flows from plt_type to
+     the frozen build attributes (a.k.a FROZEN), so plt_type has already been
+     set and FROZEN don't have any effect on plt_type.
+     Whereas if BTI is inferred from the input bfds, information flows from
+     output build attributes to plt_type.  If the property GNU_PROPERTY_AARCH64
+     _FEATURE_1_BTI has been set on all the input bfds, then BTI is set on the
+     output bfd and plt_type is updated accordingly.
+
+     Important note: this is not true for GNU_PROPERTY_AARCH64_FEATURE_1_PAC.
+     See more explanation in bfd_elfNN_aarch64_set_options.  */
+  obj_attr_subsection_v2 *aeabi_feature_and_bits_subsec =
+    obj_attr_subsection_v2_find_by_name (
+      elf_obj_attr_subsections (info->output_bfd).first_,
+      "aeabi_feature_and_bits", true);
+  if (aeabi_feature_and_bits_subsec != NULL)
+    {
+      obj_attr_v2 *attr_bti = obj_attr_v2_find_by_tag
+	(aeabi_feature_and_bits_subsec, Tag_Feature_BTI, true);
+      if (attr_bti && attr_bti->vals.uint_val == 1)
+	tdata->sw_protections.plt_type |= PLT_BTI;
+    }
+
+  setup_plt_values (info, tdata->sw_protections.plt_type);
+
+  return pbfd;
+}
+
 /* Implement elf_backend_setup_gnu_properties for AArch64.  It serves as a
    wrapper function for _bfd_aarch64_elf_link_setup_gnu_properties to account
    for the effect of GNU properties of the output_bfd.  */
@@ -10732,9 +10795,27 @@ const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_symbol_processing		\
   elfNN_aarch64_backend_symbol_processing
 
+#define elf_backend_setup_build_attributes	\
+  elfNN_aarch64_link_setup_build_attributes
+
 #define elf_backend_setup_gnu_properties	\
   elfNN_aarch64_link_setup_gnu_properties
 
+#define elf_backend_translate_relevant_gnu_props_to_obj_attrs \
+  _bfd_aarch64_translate_relevant_gnu_props_to_obj_attrs
+
+#define elf_backend_translate_relevant_obj_attrs_to_gnu_props \
+  _bfd_aarch64_translate_relevant_obj_attrs_to_gnu_props
+
+#define elf_backend_obj_attr_subsection_v2_match_known \
+  _bfd_aarch64_obj_attr_subsection_v2_match_known
+
+#define elf_backend_obj_attr_v2_default_value	\
+  _bfd_aarch64_obj_attr_v2_default_value
+
+#define elf_backend_obj_attr_v2_tag_merge	\
+  _bfd_aarch64_obj_attr_v2_tag_merge
+
 #define elf_backend_merge_gnu_properties	\
   elfNN_aarch64_merge_gnu_properties
 
@@ -10775,6 +10856,12 @@ const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_obj_attrs_section_type	SHT_AARCH64_ATTRIBUTES
 #undef	elf_backend_obj_attrs_version
 #define elf_backend_obj_attrs_version		2
+/* Object attributes v2 specific values.  */
+#undef	elf_backend_obj_attr_v2_known_subsections
+#define elf_backend_obj_attr_v2_known_subsections \
+  aarch64_obj_attr_v2_known_subsections
+#undef	elf_backend_obj_attr_v2_known_subsections_size
+#define elf_backend_obj_attr_v2_known_subsections_size 2
 
 #include "elfNN-target.h"
 
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 45a02058e81..3e6ffd89080 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -21,6 +21,7 @@
 #include "sysdep.h"
 #include "bfd.h"
 #include "elf-bfd.h"
+#include "elf/aarch64.h"
 #include "elfxx-aarch64.h"
 #include "libbfd.h"
 #include <stdarg.h>
@@ -868,6 +869,335 @@ _bfd_aarch64_elf_check_gnu_properties_linked_dynamic_objects (
 	pbfd);
 }
 
+/* Note: this array has to be sorted.  */
+static const known_tag_v2 known_tags_aeabi_feature_and_bits [] =
+{
+  {Tag_Feature_BTI, OBJ_ATTR_TAG_v2(Feature_BTI), .default_value.uint_val = 0},
+  {Tag_Feature_PAC, OBJ_ATTR_TAG_v2(Feature_PAC), .default_value.uint_val = 0},
+  {Tag_Feature_GCS, OBJ_ATTR_TAG_v2(Feature_GCS), .default_value.uint_val = 0},
+};
+/* This is a required subsection to use PAuthABI (which is currently
+   unsupported by GCC). A value of 0 for any the tags below means that
+   the user did not permit this entity to use the PAuthABI.
+   Note: this array has to be sorted.  */
+static const known_tag_v2 known_tags_aeabi_pauthabi [] =
+{
+  {Tag_PAuth_Platform, OBJ_ATTR_TAG_v2(PAuth_Platform), .default_value.uint_val = 0},
+  {Tag_PAuth_Schema, OBJ_ATTR_TAG_v2(PAuth_Schema), .default_value.uint_val = 0},
+};
+
+/* Note: this array is exported by the backend, and needs to be sorted.  */
+const known_subsection_v2 aarch64_obj_attr_v2_known_subsections[] =
+{
+  {
+    .subsec_name = "aeabi_feature_and_bits",
+    .known_tags = known_tags_aeabi_feature_and_bits,
+    .optional = true,
+    .encoding = ULEB128,
+    .len = sizeof (known_tags_aeabi_feature_and_bits) / sizeof (known_tag_v2),
+  },
+  {
+    .subsec_name = "aeabi_pauthabi",
+    .known_tags = known_tags_aeabi_pauthabi,
+    .optional = false,
+    .encoding = ULEB128,
+    .len = sizeof (known_tags_aeabi_pauthabi) / sizeof (known_tag_v2),
+  },
+};
+
+void
+_bfd_aarch64_record_obj_attr_v2 (obj_attr_subsection_v2 *subsec,
+				 Tag_Feature_XXX feature_tag,
+				 uint32_t value)
+{
+  union obj_attr_value_v2 data;
+  data.uint_val = value;
+  obj_attr_v2 *attr = _bfd_elf_obj_attr_v2_init (feature_tag, data);
+  LINKED_LIST_APPEND(obj_attr_v2) (subsec, attr);
+}
+
+static void
+obj_attr_v2_record_tag_value (obj_attr_subsection_v2 *subsec,
+		   Tag_Feature_XXX tag,
+		   bool value)
+{
+  obj_attr_v2 *attr;
+  attr = obj_attr_v2_find_by_tag (subsec, tag, false);
+  if (attr != NULL)
+    {
+      if (attr->vals.uint_val != value)
+	{
+	  /* If we find an existing value for the given object attributes and
+	     this value is different from the new one, it can mean two things:
+	       - either the values are conflicting, and we need to raise an
+	       error.
+	       - either there are several GNU properties AARCH64_FEATURE_1_AND
+	       which were recorded, but its final value is the result of the
+	       merge of those separate values.
+	     For now, only the second case occurs.  */
+	  uint32_t merged_val = attr->vals.uint_val | value;
+	  _bfd_aarch64_record_obj_attr_v2 (subsec, tag, merged_val);
+	}
+      // else: nothing to do
+    }
+  else
+    _bfd_aarch64_record_obj_attr_v2 (subsec, tag, value);
+}
+
+/* Translate the relevant GNU properties to object attributes v2.  */
+void
+_bfd_aarch64_translate_relevant_gnu_props_to_obj_attrs (
+  bfd *abfd,
+  elf_property_list *p)
+{
+  if (p->property.pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+    {
+      elf_property *prop = &p->property;
+      BFD_ASSERT (prop->pr_kind == property_number);
+
+      obj_attr_subsection_v2 *subsec = obj_attr_subsection_v2_find_by_name
+	(elf_obj_attr_subsections (abfd).first_, "aeabi_feature_and_bits", false);
+
+      bool new_subsec = false;
+      if (subsec == NULL)
+	{
+	  subsec = _bfd_elf_obj_attr_subsection_v2_init (
+	    "aeabi_feature_and_bits", SUBSEC_PUBLIC, true, ULEB128);
+	  new_subsec = true;
+	}
+
+      bool bti_bit = prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+      bool pac_bit = prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
+      bool gcs_bit = prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+
+      obj_attr_v2_record_tag_value (subsec, Tag_Feature_BTI, bti_bit);
+      obj_attr_v2_record_tag_value (subsec, Tag_Feature_PAC, pac_bit);
+      obj_attr_v2_record_tag_value (subsec, Tag_Feature_GCS, gcs_bit);
+
+      if (new_subsec)
+	LINKED_LIST_APPEND(obj_attr_subsection_v2) (
+	  &elf_obj_attr_subsections (abfd), subsec);
+    }
+}
+
+void
+_bfd_aarch64_translate_relevant_obj_attrs_to_gnu_props (
+  bfd *abfd,
+  obj_attr_subsection_v2 *subsec)
+{
+  /* Note: there is no need to create the GNU properties section here.  It will
+     be handled later by setup_gnu_properties.  */
+
+  if (strcmp (subsec->name, "aeabi_feature_and_bits") == 0)
+    {
+      uint32_t gnu_property_aarch64_features = 0;
+
+      for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
+	{
+	  if (attr->tag == Tag_Feature_BTI && attr->vals.uint_val == 1)
+	    gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+	  else if (attr->tag == Tag_Feature_PAC && attr->vals.uint_val == 1)
+	    gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
+	  else if (attr->tag == Tag_Feature_GCS && attr->vals.uint_val == 1)
+	    gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+	}
+
+      /* Note: _bfd_elf_get_property find the existing property, or create one.
+	 The insertion is already done by it.  */
+      elf_property *prop =
+	_bfd_elf_get_property (abfd, GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4);
+      prop->u.number |= gnu_property_aarch64_features;
+      prop->pr_kind = property_number;
+    }
+}
+
+/* Check whether a subsection is known, and if so, whether the current
+   properties of the subsection match the expected ones.
+   Return True if the subsection is known from the backend, OR all the
+   properties of the subsection match the expected.  False otherwise.  */
+bool
+_bfd_aarch64_obj_attr_subsection_v2_match_known (struct bfd_link_info *info,
+						 bfd *abfd,
+						 obj_attr_subsection_v2 *subsec)
+{
+  const known_subsection_v2 *subsec_info =
+    identify_subsection (get_elf_backend_data (abfd), subsec->name);
+
+  bool match = true;
+  if (subsec_info == NULL)
+    return match;
+
+  if (subsec_info->encoding != subsec->encoding)
+    {
+      info->callbacks->einfo (_("%X%pB: error: encoding property of subsection "
+	"'%s' was incorrectly set. Got '%s', expected '%s'.\n"),
+	abfd, subsec->name,
+	obj_attr_encoding_v2_to_string (subsec->encoding),
+	obj_attr_encoding_v2_to_string (subsec_info->encoding));
+      match = false;
+    }
+  if (subsec_info->optional != subsec->optional)
+    {
+      info->callbacks->einfo (_("%X%pB: error: optional property of subsection "
+	"'%s' was incorrectly set. Got '%s', expected '%s'.\n"),
+	abfd, subsec->name,
+	obj_attr_subsection_v2_optional_to_string (subsec->optional),
+	obj_attr_subsection_v2_optional_to_string (subsec_info->optional));
+      match = false;
+    }
+  return match;
+}
+
+/* True if the default value for the tag is managed by the backend.
+   False otherwise.  */
+bool
+_bfd_aarch64_obj_attr_v2_default_value (struct bfd_link_info *info,
+					const known_tag_v2 *tag_info,
+					obj_attr_subsection_v2 *subsec,
+					obj_attr_v2 *attr)
+{
+  (void) info;
+  (void) tag_info;
+  (void) subsec;
+  (void) attr;
+
+  /* For now, there is no default value set by the backend. The default BTI and
+     GCS values are set by the respective command-line options '-z force-bti'
+     and '-z gcs'.  */
+
+  return false;
+}
+
+/* True, the tag needs to be merged, False don't merge.  */
+obj_attr_v2_merge_result
+_bfd_aarch64_obj_attr_v2_tag_merge (struct bfd_link_info *info,
+				    bfd *abfd,
+				    obj_attr_subsection_v2 *subsec,
+				    obj_attr_v2 *lhs, obj_attr_v2 *rhs,
+				    obj_attr_v2 *frozen)
+{
+  obj_attr_v2_merge_result res = {
+    .merge = false,
+    .vals.uint_val = 0,
+    .reason = NONE,
+  };
+
+  /* No need to list required sections here, they are handled separately as
+     they require a perfect one-to-one match for all the tag values.  */
+  if (strcmp (subsec->name, "aeabi_feature_and_bits") == 0)
+    {
+      BFD_ASSERT (subsec->encoding == ULEB128 && subsec->optional);
+      const known_tag_v2 *tag_info =
+	known_obj_attr_v2_find_by_tag (get_elf_backend_data (abfd),
+	  subsec->name, lhs->tag);
+      if (tag_info == NULL)
+	{
+	  info->callbacks->einfo (_("%pB: warning: cannot merge unknown tag "
+	    "Tag_unknown_%u (=0x%x) in subsection '%s'.\n"), abfd, rhs->tag,
+	    rhs->vals.uint_val, subsec->name);
+	  res.reason = UNSUPPORTED;
+	  return res;
+	}
+
+      /* For now, there is no different between the tags of this section, all
+	 will be merged in the same way.  */
+      res = obj_attr_v2_tag_merge_AND (info, abfd, subsec, lhs, rhs, frozen);
+
+      const aarch64_protection_opts *sw_protections
+	= &elf_aarch64_tdata (info->output_bfd)->sw_protections;
+      aarch64_feature_marking_report bti_report = sw_protections->bti_report;
+      aarch64_feature_marking_report gcs_report = sw_protections->gcs_report;
+
+      if ((rhs->tag == Tag_Feature_BTI) && (bti_report != MARKING_NONE)
+       && (sw_protections->plt_type & PLT_BTI) && (rhs->vals.uint_val == 0))
+	_bfd_aarch64_elf_check_bti_report (info, abfd);
+
+      if ((rhs->tag == Tag_Feature_GCS) && (gcs_report != MARKING_NONE)
+       && (sw_protections->gcs_type == GCS_ALWAYS) && (rhs->vals.uint_val == 0))
+	_bfd_aarch64_elf_check_gcs_report (info, abfd);
+
+      /* Make sure that frozen bits don't disappear from REF when it will be
+	 compared to the next file.  */
+      if (frozen != NULL)
+	res.vals.uint_val |= frozen->vals.uint_val;
+    }
+  else
+    res.reason = UNSUPPORTED;
+
+  return res;
+}
+
+static bool
+aarch64_check_pauthabi_attributes (struct bfd_link_info *info)
+{
+  /* The subsection "aeabi_pauthabi" contains information about the Pointer
+     Authentication Signing schema when the object uses an extension to ELF,
+     PAUTHABI64, which is currently not supported by GCC toolchain. The pointers
+     that are signed as well as the modifiers and key used for each type of
+     pointer are known as the signing schema.
+     The AEABI Build attributes specification defines the following tuple values
+     of (Tag_Pauth_Platform, Tag_Pauth_Schema):
+       - The tuple (0, 0) is obtained when both attributes are explicitly set to
+	 0 or are implicitly set to 0 due to the rules for setting default values
+	 for public tags. This represents an ELF file which makes no use of the
+	 PAuthABI extension.
+       - The tuple (0, 1) is reserved for the "Invalid" platform. ELF files with
+	 an "Invalid" platform are incompatible with the PAuth ABI Extension.
+       - The tuples (0, N) where N > 1 are reserved.
+       - The tuples (M, N) where M is the id of one of the registered platforms
+	 defined in PAuthABI64, represents a valid signing schema. (M, 0)
+	 represents a schema version of 0 for platform M.
+     Given that the GNU linker does not support PAuthABI, it cannot do anything
+     with values others than (0, 0) or (0, 1).
+     The check below enforces either that the output object has either no
+     subsection "aeabi_pauthabi", or the tuple is set to (0, 0) and (0, 1).  */
+
+  obj_attr_subsection_v2 *subsecs =
+    elf_obj_attr_subsections (info->output_bfd).first_;
+  obj_attr_subsection_v2 *subsec =
+    obj_attr_subsection_v2_find_by_name (subsecs, "aeabi_pauthabi", true);
+  if (subsec == NULL)
+    return true;
+
+  int platform_id = 0;
+  int version_id = 0;
+
+  obj_attr_v2 *attr = obj_attr_v2_find_by_tag(subsec, Tag_PAuth_Platform, true);
+  if (attr != NULL)
+    platform_id = attr->vals.uint_val;
+
+  attr = obj_attr_v2_find_by_tag(subsec, Tag_PAuth_Schema, true);
+  if (attr != NULL)
+    version_id = attr->vals.uint_val;
+
+  if (! ((platform_id == 0 && version_id == 0)
+      || (platform_id == 0 && version_id == 1)))
+    {
+      info->callbacks->einfo (_("%Xerror: the GNU linker does not support "
+	"PAuthABI. Any value different from (platform = 0, schema = 0) or "
+	"(platform = 0, schema = 1) is not supported.\n"));
+      return false;
+    }
+
+  return true;
+}
+
+bfd *
+_bfd_aarch64_elf_link_setup_build_attributes (struct bfd_link_info *info)
+{
+  bfd *pbfd = _bfd_elf_link_setup_build_attributes (info);
+
+  /* Check PAuthABI compatibility.  */
+  if (! aarch64_check_pauthabi_attributes (info))
+    return NULL;
+
+  /* Set the flag marking whether the merge of build attributes was done so
+     that setup_gnu_properties does not raise the same errors/warning again.  */
+  elf_aarch64_tdata (info->output_bfd)->ba_merge_done = true;
+
+  return pbfd;
+}
+
 /* 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.  */
@@ -888,14 +1218,24 @@ _bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *info)
 
 	 Note: If there is no .gnu.note.property section, we might think that
 	 elf_properties (res.pbfd) is always NULL.  However, this is not always
-	 true.  In PR23900: old linkers were treating .note.gnu.property as a
-	 generic note section, so old objects might contain properties inside
-	 .note instead of .note.gnu.property. In this case, the section won't be
-	 detected but the properties are still parsed. Consequently,
-	 elf_properties (res.pbfd) is populated and different from NULL (see
-	 https://sourceware.org/bugzilla/show_bug.cgi?id=23900 for more
-	 details).  */
-      if (res.sec == NULL && elf_properties (res.pbfd) == NULL)
+	 true for the following reasons:
+	 - PR23900: old linkers were treating .note.gnu.property as a generic
+	   note section, so old objects might contain properties inside .note
+	   instead of .note.gnu.property. In this case, the section won't be
+	   detected but the properties are still parsed. Consequently,
+	   elf_properties (res.pbfd) is populated and different from NULL (see
+	   https://sourceware.org/bugzilla/show_bug.cgi?id=23900 for more
+	   details).
+	 - since the introduction of the build attributes, once the merge
+	   of the BAs is done, some of the BAs can be translated to GNU
+	   properties like GNU_PROPERTY_AARCH64_FEATURE_1_AND.  In this case,
+	   we need to check explicitly for the presence of the GNU properties
+	   that might be added by the BAs merge.  */
+      if (res.sec == NULL
+       && (elf_properties (res.pbfd) == NULL
+	|| _bfd_elf_find_property (elf_properties (res.pbfd),
+				   GNU_PROPERTY_AARCH64_FEATURE_1_AND,
+				   NULL)))
 	_bfd_aarch64_elf_create_gnu_property_section (info, res.pbfd);
 
       /* Merge the found input property with output properties. Note: if no
@@ -1110,7 +1450,8 @@ _bfd_aarch64_elf_check_bti_report (struct bfd_link_info *info, bfd *ebfd)
 {
   struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd);
 
-  if (tdata->sw_protections.bti_report == MARKING_NONE)
+  if (elf_aarch64_tdata (info->output_bfd)->ba_merge_done
+   || tdata->sw_protections.bti_report == MARKING_NONE)
     return;
 
   ++tdata->n_bti_issues;
@@ -1144,7 +1485,8 @@ _bfd_aarch64_elf_check_gcs_report (struct bfd_link_info *info, bfd *ebfd)
     }
   else
     {
-      if (tdata->sw_protections.gcs_report == MARKING_NONE)
+      if (elf_aarch64_tdata (info->output_bfd)->ba_merge_done
+       || tdata->sw_protections.gcs_report == MARKING_NONE)
 	return;
       ++tdata->n_gcs_issues;
       if (tdata->n_gcs_issues > GNU_PROPERTY_ISSUES_MAX)
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index 506f4a93c9d..c30f41b30c0 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -107,6 +107,9 @@ struct elf_aarch64_obj_tdata
   /* Software protections options.  */
   struct aarch64_protection_opts sw_protections;
 
+  /* The merge of build attributes already occured.  */
+  bool ba_merge_done;
+
   /* Number of reported BTI issues.  */
   int n_bti_issues;
 
@@ -209,6 +212,39 @@ _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 const known_subsection_v2 aarch64_obj_attr_v2_known_subsections[];
+
+extern bfd *
+_bfd_aarch64_elf_link_setup_build_attributes (struct bfd_link_info *);
+
+extern void
+_bfd_aarch64_record_obj_attr_v2 (obj_attr_subsection_v2 *, Tag_Feature_XXX,
+  uint32_t);
+
+extern void
+_bfd_aarch64_translate_relevant_gnu_props_to_obj_attrs (bfd *,
+  elf_property_list *);
+
+extern void
+_bfd_aarch64_translate_relevant_obj_attrs_to_gnu_props (bfd *,
+  obj_attr_subsection_v2 *);
+
+extern bool
+_bfd_aarch64_obj_attr_subsection_v2_match_known (struct bfd_link_info *,
+						 bfd *,
+						 obj_attr_subsection_v2 *);
+
+extern bool
+_bfd_aarch64_obj_attr_v2_default_value (struct bfd_link_info *,
+					const known_tag_v2 *,
+					obj_attr_subsection_v2 *,
+					obj_attr_v2 *);
+
+extern obj_attr_v2_merge_result
+_bfd_aarch64_obj_attr_v2_tag_merge (struct bfd_link_info *, bfd *,
+				    obj_attr_subsection_v2 *, obj_attr_v2 *,
+				    obj_attr_v2 *, obj_attr_v2 *);
+
 extern bfd *
 _bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *);
 
-- 
2.49.0



More information about the Binutils mailing list