[PATCH v8 03/19] Object Attributes v2: new abstractions for subsections and attributes
Matthieu Longo
matthieu.longo@arm.com
Mon Aug 4 15:25:19 GMT 2025
On 2025-07-31 13:18, Jan Beulich wrote:
> On 15.07.2025 13:39, Matthieu Longo wrote:
>> @@ -834,8 +867,218 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
>> return result;
>> }
>>
>> -bool _bfd_elf_write_section_build_attributes (bfd *abfd,
>> - struct bfd_link_info *info ATTRIBUTE_UNUSED)
>> +/* Create a new object attribute with key TAG and value VALS.
>> + Return a pointer to it. */
>> +
>> +obj_attr_v2 *
>> +_bfd_elf_obj_attr_v2_init (obj_attr_tag_t tag,
>> + union obj_attr_value_v2 vals)
>> +{
>> + obj_attr_v2 *attr = (obj_attr_v2 *) malloc (sizeof (*attr));
>
> No need for a cast? Also, if you don't ...
>
>> + memset (attr, 0, sizeof (*attr));
>
> ... check the return value before use, likely you mean xmalloc()? Or, as you
> want the array zeroed, e.g. XCNEW()?
>
Replaced with XCNEW().
>> + attr->tag = tag;
>> + attr->vals = vals;
>
> Why "vals", not "val"?
>
It contains only one value even if it is an union, so "val" is better.
Changed in the next revision.
>> + return attr;
>> +}
>> +
>> +/* Free memory allocated by the object attribute ATTR. */
>> +
>> +void
>> +_bfd_elf_obj_attr_v2_free (obj_attr_v2 *attr, obj_attr_encoding_v2 encoding)
>> +{
>> + if (encoding == OA_ENC_NTBS)
>> + free ((char *) attr->vals.string_val);
>> + free (attr);
>> +}
>> +
>> +/* Copy an object attribute OTHER, and return a pointer to the copy. */
>> +
>> +obj_attr_v2 *
>> +_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *other,
>> + obj_attr_encoding_v2 encoding)
>> +{
>> + union obj_attr_value_v2 vals;
>> + if (encoding == OA_ENC_NTBS)
>> + vals.string_val
>> + = (other->vals.string_val != NULL
>> + ? strdup (other->vals.string_val)
>
> xstrdup()
>
Fixed.
>> + : NULL);
>> + else
>> + vals.uint_val = other->vals.uint_val;
>> +
>> + return _bfd_elf_obj_attr_v2_init (other->tag, vals);
>> +}
>> +
>> +/* 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 *a1, const obj_attr_v2 *a2)
>> +{
>> + if (a1->tag < a2->tag)
>> + return -1;
>> + else if (a1->tag > a2->tag)
>> + return 1;
>> + else
>> + return 0;
>
> Please may I ask that unnecessary "else" be omitted (also elsewhere)?
>
Fixed.
>> +}
>> +
>> +/* 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 *
>> +obj_attr_v2_find_by_tag (const obj_attr_subsection_v2 *subsec,
>> + obj_attr_tag_t tag,
>> + bool sorted)
>> +{
>> + for (obj_attr_v2 *attr = subsec->first;
>> + attr != NULL;
>> + attr = attr->next)
>> + if (attr->tag == tag)
>> + return attr;
>> + else 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, obj_attr_v2, /* public */)
>> +LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_v2, obj_attr_v2, /* public */)
>> +
>> +/* Create a new object attribute subsection with the following properties:
>> + - NAME: the name of the subsection.
>> + - 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 *
>> +_bfd_elf_obj_attr_subsection_v2_init (const char *name,
>> + obj_attr_subsection_scope_v2 scope,
>> + bool optional,
>> + obj_attr_encoding_v2 encoding)
>> +{
>> + obj_attr_subsection_v2 *subsection = (obj_attr_subsection_v2 *)
>> + malloc (sizeof (*subsection));
>> + memset (subsection, 0, sizeof (*subsection));
>
> Same comments as for _bfd_elf_obj_attr_v2_init().
>
Replaced by XCNEW().
>> + 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 *subsec)
>> +{
>> + obj_attr_v2 *attr = subsec->first;
>> + while (attr != NULL)
>> + {
>> + obj_attr_v2 *a = attr;
>> + attr = attr->next;
>> + _bfd_elf_obj_attr_v2_free (a, subsec->encoding);
>> + }
>> + free (subsec);
>> +}
>> +
>> +/* Deep copy an object attribute subsection OTHER, and return a pointer to the
>> + copy. */
>> +
>> +obj_attr_subsection_v2 *
>> +_bfd_elf_obj_attr_subsection_v2_copy (obj_attr_subsection_v2 const *other)
>> +{
>> + obj_attr_subsection_v2 *new_subsec
>> + = _bfd_elf_obj_attr_subsection_v2_init (other->name, other->scope,
>> + other->optional, other->encoding);
>> + for (obj_attr_v2* attr = other->first;
>
> Nit: Misplaced *, also ...
>
Fixed.
I used check_GNU_style.py inside gcc/contrib, and didn't find others
issues regarding the pointers in the patch series.
>> + attr != NULL;
>> + attr = attr->next)
>> + {
>> + obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
>
> ... here.
>
Fixed.
>> --- /dev/null
>> +++ b/bfd/elf-attrs.h
>> @@ -0,0 +1,118 @@
>> +/* 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_t {
>> + OBJ_ATTR_VERSION_NONE = 0,
>> + OBJ_ATTR_VERSION_UNSUPPORTED,
>> + OBJ_ATTR_V1,
>> + OBJ_ATTR_V2,
>> + OBJ_ATTR_MAX_V = OBJ_ATTR_V2,
>> +} obj_attr_version_t;
>> +
>> +/* --------------------
>> + Object attributes v2
>> + -------------------- */
>> +
>> +typedef enum obj_attr_encoding_v2
>> +{
>> + OA_ENC_UNSET = 0,
>> + OA_ENC_ULEB128 = 1,
>> + OA_ENC_NTBS = 2,
>> + OA_ENC_MAX = OA_ENC_NTBS,
>> +} obj_attr_encoding_v2;
>> +
>> +#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_val;
>> + const char* string_val;
>
> Another misplaced *. Please check the entire series.
>
Fixed.
>> +} obj_attr_value_v2;
>> +
>> +typedef uint32_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 vals;
>> +
>> + /* 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;
>> +
>
> Nit: Unnecessary / unwanted blank line. (Again below.)
>
Fixed.
>> +} obj_attr_v2;
>> +
>> +typedef enum obj_attr_subsection_scope_v2
>> +{
>> + OA_SUBSEC_PUBLIC = 0,
>> + OA_SUBSEC_PRIVATE = 1,
>
> Is the explicit specifying of values actually needed for something?
> Or is this reflecting some part of the specification, rather being an
> internal-only representation?
>
>> +} obj_attr_subsection_scope_v2;
>> +
>> +typedef struct obj_attr_subsection_v2 {
>> + /* The name of the subsection. */
>> + const char *name;
>> +
>> + /* The scope of the subsection. */
>> + obj_attr_subsection_scope_v2 scope;
>> +
>> + /* Is this subsection optional ? Can it be skipped ? */
>
> Like full stops, question marks don't really want/need separating by a
> blank.
>
Fixed.
>> + bool optional;
>> +
>> + /* The value encoding of attributes in this subsection. */
>> + obj_attr_encoding_v2 encoding;
>> +
>> + /* The size of the list. */
>> + uint32_t size;
>
> Here and elsewhere I think it would be better to use "unsigned int".
> Fixed-width types are helpful to describe ABIs or file formats.
What about using size_t instead ?
The only issue I see with size_t is that it is platform dependent so the
size can change. But is it an issue here ?
>
> Jan
More information about the Binutils
mailing list