[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