[PATCH v10 05/28] Object Attributes v2: new abstractions for subsections and attributes
Jan Beulich
jbeulich@suse.com
Fri Nov 28 13:30:45 GMT 2025
On 20.11.2025 18:58, Matthieu Longo wrote:
> From: Richard Ball <richard.ball@arm.com>
>
> 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>
Okay with a few small adjustments (see below), and provided you also got
Arm64 side approval.
> @@ -683,6 +719,12 @@ bool
> _bfd_elf_merge_object_attributes (bfd *ibfd, struct bfd_link_info *info)
> {
> bfd *obfd = info->output_bfd;
> +
> + /* 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;
> +
> obj_attribute *in_attr;
> obj_attribute *out_attr;
> int vendor;
Mixing declarations and statements is now allowed, but I think we shouldn't
needlessly mix them when functions clearly have the two things separated.
> @@ -3105,6 +3126,10 @@ extern bfd *_bfd_elf64_bfd_from_remote_memory
> 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 int bfd_elf_get_obj_attr_int (bfd *, obj_attr_vendor_t, obj_attr_tag_t);
> @@ -3143,6 +3168,36 @@ extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr
> 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);
Except for this, ...
> +extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2_t *, obj_attr_encoding_v2_t);
> +extern obj_attr_v2_t *_bfd_elf_obj_attr_v2_copy (const obj_attr_v2_t *,
> + obj_attr_encoding_v2_t);
> +extern int _bfd_elf_obj_attr_v2_cmp (const obj_attr_v2_t *,
> + const obj_attr_v2_t *);
> +extern obj_attr_v2_t *
> +obj_attr_v2_find_by_tag (const obj_attr_subsection_v2_t *, obj_attr_tag_t,
> + bool);
... by their names these are libbfd-internal functions. In which case they want
to gain ATTRIBUTE_HIDDEN, just like you have it in the earlier hunk.
> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_v2_t,
> + obj_attr_v2_t, extern);
> +LINKED_LIST_MERGE_SORT_PROTOTYPE_(obj_attr_v2_t, extern);
> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2_t,
> + obj_attr_v2_t, extern);
> +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 *);
> +extern obj_attr_subsection_v2_t *_bfd_elf_obj_attr_subsection_v2_copy
> + (const obj_attr_subsection_v2_t *);
> +extern int _bfd_elf_obj_attr_subsection_v2_cmp
> + (const obj_attr_subsection_v2_t *, const obj_attr_subsection_v2_t *);
> +extern obj_attr_subsection_v2_t * obj_attr_subsection_v2_find_by_name
> + (obj_attr_subsection_v2_t *, const char *, bool);
Same here.
Jan
More information about the Binutils
mailing list