[PATCH v10 05/28] Object Attributes v2: new abstractions for subsections and attributes
Matthieu Longo
matthieu.longo@arm.com
Fri Nov 28 17:30:28 GMT 2025
On 28/11/2025 13:30, Jan Beulich wrote:
> 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.
>
Fixed.
>> @@ -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.
>
Fixed.
>> +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
Fixed.
Matthieu
More information about the Binutils
mailing list