[PATCH v5 15/20] aarch64: merge of Object Attributes v2 during linkage

Richard Earnshaw (lists) Richard.Earnshaw@arm.com
Thu Jul 10 14:05:35 GMT 2025


On 07/07/2025 17:49, Matthieu Longo wrote:
> 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 |  83 +++++++++-
>  bfd/elfxx-aarch64.c | 390 ++++++++++++++++++++++++++++++++++++++++++--
>  bfd/elfxx-aarch64.h |  33 ++++
>  3 files changed, 487 insertions(+), 19 deletions(-)
> 
> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
> index 4ef18a052cd..19738763e52 100644
> --- a/bfd/elfnn-aarch64.c
> +++ b/bfd/elfnn-aarch64.c
> @@ -5026,27 +5026,50 @@ 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",
> +      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
> @@ -10398,7 +10421,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)
>  {
> @@ -10518,6 +10542,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);

No space after '*'

> +
> +  /* 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 =

'=' goes on the following line with the call.

There are other instances of this elsewhere in this patch that also need fixing.

> +    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);

Break the line before the '='. You should then have enough space to put at least one parameter on the same line as the function name itself.

     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.  */
> @@ -10735,9 +10794,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_tag_merge	\
> +  _bfd_aarch64_oav2_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 2d738bbe47a..f7d649330fa 100644
> --- a/bfd/elfxx-aarch64.c
> +++ b/bfd/elfxx-aarch64.c
> @@ -888,7 +888,8 @@ _bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t version)
>    abort ();
>  }
>  
> -/* Note: this array has to be sorted.  */
> +/* List of known tags in the subsection "aeabi_feature_and_bits".
> +   Note: the array below needs to be sorted.  */
>  static const obj_attr_info_t known_tags_aeabi_feature_and_bits [] =
>  {
>    {
> @@ -917,10 +918,12 @@ static const obj_attr_info_t known_tags_aeabi_feature_and_bits [] =
>    },
>  };
>  
> -/* 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.  */
> +/* List of known tags in the subsection "aeabi_pauthabi".
> +   Notes:
> +   - "aeabi_pauthabi" 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.
> +   - the array below needs to be sorted.  */
>  static const obj_attr_info_t known_tags_aeabi_pauthabi [] =
>  {
>    {
> @@ -941,7 +944,8 @@ static const obj_attr_info_t known_tags_aeabi_pauthabi [] =
>    },
>  };
>  
> -/* Note: this array is exported by the backend, and needs to be sorted.  */
> +/* List of known subsections.
> +   Note: this array is exported by the backend, and needs to be sorted.  */
>  const known_subsection_v2 aarch64_obj_attr_v2_known_subsections[] =
>  {
>    {
> @@ -960,6 +964,347 @@ const known_subsection_v2 aarch64_obj_attr_v2_known_subsections[] =
>    },
>  };
>  
> +/* Record the pair (TAG, VALUE) into SUBSEC.  */
> +void
> +_bfd_aarch64_oav2_record (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);
> +}
> +
> +/* 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_XXX tag,
> +		   bool value)

Indentation.

> +{
> +  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_oav2_record (subsec, tag, merged_val);
> +	}
> +      // else: nothing to do

Please use traditional C-style comments.

> +    }
> +  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 (
> +	    "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->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_oav2_subsection_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));

Indentation.

> +      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));

And again.  In fact, there are several more instances of this that need fixing.

> +      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 key, 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_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 = 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 *tag_info =
> +	known_obj_attr_v2_find_by_tag (get_elf_backend_data (abfd),
> +	  subsec->name, lhs->tag);

indentation.

> +      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))

Indentation.  With so many clauses, I think it's worth having one per line:

      if (A == P
          && B != Q
          && (C & R)  // Note: needs parenthesis
          && D == S)
There's no need for extra parenthesis in this case unless it really helps to
clarify the binding.
 
> +	_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;
> +}
> +
> +/* 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 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;
> +}
> +
> +/* 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.  */
> @@ -980,14 +1325,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)))

The '||' is a subclause of the '&&' so should be indented to the parentheis level:
   if (A == NULL
       && (B == NULL
           || _func (a, b,
                     c)))


>  	_bfd_aarch64_elf_create_gnu_property_section (info, res.pbfd);
>  
>        /* Merge the found input property with output properties. Note: if no
> @@ -1194,7 +1549,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;
> @@ -1212,6 +1568,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)
>  {
> @@ -1228,7 +1585,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 92b60439f6d..e871ff7db76 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;
>  
> @@ -217,6 +220,36 @@ _bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t);
>  
>  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_oav2_record (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_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_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 *);
>  

Please go through this patch again and fix the various indentation issues.  I've only highlighted a few of the issues to avoid undue repetition.

R.


More information about the Binutils mailing list