[PATCH v9 14/19] aarch64: merge of Object Attributes v2 during linkage

Matthieu Longo matthieu.longo@arm.com
Mon Sep 1 16:56:21 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 |  87 +++++++++-
 bfd/elfxx-aarch64.c | 390 ++++++++++++++++++++++++++++++++++++++++++--
 bfd/elfxx-aarch64.h |  33 ++++
 3 files changed, 492 insertions(+), 18 deletions(-)

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 6ef106822a8..feae7b079a6 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -5031,27 +5031,51 @@ 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 (xstrdup ("aeabi_feature_and_bits"),
+					    OA_SUBSEC_PUBLIC, true,
+					    OA_ENC_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_oav2_record (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;
+      _bfd_aarch64_oav2_record (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;
+      _bfd_aarch64_oav2_record (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
@@ -10416,7 +10440,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)
 {
@@ -10536,6 +10561,42 @@ 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 doesn'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->val.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.  */
@@ -10551,7 +10612,7 @@ elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info)
      outprop 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.  */
-  struct elf_aarch64_obj_tdata * tdata = elf_aarch64_tdata (info->output_bfd);
+  struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd);
   uint32_t outprop = tdata->gnu_property_aarch64_feature_1_and;
   if (outprop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
     tdata->sw_protections.plt_type |= PLT_BTI;
@@ -10753,9 +10814,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_oav2_subsection_match_known
+
+#define elf_backend_obj_attr_v2_default_value	\
+  _bfd_aarch64_oav2_default_value
+
+#define elf_backend_obj_attr_v2_merge	\
+  _bfd_aarch64_oav2_attr_merge
+
 #define elf_backend_merge_gnu_properties	\
   elfNN_aarch64_merge_gnu_properties
 
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 80052316ed1..d7730c946c0 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -946,6 +946,355 @@ const known_subsection_v2 aarch64_obj_attr_v2_known_subsections[2] =
   },
 };
 
+/* Record the pair (TAG, VALUE) into SUBSEC.  */
+void
+_bfd_aarch64_oav2_record (obj_attr_subsection_v2 *subsec,
+			  Tag_Feature_Set 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);
+}
+
+/* Wrapper around the recording of the pair (TAG, VALUE) into SUBSEC called from
+   a context of translation from GNU properties.  */
+static void
+obj_attr_v2_record_tag_value (obj_attr_subsection_v2 *subsec,
+			      Tag_Feature_Set tag,
+			      bool value)
+{
+  obj_attr_v2 *attr;
+  attr = obj_attr_v2_find_by_tag (subsec, tag, false);
+  if (attr != NULL)
+    {
+      if (attr->val.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->val.uint_val | value;
+	  _bfd_aarch64_oav2_record (subsec, tag, merged_val);
+	}
+      /* else: nothing to do.  */
+    }
+  else
+    _bfd_aarch64_oav2_record (subsec, tag, value);
+}
+
+/* Translate the relevant GNU properties in P to their Object Attributes v2
+   equivalents.  */
+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
+	    (xstrdup ("aeabi_feature_and_bits"), OA_SUBSEC_PUBLIC, true,
+	     OA_ENC_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);
+    }
+}
+
+/* Translate relevant Object Attributes v2 in SUBSEC to GNU properties.  */
+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->val.uint_val == 1)
+	    gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+	  else if (attr->tag == Tag_Feature_PAC && attr->val.uint_val == 1)
+	    gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
+	  else if (attr->tag == Tag_Feature_GCS && attr->val.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_oav2_subsection_match_known (struct bfd_link_info *info,
+					  bfd *abfd,
+					  obj_attr_subsection_v2 *subsec)
+{
+  const known_subsection_v2 *subsec_info
+    = obj_attr_v2_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: <%s> property of subsection '%s' was "
+	   "incorrectly set.  Got '%s', expected '%s'\n"),
+	 abfd, "encoding", subsec->name,
+	 oav2_encoding_to_string (subsec->encoding),
+	 oav2_encoding_to_string (subsec_info->encoding));
+      match = false;
+    }
+  if (subsec_info->optional != subsec->optional)
+    {
+      info->callbacks->einfo
+	(_("%X%pB: error: <%s> property of subsection '%s' was "
+	   "incorrectly set.  Got '%s', expected '%s'\n"),
+	 abfd, "comprehension", subsec->name,
+	 oav2_comprehension_to_string (subsec->optional),
+	 oav2_comprehension_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_oav2_default_value (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+				 const obj_attr_info_t *tag_info ATTRIBUTE_UNUSED,
+				 obj_attr_subsection_v2 *subsec ATTRIBUTE_UNUSED,
+				 obj_attr_v2 *attr ATTRIBUTE_UNUSED)
+{
+  /* 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;
+}
+
+/* Merge the values from LHS, RHS, FROZEN, and return the merge result.  LHS,
+   RHS and FROZEN correspond to an attribute from SUBSEC with the same tag, but
+   from three different contexts:
+    - LHS corresponds to the global merge result.
+    - RHS corresponds to the new value that is merged into the global merge
+      result.
+    - FROZEN corresponds to the value coming from some configuration context
+      (usually a command-line option) and which is immutable for the whole
+      merge process.  */
+obj_attr_v2_merge_result
+_bfd_aarch64_oav2_attr_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,
+    .val.uint_val = 0,
+    .reason = MERGE_OK,
+  };
+
+  /* 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 == OA_ENC_ULEB128 && subsec->optional);
+      const obj_attr_info_t *attr_info
+	= obj_attr_v2_find_known_by_tag (get_elf_backend_data (abfd),
+					 subsec->name, lhs->tag);
+      if (attr_info == NULL)
+	{
+	  info->callbacks->einfo
+	    (_("%pB: warning: cannot merge unknown tag 'Tag_unknown_%u' "
+	       "(=0x%x) in subsection '%s'.\n"),
+	     abfd, rhs->tag, rhs->val.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_merge_policy_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->val.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->val.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.val.uint_val |= frozen->val.uint_val;
+    }
+  else
+    res.reason = UNSUPPORTED;
+
+  return res;
+}
+
+/* Check for incompatibilities with PAuthABI attributes.  */
+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 today only supported by LLVM, and not supported by
+     GCC 15 toolchain or ealier ones.  There is no plan to add support for it
+     in the future.  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->val.uint_val;
+
+  attr = obj_attr_v2_find_by_tag (subsec, Tag_PAuth_Schema, true);
+  if (attr != NULL)
+    version_id = attr->val.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;
+}
+
+/* Merge the AEABI Build Attributes present in the input BFDs, raise any
+   compatibility issue, and write the merge result to OBFD.
+
+   AArch64 backend declares two 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 incompatibi-
+    -lities in shared objects might be a future work to bring it in pair with
+    thenGNU 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 *
+_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.  */
@@ -966,22 +1315,32 @@ _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
 	 property was found, _bfd_elf_get_property will create one.  */
-      elf_property *prop =
-	_bfd_elf_get_property (res.pbfd,
-			       GNU_PROPERTY_AARCH64_FEATURE_1_AND,
-			       4);
+      elf_property *prop
+	= _bfd_elf_get_property (res.pbfd,
+				 GNU_PROPERTY_AARCH64_FEATURE_1_AND,
+				 4);
 
       /* Check for a feature mismatch and report issue (if any) before this
 	 information get lost as the value of ebfd will be overriden with
@@ -1180,7 +1539,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;
@@ -1198,6 +1558,7 @@ _bfd_aarch64_elf_check_bti_report (struct bfd_link_info *info, bfd *ebfd)
   info->callbacks->einfo (msg, ebfd);
 }
 
+/* Check AArch64 GCS report.  */
 void
 _bfd_aarch64_elf_check_gcs_report (struct bfd_link_info *info, bfd *ebfd)
 {
@@ -1214,7 +1575,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 32964677fbd..f3c91ce43ba 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;
 
@@ -242,6 +245,36 @@ _bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t);
 
 extern const known_subsection_v2 aarch64_obj_attr_v2_known_subsections[2];
 
+extern bfd *
+_bfd_aarch64_elf_link_setup_build_attributes (struct bfd_link_info *);
+
+extern void
+_bfd_aarch64_oav2_record (obj_attr_subsection_v2 *, Tag_Feature_Set, 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_oav2_subsection_match_known (struct bfd_link_info *,
+					  bfd *,
+					  obj_attr_subsection_v2 *);
+
+extern bool
+_bfd_aarch64_oav2_default_value (struct bfd_link_info *,
+				 const obj_attr_info_t *,
+				 obj_attr_subsection_v2 *,
+				 obj_attr_v2 *);
+
+extern obj_attr_v2_merge_result
+_bfd_aarch64_oav2_attr_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.51.0



More information about the Binutils mailing list