This patch lays the groundwork for the support of Object Attributes v2 (OAv2).
OAv2 is an enhancement of OAv1. They retain successful aspects of OAv1, define
the relationship between object attributes and existing GNU properties, separate
architectural requirements from software ABI requirements, and simplify the
format to make it easier for OAv2 consumers to parse, and skip subsections and
attributes. Interestingly, OAv2 have only one scope: the whole relocatable file
where they were specified. For the reason behind this choice, see [1], "Build
attributes at file scope only". This document also provides more insights into
the design rationale for OAv2.
Even if OAv2 was designed primarily for AArch64, this implementation splits the
generic core logic from the backend-specific one, and aims at facilitating OAv2
adoption by others backend. This logic will apply for any subsequent OAv2 patch.
New abstractions for attributes and subsections are introduced in bfd/elf-attrs.h
Those align with the format of OAv2 proposed in [2].
An object attribute obj_attr_v2 is a tag-value pair:
- tag: a key, i.e. a unique identifier for the attribute in the
subsection.
- value: a variant for which the interpretation depends on the encoding
set in the subsection it was stored in. 2 types of values are possible:
ULEB128 (Unsigned Little Endian Base 128) or a string encoded as NTBS
(Null-Terminated Byte String).
A subsection obj_attr_subsection_v2 has the following members:
- name: the name of this subsection.
- scope: the prefix in the subsection name determines whether the
subsection is public or private.
- optionality: is this subsection optional or required ? Depending on
whether the subsection is public or private, it can be ignored by the
consumer.
- encoding: see previous note regarding the value of an attribute. This
encoding applies to all the attributes in this subsection.
- list of object attributes.
Even if OAv1 and OAv2 data structures are similar, their processing is
different. Thus refactoring the code of OAv1 and OAv2 to share it does not
seem the right approach for clarity and maintainability, and minimalization
of the risk of introducing regressions.
Consequently, utility functions to initialize, copy, swap, free, compare,
mutate, and sort those structures won't be shared between OAv1 and OAv2.
Finally, the version ID used to identify the storage format of the object
attributes is object and backend dependent. This approach allows mixing
OAv1 and OAv2 in input objects. Then the deserializer translates the input
data to the internal model (currently OAv2, but it could be a more generic
one in the future) to perform the merge. In the end, the output format is
set by the backend: OAv2 for AArch64, OAv1 for others. The only exception
for this is objcopy, which won't change the format of the object attributes,
and will preserve the format of the data during the copy.
Hopefully, this mechanism will make easy the migration from OAv1 to OAv2 if
anyone is interested.
[1]: [Design Rationale for Build Attributes for the Arm 64-bit Architecture (AARCH64)]
(https://github.com/ARM-software/abi-aa/blob/
eec881270d5e3b23e58a6250640d06ff545ec1fc
/design-documents/buildattr64-rationale.rst)
[2]: [Build Attributes for the Arm® 64-bit Architecture (AArch64)](https://github.com
/ARM-software/abi-aa/blob/
eec881270d5e3b23e58a6250640d06ff545ec1fc/buildattr64
/buildattr64.rst)
Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
elf32-metag.h elf32-nds32.h elf32-ppc.h \
elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
- elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
+ elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
elf-linux-core.h elf-s390.h elf-vxworks.h \
elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
elf32-metag.h elf32-nds32.h elf32-ppc.h \
elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
- elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
+ elf64-hppa.h elf64-ppc.h elf64-tilegx.h elf-attrs.h \
elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
elf-linux-core.h elf-s390.h elf-vxworks.h \
elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
#include "sysdep.h"
#include "bfd.h"
+#include "doubly-linked-list.h"
#include "libiberty.h"
#include "libbfd.h"
#include "elf-bfd.h"
+/* Decode the encoded version number corresponding to the Object Attribute
+ version. Return the version on success, UNSUPPORTED on failure. */
+obj_attr_version_t
+_bfd_obj_attrs_version_dec (uint8_t encoded_version)
+{
+ if (encoded_version == 'A')
+ return OBJ_ATTR_V1;
+ return OBJ_ATTR_VERSION_UNSUPPORTED;
+}
+
+/* Encode the Object Attribute version into a byte. */
+uint8_t
+_bfd_obj_attrs_version_enc (obj_attr_version_t version)
+{
+ if (version == OBJ_ATTR_V1)
+ return 'A';
+ abort ();
+}
+
/* Return the number of bytes needed by I in uleb128 format. */
static uint32_t
uleb128_size (uint32_t i)
static void
write_obj_attr_section_v1 (bfd *abfd, bfd_byte *buffer, bfd_vma size)
{
+ /* This function should only be called for object attributes version 1. */
+ BFD_ASSERT (elf_obj_attr_version (abfd) == OBJ_ATTR_V1);
+
bfd_byte *p = buffer;
- /* <format-version: ‘A’> */
- *(p++) = 'A';
+ const struct elf_backend_data *be = get_elf_backend_data (abfd);
+ /* <format-version: uint8> */
+ *(p++) = be->obj_attrs_version_enc (elf_obj_attr_version (abfd));
for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor)
{
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return;
+ obj_attr_version_t version = elf_obj_attr_version (ibfd);
+ elf_obj_attr_version (obfd) = version;
+
+ if (version == OBJ_ATTR_VERSION_NONE)
+ return;
+
for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
{
in_attr
obj_attr_vendor_t vendor,
obj_attr_tag_t tag)
{
+ /* This function should only be called for object attributes version 1. */
+ BFD_ASSERT (elf_obj_attr_version (abfd) == OBJ_ATTR_V1);
switch (vendor)
{
case OBJ_ATTR_PROC:
void
_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
{
+ elf_obj_attr_version (abfd) = OBJ_ATTR_VERSION_NONE;
+
/* PR 17512: file: 2844a11d. */
if (hdr->sh_size == 0)
return;
unsigned char *cursor = data;
- /* The first character is the version of the attributes.
- Currently only version 'A' is recognised here. */
- if (*cursor != 'A')
+ /* The first character is the version of the attributes. */
+ obj_attr_version_t version
+ = get_elf_backend_data (abfd)->obj_attrs_version_dec (*cursor);
+ if (version == OBJ_ATTR_VERSION_UNSUPPORTED || version > OBJ_ATTR_VERSION_MAX)
{
- _bfd_error_handler (_("%pB: error: unknown attributes version '%c'(%d) "
- "- expecting 'A'\n"), abfd, *cursor, *cursor);
+ _bfd_error_handler (_("%pB: error: unknown attributes version '%c'(%d)\n"),
+ abfd, *cursor, *cursor);
bfd_set_error (bfd_error_wrong_format);
goto free_data;
}
++cursor;
+ elf_obj_attr_version (abfd) = version;
bfd_elf_parse_attr_section_v1 (abfd, cursor, data + hdr->sh_size);
free_data:
obj_attribute *out_attr;
int vendor;
+ /* Set the object attribute version for the output object to the recommended
+ value by the backend. */
+ elf_obj_attr_version (obfd)
+ = get_elf_backend_data (obfd)->default_obj_attr_version;
+
/* The only common attribute is currently Tag_compatibility,
accepted in both processor and "gnu" sections. */
for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
return result;
}
+/* Create a new object attribute with key TAG and value VAL.
+ Return a pointer to it. */
+
+obj_attr_v2_t *
+bfd_elf_obj_attr_v2_init (obj_attr_tag_t tag,
+ union obj_attr_value_v2 val)
+{
+ obj_attr_v2_t *attr = XCNEW (obj_attr_v2_t);
+ attr->tag = tag;
+ attr->val = val;
+ return attr;
+}
+
+/* Free memory allocated by the object attribute ATTR. */
+
+void
+_bfd_elf_obj_attr_v2_free (obj_attr_v2_t *attr, obj_attr_encoding_v2_t encoding)
+{
+ if (encoding == OA_ENC_NTBS)
+ /* Note: this field never holds a string literal. */
+ free ((char *) attr->val.string);
+ free (attr);
+}
+
+/* Copy an object attribute OTHER, and return a pointer to the copy. */
+
+obj_attr_v2_t *
+_bfd_elf_obj_attr_v2_copy (const obj_attr_v2_t *other,
+ obj_attr_encoding_v2_t encoding)
+{
+ union obj_attr_value_v2 val;
+ if (encoding == OA_ENC_NTBS)
+ val.string
+ = (other->val.string != NULL
+ ? xstrdup (other->val.string)
+ : NULL);
+ else if (encoding == OA_ENC_ULEB128)
+ val.uint = other->val.uint;
+ else
+ abort ();
+
+ return bfd_elf_obj_attr_v2_init (other->tag, val);
+}
+
+/* Compare two object attributes based on their TAG value only (partial
+ ordering), and return an integer indicating the result of the comparison,
+ as follows:
+ - 0, if A1 and A2 are equal.
+ - a negative value if A1 is less than A2.
+ - a positive value if A1 is greater than A2. */
+
+int
+_bfd_elf_obj_attr_v2_cmp (const obj_attr_v2_t *a1, const obj_attr_v2_t *a2)
+{
+ if (a1->tag < a2->tag)
+ return -1;
+ if (a1->tag > a2->tag)
+ return 1;
+ return 0;
+}
+
+/* Return an object attribute in SUBSEC matching TAG or NULL if one is not
+ found. SORTED specifies whether the given list is ordered by tag number.
+ This allows an early return if we find a higher numbered tag. */
+
+obj_attr_v2_t *
+_bfd_obj_attr_v2_find_by_tag (const obj_attr_subsection_v2_t *subsec,
+ obj_attr_tag_t tag,
+ bool sorted)
+{
+ for (obj_attr_v2_t *attr = subsec->first;
+ attr != NULL;
+ attr = attr->next)
+ {
+ if (attr->tag == tag)
+ return attr;
+ if (sorted && attr->tag > tag)
+ break;
+ }
+ return NULL;
+}
+
+/* Sort the object attributes inside a subsection.
+ Note: since a subsection is a list of attributes, the sorting algorithm is
+ implemented with a merge sort.
+ See more details in libiberty/doubly-linked-list.h */
+
+LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_v2_t,
+ obj_attr_v2_t, /* extern */)
+LINKED_LIST_MERGE_SORT_DECL (obj_attr_subsection_v2_t,
+ obj_attr_v2_t, /* extern */)
+
+/* Create a new object attribute subsection with the following properties:
+ - NAME: the name of the subsection. Note: this parameter never holds a
+ string literal, so the value has to be freeable.
+ - SCOPE: the scope of the subsection (public or private).
+ - OPTIONAL: whether this subsection is optional (true) or required (false).
+ - ENCODING: the expected encoding for the attributes values (ULEB128 or NTBS).
+ Return a pointer to it. */
+
+obj_attr_subsection_v2_t *
+bfd_elf_obj_attr_subsection_v2_init (const char *name,
+ obj_attr_subsection_scope_v2_t scope,
+ bool optional,
+ obj_attr_encoding_v2_t encoding)
+{
+ obj_attr_subsection_v2_t *subsection = XCNEW (obj_attr_subsection_v2_t);
+ subsection->name = name;
+ subsection->scope = scope;
+ subsection->optional = optional;
+ subsection->encoding = encoding;
+ return subsection;
+}
+
+/* Free memory allocated by the object attribute subsection SUBSEC. */
+
+void
+_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2_t *subsec)
+{
+ obj_attr_v2_t *attr = subsec->first;
+ while (attr != NULL)
+ {
+ obj_attr_v2_t *a = attr;
+ attr = attr->next;
+ _bfd_elf_obj_attr_v2_free (a, subsec->encoding);
+ }
+ /* Note: this field never holds a string literal. */
+ free ((char *) subsec->name);
+ free (subsec);
+}
+
+/* Deep copy an object attribute subsection OTHER, and return a pointer to the
+ copy. */
+
+obj_attr_subsection_v2_t *
+_bfd_elf_obj_attr_subsection_v2_copy (const obj_attr_subsection_v2_t *other)
+{
+ obj_attr_subsection_v2_t *new_subsec
+ = bfd_elf_obj_attr_subsection_v2_init (xstrdup (other->name), other->scope,
+ other->optional, other->encoding);
+ for (obj_attr_v2_t *attr = other->first;
+ attr != NULL;
+ attr = attr->next)
+ {
+ obj_attr_v2_t *new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
+ LINKED_LIST_APPEND (obj_attr_v2_t) (new_subsec, new_attr);
+ }
+ return new_subsec;
+}
+
+/* Compare two object attribute subsections based on all their properties.
+ This operator can be used to obtain a total order in a collection.
+ Return an integer indicating the result of the comparison, as follows:
+ - 0, if S1 and S2 are equal.
+ - a negative value if S1 is less than S2.
+ - a positive value if S1 is greater than S2.
+
+ NB: the scope is computed from the name, so is not used for the
+ comparison. */
+
+int
+_bfd_elf_obj_attr_subsection_v2_cmp (const obj_attr_subsection_v2_t *s1,
+ const obj_attr_subsection_v2_t *s2)
+{
+ int res = strcmp (s1->name, s2->name);
+ if (res != 0)
+ return res;
+
+ /* Note: The comparison of the encoding and optionality of subsections
+ is entirely arbitrary. The numeric values could be completely flipped
+ around without any effect. Likewise, assigning higher priority to
+ optionality than to encoding is artificial. The desired properties for
+ this comparison operator are reflexivity, transitivity, antisymmetry,
+ and totality, in order to achieve a total ordering when sorting a
+ collection of subsections.
+ If the nature of this ordering were to change in the future, it would
+ have no functional impact (but e.g. testsuite expectations might still
+ need adjusting) on the final merged result in the output file. Only the
+ order of the serialized subsections would differ, which does not affect
+ the interpretation of the object attributes.
+ Similarly, the ordering of subsections and attributes in an input file
+ does not affect the merge process in ld. The merge process never assumes
+ any particular ordering from the input files, it always sorts the
+ subsections and attributes before merging. This means that using an
+ older version of gas with a newer ld is safe, and vice versa as long as
+ no new features are used that the older ld doesn't know of.
+ In conclusion, the (arbitrary) criteria used to sort subsections during
+ the merge process are entirely internal to ld and have no effect on the
+ merge result. */
+
+ if (!s1->optional && s2->optional)
+ return -1;
+ else if (s1->optional && !s2->optional)
+ return 1;
+
+ if (s1->encoding < s2->encoding)
+ return -1;
+ else if (s1->encoding > s2->encoding)
+ return 1;
+
+ return 0;
+}
+
+/* Return a subsection in the list FIRST matching NAME, or NULL if one is not
+ found. SORTED specifies whether the given list is ordered by name.
+ This allows an early return if we find a alphabetically-higher name. */
+
+obj_attr_subsection_v2_t *
+bfd_obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2_t *first,
+ const char *name,
+ bool sorted)
+{
+ for (obj_attr_subsection_v2_t *s = first;
+ s != NULL;
+ s = s->next)
+ {
+ int cmp = strcmp (s->name, name);
+ if (cmp == 0)
+ return s;
+ else if (sorted && cmp > 0)
+ break;
+ }
+ return NULL;
+}
+
+/* Sort the subsections in a vendor section.
+ Note: since a section is a list of subsections, the sorting algorithm is
+ implemented with a merge sort.
+ See more details in libiberty/doubly-linked-list.h */
+
+LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_list_t,
+ obj_attr_subsection_v2_t, /* extern */)
+LINKED_LIST_MERGE_SORT_DECL (obj_attr_subsection_list_t,
+ obj_attr_subsection_v2_t, /* extern */)
+
+/* Serialize the object attributes in ABFD into the vendor section of
+ OUTPUT_BFD. */
+
bool _bfd_elf_write_section_object_attributes
(bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
--- /dev/null
+/* ELF attributes support (based on ARM EABI attributes).
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum obj_attr_version {
+ OBJ_ATTR_VERSION_NONE = 0,
+ OBJ_ATTR_VERSION_UNSUPPORTED,
+ OBJ_ATTR_V1,
+ OBJ_ATTR_V2,
+ OBJ_ATTR_VERSION_MAX = OBJ_ATTR_V2,
+} obj_attr_version_t;
+
+/* --------------------
+ Object attributes v2
+ -------------------- */
+
+typedef enum obj_attr_encoding_v2
+{
+ OA_ENC_UNSET = 0,
+ OA_ENC_ULEB128,
+ OA_ENC_NTBS,
+ OA_ENC_MAX = OA_ENC_NTBS,
+} obj_attr_encoding_v2_t;
+
+#define obj_attr_encoding_v2_from_u8(value) \
+ ((enum obj_attr_encoding_v2) ((value) + 1))
+#define obj_attr_encoding_v2_to_u8(value) \
+ ((uint8_t) ((value) - 1))
+
+typedef union obj_attr_value_v2 {
+ uint32_t uint;
+
+ /* Note: this field cannot hold e.g. a string literal as the value has to be
+ freeable. */
+ const char *string;
+} obj_attr_value_v2_t;
+
+typedef uint64_t obj_attr_tag_t;
+
+typedef struct obj_attr_v2 {
+ /* The name/tag of an attribute. */
+ obj_attr_tag_t tag;
+
+ /* The value assigned to an attribute, can be ULEB128 or NTBS. */
+ union obj_attr_value_v2 val;
+
+ /* The next attribute in the list or NULL. */
+ struct obj_attr_v2 *next;
+
+ /* The previous attribute in the list or NULL. */
+ struct obj_attr_v2 *prev;
+} obj_attr_v2_t;
+
+typedef enum obj_attr_subsection_scope_v2
+{
+ OA_SUBSEC_PUBLIC,
+ OA_SUBSEC_PRIVATE,
+} obj_attr_subsection_scope_v2_t;
+
+typedef struct obj_attr_subsection_v2 {
+ /* The name of the subsection.
+ Note: this field cannot hold e.g. a string literal as the value has to be
+ freeable. */
+ const char *name;
+
+ /* The scope of the subsection. */
+ obj_attr_subsection_scope_v2_t scope;
+
+ /* Is this subsection optional ? Can it be skipped ? */
+ bool optional;
+
+ /* The value encoding of attributes in this subsection. */
+ obj_attr_encoding_v2_t encoding;
+
+ /* The size of the list. */
+ unsigned int size;
+
+ /* The next subsection in the list, or NULL. */
+ struct obj_attr_subsection_v2 *next;
+
+ /* The previous subsection in the list, or NULL. */
+ struct obj_attr_subsection_v2 *prev;
+
+ /* A pointer to the first node of the list. */
+ struct obj_attr_v2 *first;
+
+ /* A pointer to the last node of the list. */
+ struct obj_attr_v2 *last;
+} obj_attr_subsection_v2_t;
+
+typedef struct obj_attr_subsection_list
+{
+ /* A pointer to the first node of the list. */
+ obj_attr_subsection_v2_t *first;
+
+ /* A pointer to the last node of the list. */
+ obj_attr_subsection_v2_t *last;
+
+ /* The size of the list. */
+ unsigned int size;
+} obj_attr_subsection_list_t;
#include <stdlib.h>
+#include "doubly-linked-list.h"
#include "elf/common.h"
#include "elf/external.h"
#include "elf/internal.h"
+#include "elf-attrs.h"
#include "bfdlink.h"
#ifndef ENABLE_CHECKING
struct bfd_elf_section_reloc_data;
-typedef uint32_t obj_attr_tag_t;
-
struct elf_backend_data
{
/* The architecture for this backend. */
/* The section name to use for a processor-standard attributes section. */
const char *obj_attrs_section;
- /* Return 1, 2 or 3 to indicate what type of arguments a
- processor-specific tag takes. */
+ /* Return 1, 2 or 3 to indicate what type of arguments a tag takes. */
int (*obj_attrs_arg_type) (obj_attr_tag_t);
/* The section type to use for an attributes section. */
unsigned int obj_attrs_section_type;
+ /* The preferred version of object attributes for the output object. */
+ obj_attr_version_t default_obj_attr_version;
+
+ /* Decode the object attributes version from the version number encoded in
+ the input object. */
+ obj_attr_version_t (*obj_attrs_version_dec) (uint8_t);
+
+ /* Encode the object attributes version into the output object. */
+ uint8_t (*obj_attrs_version_enc) (obj_attr_version_t);
+
/* This function determines the order in which any attributes are
written. It must be defined for input in the range
LEAST_KNOWN_OBJ_ATTRIBUTE..NUM_KNOWN_OBJ_ATTRIBUTES-1 (this range
after all input GNU properties are merged for output. */
elf_property_list *properties;
+ /* The version of object attributes for this object.
+ For an input object, the format version used to store the data.
+ For an output object, the targeted format version. */
+ obj_attr_version_t obj_attr_version;
+
obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
obj_attribute_list *other_obj_attributes[2];
+ /* Object attributes v2: A subsection can only hold attributes with the
+ same data type (uleb128, NTBS, etc), so each type requires a separate
+ subsection. */
+ obj_attr_subsection_list_t obj_attr_subsections;
+
/* Linked-list containing information about every Systemtap section
found in the object file. Each section corresponds to one entry
in the list. */
#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab)
#define elf_flags_init(bfd) (elf_tdata(bfd) -> o->flags_init)
#define elf_use_dt_symtab_p(bfd) (elf_tdata(bfd) -> dt_symtab_count != 0)
+#define elf_obj_attr_version(bfd) (elf_tdata (bfd) -> obj_attr_version)
#define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attributes)
#define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attributes)
#define elf_known_obj_attributes_proc(bfd) \
(elf_known_obj_attributes (bfd) [OBJ_ATTR_PROC])
#define elf_other_obj_attributes_proc(bfd) \
(elf_other_obj_attributes (bfd) [OBJ_ATTR_PROC])
+#define elf_obj_attr_subsections(bfd) (elf_tdata (bfd) -> obj_attr_subsections)
#define elf_properties(bfd) (elf_tdata (bfd) -> properties)
#define elf_has_no_copy_on_protected(bfd) \
(elf_tdata(bfd) -> has_no_copy_on_protected)
int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type))
ATTRIBUTE_HIDDEN;
+extern obj_attr_version_t _bfd_obj_attrs_version_dec (uint8_t)
+ ATTRIBUTE_HIDDEN;
+extern uint8_t _bfd_obj_attrs_version_enc (obj_attr_version_t)
+ ATTRIBUTE_HIDDEN;
extern bfd_vma bfd_elf_obj_attr_size (bfd *);
extern void bfd_elf_set_obj_attr_contents (bfd *, bfd_byte *, bfd_vma);
extern obj_attribute *
extern bool _bfd_elf_read_notes
(bfd *, file_ptr, bfd_size_type, size_t) ATTRIBUTE_HIDDEN;
+extern obj_attr_v2_t *bfd_elf_obj_attr_v2_init (obj_attr_tag_t,
+ union obj_attr_value_v2) ATTRIBUTE_HIDDEN;
+extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2_t *, obj_attr_encoding_v2_t)
+ ATTRIBUTE_HIDDEN;
+extern obj_attr_v2_t *_bfd_elf_obj_attr_v2_copy (const obj_attr_v2_t *,
+ obj_attr_encoding_v2_t) ATTRIBUTE_HIDDEN;
+extern int _bfd_elf_obj_attr_v2_cmp (const obj_attr_v2_t *,
+ const obj_attr_v2_t *) ATTRIBUTE_HIDDEN;
+extern obj_attr_v2_t * _bfd_obj_attr_v2_find_by_tag
+ (const obj_attr_subsection_v2_t *, obj_attr_tag_t, bool) ATTRIBUTE_HIDDEN;
+LINKED_LIST_MUTATIVE_OPS_PROTOTYPE (obj_attr_subsection_v2_t,
+ obj_attr_v2_t, ATTRIBUTE_HIDDEN);
+LINKED_LIST_MERGE_SORT_PROTOTYPE_ (obj_attr_v2_t, ATTRIBUTE_HIDDEN);
+LINKED_LIST_MERGE_SORT_PROTOTYPE (obj_attr_subsection_v2_t,
+ obj_attr_v2_t, ATTRIBUTE_HIDDEN);
+extern obj_attr_subsection_v2_t *bfd_elf_obj_attr_subsection_v2_init
+ (const char *, obj_attr_subsection_scope_v2_t, bool, obj_attr_encoding_v2_t);
+extern void _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2_t *)
+ ATTRIBUTE_HIDDEN;
+extern obj_attr_subsection_v2_t *_bfd_elf_obj_attr_subsection_v2_copy
+ (const obj_attr_subsection_v2_t *) ATTRIBUTE_HIDDEN;
+extern int _bfd_elf_obj_attr_subsection_v2_cmp
+ (const obj_attr_subsection_v2_t *, const obj_attr_subsection_v2_t *)
+ ATTRIBUTE_HIDDEN;
+extern obj_attr_subsection_v2_t *bfd_obj_attr_subsection_v2_find_by_name
+ (obj_attr_subsection_v2_t *, const char *, bool);
+LINKED_LIST_MUTATIVE_OPS_PROTOTYPE (obj_attr_subsection_list_t,
+ obj_attr_subsection_v2_t,
+ ATTRIBUTE_HIDDEN);
+LINKED_LIST_MERGE_SORT_PROTOTYPE_ (obj_attr_subsection_v2_t, ATTRIBUTE_HIDDEN);
+LINKED_LIST_MERGE_SORT_PROTOTYPE (obj_attr_subsection_list_t,
+ obj_attr_subsection_v2_t, ATTRIBUTE_HIDDEN);
+
extern bool _bfd_elf_parse_gnu_properties
(bfd *, Elf_Internal_Note *) ATTRIBUTE_HIDDEN;
extern elf_property_list * _bfd_elf_find_property
#define elf_backend_extern_protected_data 0
#define elf_backend_hash_symbol elf_aarch64_hash_symbol
+/* In OAv2, the presence of a vendor prefix means that the contents (syntax) can
+ be fully parsed, even if the interpretation of each tag is unknown.*/
+#undef elf_backend_obj_attrs_vendor
+#define elf_backend_obj_attrs_vendor "aeabi"
#undef elf_backend_obj_attrs_section
#define elf_backend_obj_attrs_section SEC_AARCH64_ATTRIBUTES
+/* In OAv2, the type of an attribute is specified by the subsection that
+ contains it. */
+#define elf_backend_obj_attrs_arg_type NULL
+#undef elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type SHT_AARCH64_ATTRIBUTES
+#undef elf_backend_default_obj_attr_version
+#define elf_backend_default_obj_attr_version OBJ_ATTR_V2
+#undef elf_backend_obj_attrs_version_dec
+#define elf_backend_obj_attrs_version_dec \
+ _bfd_aarch64_obj_attrs_version_dec
+#undef elf_backend_obj_attrs_version_enc
+#define elf_backend_obj_attrs_version_enc \
+ _bfd_aarch64_obj_attrs_version_enc
#include "elfNN-target.h"
pbfd);
}
+/* Decode the encoded version number corresponding to the Object Attribute
+ version. Return the version on success, UNSUPPORTED on failure. */
+obj_attr_version_t
+_bfd_aarch64_obj_attrs_version_dec (uint8_t encoded_version)
+{
+ if (encoded_version == 'A')
+ return OBJ_ATTR_V2;
+ return OBJ_ATTR_VERSION_UNSUPPORTED;
+}
+
+/* Encode the Object Attribute version into a byte. */
+uint8_t
+_bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t version)
+{
+ if (version == OBJ_ATTR_V2)
+ return 'A';
+ abort ();
+}
+
/* 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. */
#define elf_backend_grok_psinfo _bfd_aarch64_elf_grok_psinfo
#define elf_backend_write_core_note _bfd_aarch64_elf_write_core_note
+extern obj_attr_version_t
+_bfd_aarch64_obj_attrs_version_dec (uint8_t) ATTRIBUTE_HIDDEN;
+
+extern uint8_t
+_bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t) ATTRIBUTE_HIDDEN;
+
extern bfd *
_bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *)
ATTRIBUTE_HIDDEN;
#define elf_backend_obj_attrs_arg_type NULL
#endif
#ifndef elf_backend_obj_attrs_section_type
-#define elf_backend_obj_attrs_section_type SHT_GNU_ATTRIBUTES
+#define elf_backend_obj_attrs_section_type SHT_GNU_ATTRIBUTES
+#endif
+#ifndef elf_backend_default_obj_attr_version
+#define elf_backend_default_obj_attr_version OBJ_ATTR_V1
+#endif
+#ifndef elf_backend_obj_attrs_version_dec
+#define elf_backend_obj_attrs_version_dec _bfd_obj_attrs_version_dec
+#endif
+#ifndef elf_backend_obj_attrs_version_enc
+#define elf_backend_obj_attrs_version_enc _bfd_obj_attrs_version_enc
#endif
#ifndef elf_backend_obj_attrs_order
#define elf_backend_obj_attrs_order NULL
#ifndef elf_backend_symbol_section_index
#define elf_backend_symbol_section_index NULL
#endif
-
+
#ifndef elf_match_priority
#define elf_match_priority \
(ELF_ARCH == bfd_arch_unknown ? 2 \
elf_backend_obj_attrs_section,
elf_backend_obj_attrs_arg_type,
elf_backend_obj_attrs_section_type,
+ elf_backend_default_obj_attr_version,
+ elf_backend_obj_attrs_version_dec,
+ elf_backend_obj_attrs_version_enc,
elf_backend_obj_attrs_order,
elf_backend_obj_attrs_handle_unknown,
elf_backend_parse_gnu_properties,
ecofflink.c
ecoffswap.h
elf-attrs.c
+elf-attrs.h
elf-bfd.h
elf-eh-frame.c
elf-hppa.h
memset (&groups, 0, sizeof (groups));
#ifdef TC_OBJ_ATTR
+ /* Set the object attribute version for the output object to the default
+ value supported by the backend. */
+ elf_obj_attr_version (stdoutput)
+ = get_elf_backend_data (stdoutput)->default_obj_attr_version;
+
oav1_attr_info_init ();
#endif /* TC_OBJ_ATTR */
}