[PATCH v8 03/19] Object Attributes v2: new abstractions for subsections and attributes

Jan Beulich jbeulich@suse.com
Thu Jul 31 12:18:13 GMT 2025


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()?

> +  attr->tag = tag;
> +  attr->vals = vals;

Why "vals", not "val"?

> +  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()

> +	 : 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)?

> +}
> +
> +/* 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().

> +  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 ...

> +       attr != NULL;
> +       attr = attr->next)
> +    {
> +      obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);

... here.

> --- /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.

> +} 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.)

> +} 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.

> +  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.

Jan


More information about the Binutils mailing list