[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