@@ -5023,27 +5023,54 @@ 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",
+ SUBSEC_PUBLIC, true, 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_record_obj_attr_v2 (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;
+ {
+ elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
+ |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+ _bfd_aarch64_record_obj_attr_v2 (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;
+ {
+ elf_aarch64_tdata (output_bfd)->gnu_property_aarch64_feature_1_and
+ &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+ _bfd_aarch64_record_obj_attr_v2 (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
@@ -10395,7 +10422,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)
{
@@ -10515,6 +10543,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);
+
+ /* 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 don't have any effect on plt_type.
+ Whereas if BTI is inferred from the input bfds, information flows from
+ output build attributes to plt_type. If the property GNU_PROPERTY_AARCH64
+ _FEATURE_1_BTI has been set on all the input bfds, then BTI is set on the
+ output bfd and plt_type is updated accordingly.
+
+ Important note: this is not true for GNU_PROPERTY_AARCH64_FEATURE_1_PAC.
+ See more explanation in bfd_elfNN_aarch64_set_options. */
+ obj_attr_subsection_v2 *aeabi_feature_and_bits_subsec =
+ obj_attr_subsection_v2_find_by_name (
+ elf_obj_attr_subsections (info->output_bfd).first_,
+ "aeabi_feature_and_bits", true);
+ if (aeabi_feature_and_bits_subsec != NULL)
+ {
+ obj_attr_v2 *attr_bti = obj_attr_v2_find_by_tag
+ (aeabi_feature_and_bits_subsec, Tag_Feature_BTI, true);
+ if (attr_bti && attr_bti->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. */
@@ -10732,9 +10795,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_obj_attr_subsection_v2_match_known
+
+#define elf_backend_obj_attr_v2_default_value \
+ _bfd_aarch64_obj_attr_v2_default_value
+
+#define elf_backend_obj_attr_v2_tag_merge \
+ _bfd_aarch64_obj_attr_v2_tag_merge
+
#define elf_backend_merge_gnu_properties \
elfNN_aarch64_merge_gnu_properties
@@ -10775,6 +10856,12 @@ const struct elf_size_info elfNN_aarch64_size_info =
#define elf_backend_obj_attrs_section_type SHT_AARCH64_ATTRIBUTES
#undef elf_backend_obj_attrs_version
#define elf_backend_obj_attrs_version 2
+/* Object attributes v2 specific values. */
+#undef elf_backend_obj_attr_v2_known_subsections
+#define elf_backend_obj_attr_v2_known_subsections \
+ aarch64_obj_attr_v2_known_subsections
+#undef elf_backend_obj_attr_v2_known_subsections_size
+#define elf_backend_obj_attr_v2_known_subsections_size 2
#include "elfNN-target.h"
@@ -21,6 +21,7 @@
#include "sysdep.h"
#include "bfd.h"
#include "elf-bfd.h"
+#include "elf/aarch64.h"
#include "elfxx-aarch64.h"
#include "libbfd.h"
#include <stdarg.h>
@@ -868,6 +869,279 @@ _bfd_aarch64_elf_check_gnu_properties_linked_dynamic_objects (
pbfd);
}
+/* Note: this array has to be sorted. */
+static const known_tag_v2 known_tags_aeabi_feature_and_bits [] =
+{
+ {Tag_Feature_BTI, OBJ_ATTR_TAG_v2(Feature_BTI), .default_value.uint_val = 0},
+ {Tag_Feature_PAC, OBJ_ATTR_TAG_v2(Feature_PAC), .default_value.uint_val = 0},
+ {Tag_Feature_GCS, OBJ_ATTR_TAG_v2(Feature_GCS), .default_value.uint_val = 0},
+};
+/* 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. */
+static const known_tag_v2 known_tags_aeabi_pauthabi [] =
+{
+ {Tag_PAuth_Platform, OBJ_ATTR_TAG_v2(PAuth_Platform), .default_value.uint_val = 0},
+ {Tag_PAuth_Schema, OBJ_ATTR_TAG_v2(PAuth_Schema), .default_value.uint_val = 0},
+};
+
+/* Note: this array is exported by the backend, and needs to be sorted. */
+const known_subsection_v2 aarch64_obj_attr_v2_known_subsections[] =
+{
+ {
+ .subsec_name = "aeabi_feature_and_bits",
+ .known_tags = known_tags_aeabi_feature_and_bits,
+ .optional = true,
+ .encoding = ULEB128,
+ .len = sizeof (known_tags_aeabi_feature_and_bits) / sizeof (known_tag_v2),
+ },
+ {
+ .subsec_name = "aeabi_pauthabi",
+ .known_tags = known_tags_aeabi_pauthabi,
+ .optional = false,
+ .encoding = ULEB128,
+ .len = sizeof (known_tags_aeabi_pauthabi) / sizeof (known_tag_v2),
+ },
+};
+
+void
+_bfd_aarch64_record_obj_attr_v2 (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);
+}
+
+/* Translate the relevant GNU properties to object attributes v2. */
+void
+_bfd_aarch64_translate_relevant_gnu_props_to_obj_attrs (
+ bfd *abfd,
+ elf_property_list *p)
+{
+ void
+ _record_tag_value (obj_attr_subsection_v2 *subsec,
+ Tag_Feature_XXX tag,
+ bool value)
+ {
+ obj_attr_v2 *attr;
+ attr = obj_attr_v2_find_by_tag (subsec, tag, false);
+ if (attr != NULL)
+ {
+ if (attr->vals.uint_val != value)
+ {
+ /* translate_relevant_gnu_props_to_obj_attrs is only called when
+ parsing .note.gnu.property section, and this happens before the
+ parsing of the build attributes.
+ 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 case 2 occurs. */
+ uint32_t merged_val = attr->vals.uint_val | value;
+ _bfd_aarch64_record_obj_attr_v2 (subsec, tag, merged_val);
+ }
+ // else: nothing to do
+ }
+ else
+ _bfd_aarch64_record_obj_attr_v2 (subsec, tag, value);
+ }
+
+ 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", SUBSEC_PUBLIC, true, 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;
+
+ _record_tag_value (subsec, Tag_Feature_BTI, bti_bit);
+ _record_tag_value (subsec, Tag_Feature_PAC, pac_bit);
+ _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);
+ }
+}
+
+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_obj_attr_subsection_v2_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));
+ 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));
+ match = false;
+ }
+ return match;
+}
+
+/* True if the default value for the tag is managed by the backend.
+ False otherwise. */
+bool
+_bfd_aarch64_obj_attr_v2_default_value (struct bfd_link_info *info,
+ const known_tag_v2 *tag_info,
+ obj_attr_subsection_v2 *subsec,
+ obj_attr_v2 *attr)
+{
+ (void) info;
+ (void) tag_info;
+ (void) subsec;
+ (void) attr;
+
+ /* 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;
+}
+
+/* True, the tag needs to be merged, False don't merge. */
+obj_attr_v2_merge_result
+_bfd_aarch64_obj_attr_v2_tag_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 = NONE,
+ };
+
+ /* 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 == ULEB128 && subsec->optional);
+ const known_tag_v2 *tag_info =
+ known_obj_attr_v2_find_by_tag (get_elf_backend_data (abfd),
+ subsec->name, lhs->tag);
+ 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))
+ _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;
+}
+
+bfd *
+_bfd_aarch64_elf_link_setup_build_attributes (struct bfd_link_info *info)
+{
+ bfd *pbfd = _bfd_elf_link_setup_build_attributes (info);
+
+ /* 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. */
@@ -888,14 +1162,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)))
_bfd_aarch64_elf_create_gnu_property_section (info, res.pbfd);
/* Merge the found input property with output properties. Note: if no
@@ -1110,7 +1394,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;
@@ -1144,7 +1429,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)
@@ -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;
@@ -209,6 +212,39 @@ _bfd_aarch64_elf_write_core_note (bfd *, char *, int *, int, ...);
#define elf_backend_grok_psinfo _bfd_aarch64_elf_grok_psinfo
#define elf_backend_write_core_note _bfd_aarch64_elf_write_core_note
+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_record_obj_attr_v2 (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_obj_attr_subsection_v2_match_known (struct bfd_link_info *,
+ bfd *,
+ obj_attr_subsection_v2 *);
+
+extern bool
+_bfd_aarch64_obj_attr_v2_default_value (struct bfd_link_info *,
+ const known_tag_v2 *,
+ obj_attr_subsection_v2 *,
+ obj_attr_v2 *);
+
+extern obj_attr_v2_merge_result
+_bfd_aarch64_obj_attr_v2_tag_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 *);