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

Matthieu Longo matthieu.longo@arm.com
Thu Jul 10 15:48:17 GMT 2025


On 2025-07-10 15:05, Richard Earnshaw (lists) wrote:
> 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.

I fixed all the above mentioned issues in the next revision.

Matthieu


More information about the Binutils mailing list