[v0,02/15] Build attributes: add new abstractions for subsections and attributes
Checks
Commit Message
From: Richard Ball <richard.ball@arm.com>
Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
---
bfd/Makefile.am | 2 +-
bfd/Makefile.in | 2 +-
bfd/elf-attrs.c | 209 +++++++++++++++++++++++++++++++++++++++++
bfd/elf-attrs.h | 102 ++++++++++++++++++++
bfd/elf-bfd.h | 42 ++++++++-
bfd/elfnn-aarch64.c | 13 +++
bfd/elfxx-target.h | 6 +-
bfd/po/SRC-POTFILES.in | 1 +
8 files changed, 372 insertions(+), 5 deletions(-)
create mode 100644 bfd/elf-attrs.h
Comments
On 10.03.2025 18:51, Matthieu Longo wrote:
> From: Richard Ball <richard.ball@arm.com>
>
> Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
> ---
> bfd/Makefile.am | 2 +-
> bfd/Makefile.in | 2 +-
> bfd/elf-attrs.c | 209 +++++++++++++++++++++++++++++++++++++++++
> bfd/elf-attrs.h | 102 ++++++++++++++++++++
> bfd/elf-bfd.h | 42 ++++++++-
> bfd/elfnn-aarch64.c | 13 +++
> bfd/elfxx-target.h | 6 +-
> bfd/po/SRC-POTFILES.in | 1 +
> 8 files changed, 372 insertions(+), 5 deletions(-)
> create mode 100644 bfd/elf-attrs.h
Please can we have a proper description for such newly added functionality?
Jan
> --- a/bfd/Makefile.am
> +++ b/bfd/Makefile.am
> @@ -707,7 +707,7 @@ SOURCE_HFILES = \
> 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-nacl.h elf-s390.h elf-vxworks.h \
> elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
> diff --git a/bfd/Makefile.in b/bfd/Makefile.in
> index 1543af7984a..ecc91d733af 100644
> --- a/bfd/Makefile.in
> +++ b/bfd/Makefile.in
> @@ -1171,7 +1171,7 @@ SOURCE_HFILES = \
> 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-nacl.h elf-s390.h elf-vxworks.h \
> elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
> diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
> index a6a72369afd..634843b5162 100644
> --- a/bfd/elf-attrs.c
> +++ b/bfd/elf-attrs.c
> @@ -20,6 +20,7 @@
>
> #include "sysdep.h"
> #include "bfd.h"
> +#include "double-linked-list.h"
> #include "libiberty.h"
> #include "libbfd.h"
> #include "elf-bfd.h"
> @@ -476,6 +477,19 @@ gnu_obj_attrs_arg_type (unsigned int tag)
> int
> _bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag)
> {
> + if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
> + {
> + BFD_ASSERT (elf_obj_attr_subsections (abfd).last_ != NULL);
> + switch (elf_obj_attr_subsections (abfd).last_->encoding)
> + {
> + case ULEB128:
> + return ATTR_TYPE_FLAG_INT_VAL;
> + case NTBS:
> + return ATTR_TYPE_FLAG_STR_VAL;
> + }
> + }
> +
> + /* Version 1. */
> switch (vendor)
> {
> case OBJ_ATTR_PROC:
> @@ -822,6 +836,201 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
> return result;
> }
>
> +obj_attr_v2 *
> +_bfd_elf_obj_attr_v2_init (unsigned int tag,
> + union obj_attr_value_v2 vals)
> +{
> + obj_attr_v2 *attr = (obj_attr_v2*) malloc (sizeof (obj_attr_v2));
> + memset ((void *) attr, 0, sizeof (obj_attr_v2));
> + attr->tag = tag;
> + attr->vals = vals;
> + return attr;
> +}
> +
> +void
> +_bfd_elf_obj_attr_v2_free (obj_attr_v2 * attr, obj_attr_encoding_v2 encoding)
> +{
> + if (encoding == NTBS && attr->vals.string_val != NULL)
> + free ((void *) attr->vals.string_val);
> + free (attr);
> +}
> +
> +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 == NTBS)
> + vals.string_val =
> + (other->vals.string_val != NULL)
> + ? strdup (other->vals.string_val)
> + : NULL;
> + else
> + vals.uint_val = other->vals.uint_val;
> +
> + obj_attr_v2 *copy =_bfd_elf_obj_attr_v2_init (other->tag, vals);
> + copy->status = other->status;
> + return copy;
> +}
> +
> +#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
> +
> +void
> +_bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *s,
> + obj_attr_v2 *a1, obj_attr_v2 *a2)
> +{
> + SWAP (a1->next, a2->next);
> + SWAP (a1->prev, a2->prev);
> +
> + if (s->first_ == a1)
> + s->first_ = a2;
> + else if (s->first_ == a2)
> + s->first_ = a1;
> +
> + if (s->last_ == a1)
> + s->last_ = a2;
> + else if (s->last_ == a2)
> + s->last_ = a1;
> +}
> +
> +int
> +_bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *a1, obj_attr_v2 *a2)
> +{
> + if (a1->tag < a2->tag)
> + return -1;
> + else if (a1->tag > a2->tag)
> + return 1;
> + else
> + return 0;
> +}
> +
> +/* Find the object attribute matching the given tag (object attributes v2 only).
> + Note: The parameter 'sorted' specifies whether the given list is sorted or
> + not. If the list of attributes is sorted, the linear search stops as soon as
> + it finds an attribute with a greater tag. */
> +obj_attr_v2 *
> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *subsec,
> + uint32_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;
> +}
> +
> +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 */)
> +
> +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 (obj_attr_subsection_v2));
> + memset ((void *) subsection, 0, sizeof (obj_attr_subsection_v2));
> + subsection->name = name;
> + subsection->scope = scope;
> + subsection->optional = optional;
> + subsection->encoding = encoding;
> + return subsection;
> +}
> +
> +void
> +_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *subsec)
> +{
> + for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
> + _bfd_elf_obj_attr_v2_free (attr, subsec->encoding);
> + free (subsec);
> +}
> +
> +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_;
> + attr != NULL;
> + attr = attr->next)
> + {
> + obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
> + LINKED_LIST_APPEND(obj_attr_v2) (new_subsec, new_attr);
> + }
> + return new_subsec;
> +}
> +
> +void
> +_bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *plist,
> + obj_attr_subsection_v2 *s1,
> + obj_attr_subsection_v2 *s2)
> +{
> + SWAP (s1->next, s2->next);
> + SWAP (s1->prev, s2->prev);
> +
> + if (plist->first_ == s1)
> + plist->first_ = s2;
> + else if (plist->first_ == s2)
> + plist->first_ = s1;
> +
> + if (plist->last_ == s1)
> + plist->last_ = s2;
> + else if (plist->last_ == s2)
> + plist->last_ = s1;
> +}
> +
> +int
> +_bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *s1,
> + obj_attr_subsection_v2 *s2)
> +{
> + int res = strcmp (s1->name, s2->name);
> + if (res != 0)
> + return res;
> +
> + if (s1->optional < s2->optional)
> + return -1;
> + else if (s1->optional > s2->optional)
> + return 1;
> +
> + if (s1->encoding < s2->encoding)
> + return -1;
> + if (s1->encoding > s2->encoding)
> + return 1;
> + else
> + return 0;
> +}
> +
> +/* Find the subsection matching the given name.
> + Note: The parameter sorted specified whether the given list is sorted or not.
> + If the list of subsections is sorted, the linear search stops as soon as it
> + finds a subsection name with a greater order. */
> +obj_attr_subsection_v2 *
> +obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2 *first,
> + const char *name,
> + bool sorted)
> +{
> + for (obj_attr_subsection_v2 *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;
> +}
> +
> +LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
> +LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
> +
> bool _bfd_elf_write_section_build_attributes (bfd *abfd,
> struct bfd_link_info *info ATTRIBUTE_UNUSED)
> {
> diff --git a/bfd/elf-attrs.h b/bfd/elf-attrs.h
> new file mode 100644
> index 00000000000..5d41bb98538
> --- /dev/null
> +++ b/bfd/elf-attrs.h
> @@ -0,0 +1,102 @@
> +/* ELF attributes support (based on ARM EABI attributes).
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + Written by Cygnus Support.
> +
> + 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>
> +
> +/* --------------------
> + Object attributes v2
> + -------------------- */
> +
> +typedef enum obj_attr_encoding_v2
> +{
> + ULEB128 = 0,
> + NTBS = 1,
> +} obj_attr_encoding_v2;
> +
> +typedef union obj_attr_value_v2 {
> + uint32_t uint_val;
> + const char* string_val;
> +} obj_attr_value_v2;
> +
> +typedef struct obj_attr_v2 {
> + /* The name/tag of an attribute. */
> + uint32_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;
> +
> +} obj_attr_v2;
> +
> +typedef enum obj_attr_subsection_scope_v2
> +{
> + SUBSEC_PUBLIC = 0,
> + SUBSEC_PRIVATE = 1,
> +} 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 ? */
> + bool optional;
> +
> + /* The value encoding of attributes in this subsection. */
> + obj_attr_encoding_v2 encoding;
> +
> + /* 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_;
> +
> + /* The size of the list. */
> + uint32_t size;
> +
> +} obj_attr_subsection_v2;
> +
> +typedef struct obj_attr_subsection_list
> +{
> + /* A pointer to the first node of the list. */
> + obj_attr_subsection_v2 *first_;
> +
> + /* A pointer to the last node of the list. */
> + obj_attr_subsection_v2 *last_;
> +
> + /* The size of the list. */
> + uint64_t size;
> +} obj_attr_subsection_list;
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 5903d857faa..6c326d5db72 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -24,9 +24,11 @@
>
> #include <stdlib.h>
>
> +#include "double-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
> @@ -1630,13 +1632,15 @@ struct elf_backend_data
> /* 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) (int);
>
> /* The section type to use for an attributes section. */
> unsigned int obj_attrs_section_type;
>
> + /* The version of object attributes (1 or 2). */
> + unsigned int obj_attrs_version;
> +
> /* 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
> @@ -2160,6 +2164,11 @@ struct elf_obj_tdata
> obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
> obj_attribute_list *other_obj_attributes[2];
>
> + /* Object attributes v2: attributes of the same category are stored inside
> + the same subsection. A subsection can only hold attributes with the same
> + data type. */
> + obj_attr_subsection_list 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. */
> @@ -2253,6 +2262,7 @@ struct elf_obj_tdata
> (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)
> @@ -3083,6 +3093,34 @@ extern bool _bfd_elf_merge_unknown_attribute_list (bfd *, bfd *);
> extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr (asection *sec);
> extern bool elf_read_notes (bfd *, file_ptr, bfd_size_type, size_t);
>
> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_init (unsigned int,
> + union obj_attr_value_v2);
> +extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2 *, obj_attr_encoding_v2);
> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *,
> + obj_attr_encoding_v2);
> +extern void _bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *,
> + obj_attr_v2 *, obj_attr_v2 *);
> +extern int _bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *, obj_attr_v2 *);
> +extern obj_attr_v2 *
> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *, uint32_t, bool);
> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_v2, extern);
> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_init (const char*,
> + obj_attr_subsection_scope_v2, bool, obj_attr_encoding_v2);
> +extern void _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *);
> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_copy
> + (obj_attr_subsection_v2 const*);
> +extern void _bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *,
> + obj_attr_subsection_v2 *, obj_attr_subsection_v2 *);
> +extern int _bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *,
> + obj_attr_subsection_v2 *s2);
> +extern obj_attr_subsection_v2 * obj_attr_subsection_v2_find_by_name
> + (obj_attr_subsection_v2 *, const char *, bool);
> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, extern);
> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
> +
> extern bool _bfd_elf_parse_gnu_properties
> (bfd *, Elf_Internal_Note *);
> extern elf_property_list * _bfd_elf_find_property
> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
> index 548da1f8b30..21fc99c4c98 100644
> --- a/bfd/elfnn-aarch64.c
> +++ b/bfd/elfnn-aarch64.c
> @@ -10760,8 +10760,21 @@ const struct elf_size_info elfNN_aarch64_size_info =
> #define elf_backend_extern_protected_data 0
> #define elf_backend_hash_symbol elf_aarch64_hash_symbol
>
> +/* elf_backend_obj_attrs_vendor is unused for AArch64. It is replaced by the
> + concept of subsections, each one having its own name defined by the
> + assembly directive "aeabi_subsection". */
> +#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
> +/* elf_backend_obj_attrs_arg_type is unused as the type of an attribute is
> + determined by looking up at the current subsection, not the value of the
> + tag. */
> +#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_obj_attrs_version
> +#define elf_backend_obj_attrs_version 2
>
> #include "elfNN-target.h"
>
> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
> index 625243cac94..cff508dbbce 100644
> --- a/bfd/elfxx-target.h
> +++ b/bfd/elfxx-target.h
> @@ -556,6 +556,9 @@
> #ifndef elf_backend_obj_attrs_section_type
> #define elf_backend_obj_attrs_section_type SHT_GNU_ATTRIBUTES
> #endif
> +#ifndef elf_backend_obj_attrs_version
> +#define elf_backend_obj_attrs_version 1 /* Default version. */
> +#endif
> #ifndef elf_backend_obj_attrs_order
> #define elf_backend_obj_attrs_order NULL
> #endif
> @@ -808,7 +811,7 @@
> #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_OSABI == ELFOSABI_NONE ? 1 : 0)
> @@ -934,6 +937,7 @@ static const struct elf_backend_data elfNN_bed =
> elf_backend_obj_attrs_section,
> elf_backend_obj_attrs_arg_type,
> elf_backend_obj_attrs_section_type,
> + elf_backend_obj_attrs_version,
> elf_backend_obj_attrs_order,
> elf_backend_obj_attrs_handle_unknown,
> elf_backend_parse_gnu_properties,
> diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in
> index 54b078b8295..4b8ccfbe2c8 100644
> --- a/bfd/po/SRC-POTFILES.in
> +++ b/bfd/po/SRC-POTFILES.in
> @@ -132,6 +132,7 @@ ecoff.c
> ecofflink.c
> ecoffswap.h
> elf-attrs.c
> +elf-attrs.h
> elf-bfd.h
> elf-eh-frame.c
> elf-hppa.h
On 2025-03-11 07:58, Jan Beulich wrote:
> On 10.03.2025 18:51, Matthieu Longo wrote:
>> From: Richard Ball <richard.ball@arm.com>
>>
>> Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
>> ---
>> bfd/Makefile.am | 2 +-
>> bfd/Makefile.in | 2 +-
>> bfd/elf-attrs.c | 209 +++++++++++++++++++++++++++++++++++++++++
>> bfd/elf-attrs.h | 102 ++++++++++++++++++++
>> bfd/elf-bfd.h | 42 ++++++++-
>> bfd/elfnn-aarch64.c | 13 +++
>> bfd/elfxx-target.h | 6 +-
>> bfd/po/SRC-POTFILES.in | 1 +
>> 8 files changed, 372 insertions(+), 5 deletions(-)
>> create mode 100644 bfd/elf-attrs.h
>
> Please can we have a proper description for such newly added functionality?
>
> Jan
>
I apologize for this. The next revision will have hopefully a useful
description in all the commits.
Matthieu
>> --- a/bfd/Makefile.am
>> +++ b/bfd/Makefile.am
>> @@ -707,7 +707,7 @@ SOURCE_HFILES = \
>> 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-nacl.h elf-s390.h elf-vxworks.h \
>> elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
>> diff --git a/bfd/Makefile.in b/bfd/Makefile.in
>> index 1543af7984a..ecc91d733af 100644
>> --- a/bfd/Makefile.in
>> +++ b/bfd/Makefile.in
>> @@ -1171,7 +1171,7 @@ SOURCE_HFILES = \
>> 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-nacl.h elf-s390.h elf-vxworks.h \
>> elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
>> diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
>> index a6a72369afd..634843b5162 100644
>> --- a/bfd/elf-attrs.c
>> +++ b/bfd/elf-attrs.c
>> @@ -20,6 +20,7 @@
>>
>> #include "sysdep.h"
>> #include "bfd.h"
>> +#include "double-linked-list.h"
>> #include "libiberty.h"
>> #include "libbfd.h"
>> #include "elf-bfd.h"
>> @@ -476,6 +477,19 @@ gnu_obj_attrs_arg_type (unsigned int tag)
>> int
>> _bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag)
>> {
>> + if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
>> + {
>> + BFD_ASSERT (elf_obj_attr_subsections (abfd).last_ != NULL);
>> + switch (elf_obj_attr_subsections (abfd).last_->encoding)
>> + {
>> + case ULEB128:
>> + return ATTR_TYPE_FLAG_INT_VAL;
>> + case NTBS:
>> + return ATTR_TYPE_FLAG_STR_VAL;
>> + }
>> + }
>> +
>> + /* Version 1. */
>> switch (vendor)
>> {
>> case OBJ_ATTR_PROC:
>> @@ -822,6 +836,201 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
>> return result;
>> }
>>
>> +obj_attr_v2 *
>> +_bfd_elf_obj_attr_v2_init (unsigned int tag,
>> + union obj_attr_value_v2 vals)
>> +{
>> + obj_attr_v2 *attr = (obj_attr_v2*) malloc (sizeof (obj_attr_v2));
>> + memset ((void *) attr, 0, sizeof (obj_attr_v2));
>> + attr->tag = tag;
>> + attr->vals = vals;
>> + return attr;
>> +}
>> +
>> +void
>> +_bfd_elf_obj_attr_v2_free (obj_attr_v2 * attr, obj_attr_encoding_v2 encoding)
>> +{
>> + if (encoding == NTBS && attr->vals.string_val != NULL)
>> + free ((void *) attr->vals.string_val);
>> + free (attr);
>> +}
>> +
>> +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 == NTBS)
>> + vals.string_val =
>> + (other->vals.string_val != NULL)
>> + ? strdup (other->vals.string_val)
>> + : NULL;
>> + else
>> + vals.uint_val = other->vals.uint_val;
>> +
>> + obj_attr_v2 *copy =_bfd_elf_obj_attr_v2_init (other->tag, vals);
>> + copy->status = other->status;
>> + return copy;
>> +}
>> +
>> +#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
>> +
>> +void
>> +_bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *s,
>> + obj_attr_v2 *a1, obj_attr_v2 *a2)
>> +{
>> + SWAP (a1->next, a2->next);
>> + SWAP (a1->prev, a2->prev);
>> +
>> + if (s->first_ == a1)
>> + s->first_ = a2;
>> + else if (s->first_ == a2)
>> + s->first_ = a1;
>> +
>> + if (s->last_ == a1)
>> + s->last_ = a2;
>> + else if (s->last_ == a2)
>> + s->last_ = a1;
>> +}
>> +
>> +int
>> +_bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *a1, obj_attr_v2 *a2)
>> +{
>> + if (a1->tag < a2->tag)
>> + return -1;
>> + else if (a1->tag > a2->tag)
>> + return 1;
>> + else
>> + return 0;
>> +}
>> +
>> +/* Find the object attribute matching the given tag (object attributes v2 only).
>> + Note: The parameter 'sorted' specifies whether the given list is sorted or
>> + not. If the list of attributes is sorted, the linear search stops as soon as
>> + it finds an attribute with a greater tag. */
>> +obj_attr_v2 *
>> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *subsec,
>> + uint32_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;
>> +}
>> +
>> +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 */)
>> +
>> +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 (obj_attr_subsection_v2));
>> + memset ((void *) subsection, 0, sizeof (obj_attr_subsection_v2));
>> + subsection->name = name;
>> + subsection->scope = scope;
>> + subsection->optional = optional;
>> + subsection->encoding = encoding;
>> + return subsection;
>> +}
>> +
>> +void
>> +_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *subsec)
>> +{
>> + for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
>> + _bfd_elf_obj_attr_v2_free (attr, subsec->encoding);
>> + free (subsec);
>> +}
>> +
>> +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_;
>> + attr != NULL;
>> + attr = attr->next)
>> + {
>> + obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
>> + LINKED_LIST_APPEND(obj_attr_v2) (new_subsec, new_attr);
>> + }
>> + return new_subsec;
>> +}
>> +
>> +void
>> +_bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *plist,
>> + obj_attr_subsection_v2 *s1,
>> + obj_attr_subsection_v2 *s2)
>> +{
>> + SWAP (s1->next, s2->next);
>> + SWAP (s1->prev, s2->prev);
>> +
>> + if (plist->first_ == s1)
>> + plist->first_ = s2;
>> + else if (plist->first_ == s2)
>> + plist->first_ = s1;
>> +
>> + if (plist->last_ == s1)
>> + plist->last_ = s2;
>> + else if (plist->last_ == s2)
>> + plist->last_ = s1;
>> +}
>> +
>> +int
>> +_bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *s1,
>> + obj_attr_subsection_v2 *s2)
>> +{
>> + int res = strcmp (s1->name, s2->name);
>> + if (res != 0)
>> + return res;
>> +
>> + if (s1->optional < s2->optional)
>> + return -1;
>> + else if (s1->optional > s2->optional)
>> + return 1;
>> +
>> + if (s1->encoding < s2->encoding)
>> + return -1;
>> + if (s1->encoding > s2->encoding)
>> + return 1;
>> + else
>> + return 0;
>> +}
>> +
>> +/* Find the subsection matching the given name.
>> + Note: The parameter sorted specified whether the given list is sorted or not.
>> + If the list of subsections is sorted, the linear search stops as soon as it
>> + finds a subsection name with a greater order. */
>> +obj_attr_subsection_v2 *
>> +obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2 *first,
>> + const char *name,
>> + bool sorted)
>> +{
>> + for (obj_attr_subsection_v2 *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;
>> +}
>> +
>> +LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
>> +LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
>> +
>> bool _bfd_elf_write_section_build_attributes (bfd *abfd,
>> struct bfd_link_info *info ATTRIBUTE_UNUSED)
>> {
>> diff --git a/bfd/elf-attrs.h b/bfd/elf-attrs.h
>> new file mode 100644
>> index 00000000000..5d41bb98538
>> --- /dev/null
>> +++ b/bfd/elf-attrs.h
>> @@ -0,0 +1,102 @@
>> +/* ELF attributes support (based on ARM EABI attributes).
>> + Copyright (C) 2025 Free Software Foundation, Inc.
>> + Written by Cygnus Support.
>> +
>> + 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>
>> +
>> +/* --------------------
>> + Object attributes v2
>> + -------------------- */
>> +
>> +typedef enum obj_attr_encoding_v2
>> +{
>> + ULEB128 = 0,
>> + NTBS = 1,
>> +} obj_attr_encoding_v2;
>> +
>> +typedef union obj_attr_value_v2 {
>> + uint32_t uint_val;
>> + const char* string_val;
>> +} obj_attr_value_v2;
>> +
>> +typedef struct obj_attr_v2 {
>> + /* The name/tag of an attribute. */
>> + uint32_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;
>> +
>> +} obj_attr_v2;
>> +
>> +typedef enum obj_attr_subsection_scope_v2
>> +{
>> + SUBSEC_PUBLIC = 0,
>> + SUBSEC_PRIVATE = 1,
>> +} 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 ? */
>> + bool optional;
>> +
>> + /* The value encoding of attributes in this subsection. */
>> + obj_attr_encoding_v2 encoding;
>> +
>> + /* 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_;
>> +
>> + /* The size of the list. */
>> + uint32_t size;
>> +
>> +} obj_attr_subsection_v2;
>> +
>> +typedef struct obj_attr_subsection_list
>> +{
>> + /* A pointer to the first node of the list. */
>> + obj_attr_subsection_v2 *first_;
>> +
>> + /* A pointer to the last node of the list. */
>> + obj_attr_subsection_v2 *last_;
>> +
>> + /* The size of the list. */
>> + uint64_t size;
>> +} obj_attr_subsection_list;
>> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
>> index 5903d857faa..6c326d5db72 100644
>> --- a/bfd/elf-bfd.h
>> +++ b/bfd/elf-bfd.h
>> @@ -24,9 +24,11 @@
>>
>> #include <stdlib.h>
>>
>> +#include "double-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
>> @@ -1630,13 +1632,15 @@ struct elf_backend_data
>> /* 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) (int);
>>
>> /* The section type to use for an attributes section. */
>> unsigned int obj_attrs_section_type;
>>
>> + /* The version of object attributes (1 or 2). */
>> + unsigned int obj_attrs_version;
>> +
>> /* 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
>> @@ -2160,6 +2164,11 @@ struct elf_obj_tdata
>> obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
>> obj_attribute_list *other_obj_attributes[2];
>>
>> + /* Object attributes v2: attributes of the same category are stored inside
>> + the same subsection. A subsection can only hold attributes with the same
>> + data type. */
>> + obj_attr_subsection_list 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. */
>> @@ -2253,6 +2262,7 @@ struct elf_obj_tdata
>> (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)
>> @@ -3083,6 +3093,34 @@ extern bool _bfd_elf_merge_unknown_attribute_list (bfd *, bfd *);
>> extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr (asection *sec);
>> extern bool elf_read_notes (bfd *, file_ptr, bfd_size_type, size_t);
>>
>> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_init (unsigned int,
>> + union obj_attr_value_v2);
>> +extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2 *, obj_attr_encoding_v2);
>> +extern obj_attr_v2 *_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *,
>> + obj_attr_encoding_v2);
>> +extern void _bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *,
>> + obj_attr_v2 *, obj_attr_v2 *);
>> +extern int _bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *, obj_attr_v2 *);
>> +extern obj_attr_v2 *
>> +obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *, uint32_t, bool);
>> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
>> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_v2, extern);
>> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
>> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_init (const char*,
>> + obj_attr_subsection_scope_v2, bool, obj_attr_encoding_v2);
>> +extern void _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *);
>> +extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_copy
>> + (obj_attr_subsection_v2 const*);
>> +extern void _bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *,
>> + obj_attr_subsection_v2 *, obj_attr_subsection_v2 *);
>> +extern int _bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *,
>> + obj_attr_subsection_v2 *s2);
>> +extern obj_attr_subsection_v2 * obj_attr_subsection_v2_find_by_name
>> + (obj_attr_subsection_v2 *, const char *, bool);
>> +LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
>> +_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, extern);
>> +LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
>> +
>> extern bool _bfd_elf_parse_gnu_properties
>> (bfd *, Elf_Internal_Note *);
>> extern elf_property_list * _bfd_elf_find_property
>> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
>> index 548da1f8b30..21fc99c4c98 100644
>> --- a/bfd/elfnn-aarch64.c
>> +++ b/bfd/elfnn-aarch64.c
>> @@ -10760,8 +10760,21 @@ const struct elf_size_info elfNN_aarch64_size_info =
>> #define elf_backend_extern_protected_data 0
>> #define elf_backend_hash_symbol elf_aarch64_hash_symbol
>>
>> +/* elf_backend_obj_attrs_vendor is unused for AArch64. It is replaced by the
>> + concept of subsections, each one having its own name defined by the
>> + assembly directive "aeabi_subsection". */
>> +#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
>> +/* elf_backend_obj_attrs_arg_type is unused as the type of an attribute is
>> + determined by looking up at the current subsection, not the value of the
>> + tag. */
>> +#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_obj_attrs_version
>> +#define elf_backend_obj_attrs_version 2
>>
>> #include "elfNN-target.h"
>>
>> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
>> index 625243cac94..cff508dbbce 100644
>> --- a/bfd/elfxx-target.h
>> +++ b/bfd/elfxx-target.h
>> @@ -556,6 +556,9 @@
>> #ifndef elf_backend_obj_attrs_section_type
>> #define elf_backend_obj_attrs_section_type SHT_GNU_ATTRIBUTES
>> #endif
>> +#ifndef elf_backend_obj_attrs_version
>> +#define elf_backend_obj_attrs_version 1 /* Default version. */
>> +#endif
>> #ifndef elf_backend_obj_attrs_order
>> #define elf_backend_obj_attrs_order NULL
>> #endif
>> @@ -808,7 +811,7 @@
>> #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_OSABI == ELFOSABI_NONE ? 1 : 0)
>> @@ -934,6 +937,7 @@ static const struct elf_backend_data elfNN_bed =
>> elf_backend_obj_attrs_section,
>> elf_backend_obj_attrs_arg_type,
>> elf_backend_obj_attrs_section_type,
>> + elf_backend_obj_attrs_version,
>> elf_backend_obj_attrs_order,
>> elf_backend_obj_attrs_handle_unknown,
>> elf_backend_parse_gnu_properties,
>> diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in
>> index 54b078b8295..4b8ccfbe2c8 100644
>> --- a/bfd/po/SRC-POTFILES.in
>> +++ b/bfd/po/SRC-POTFILES.in
>> @@ -132,6 +132,7 @@ ecoff.c
>> ecofflink.c
>> ecoffswap.h
>> elf-attrs.c
>> +elf-attrs.h
>> elf-bfd.h
>> elf-eh-frame.c
>> elf-hppa.h
>
@@ -707,7 +707,7 @@ SOURCE_HFILES = \
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-nacl.h elf-s390.h elf-vxworks.h \
elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
@@ -1171,7 +1171,7 @@ SOURCE_HFILES = \
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-nacl.h elf-s390.h elf-vxworks.h \
elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
@@ -20,6 +20,7 @@
#include "sysdep.h"
#include "bfd.h"
+#include "double-linked-list.h"
#include "libiberty.h"
#include "libbfd.h"
#include "elf-bfd.h"
@@ -476,6 +477,19 @@ gnu_obj_attrs_arg_type (unsigned int tag)
int
_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag)
{
+ if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
+ {
+ BFD_ASSERT (elf_obj_attr_subsections (abfd).last_ != NULL);
+ switch (elf_obj_attr_subsections (abfd).last_->encoding)
+ {
+ case ULEB128:
+ return ATTR_TYPE_FLAG_INT_VAL;
+ case NTBS:
+ return ATTR_TYPE_FLAG_STR_VAL;
+ }
+ }
+
+ /* Version 1. */
switch (vendor)
{
case OBJ_ATTR_PROC:
@@ -822,6 +836,201 @@ _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
return result;
}
+obj_attr_v2 *
+_bfd_elf_obj_attr_v2_init (unsigned int tag,
+ union obj_attr_value_v2 vals)
+{
+ obj_attr_v2 *attr = (obj_attr_v2*) malloc (sizeof (obj_attr_v2));
+ memset ((void *) attr, 0, sizeof (obj_attr_v2));
+ attr->tag = tag;
+ attr->vals = vals;
+ return attr;
+}
+
+void
+_bfd_elf_obj_attr_v2_free (obj_attr_v2 * attr, obj_attr_encoding_v2 encoding)
+{
+ if (encoding == NTBS && attr->vals.string_val != NULL)
+ free ((void *) attr->vals.string_val);
+ free (attr);
+}
+
+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 == NTBS)
+ vals.string_val =
+ (other->vals.string_val != NULL)
+ ? strdup (other->vals.string_val)
+ : NULL;
+ else
+ vals.uint_val = other->vals.uint_val;
+
+ obj_attr_v2 *copy =_bfd_elf_obj_attr_v2_init (other->tag, vals);
+ copy->status = other->status;
+ return copy;
+}
+
+#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
+
+void
+_bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *s,
+ obj_attr_v2 *a1, obj_attr_v2 *a2)
+{
+ SWAP (a1->next, a2->next);
+ SWAP (a1->prev, a2->prev);
+
+ if (s->first_ == a1)
+ s->first_ = a2;
+ else if (s->first_ == a2)
+ s->first_ = a1;
+
+ if (s->last_ == a1)
+ s->last_ = a2;
+ else if (s->last_ == a2)
+ s->last_ = a1;
+}
+
+int
+_bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *a1, obj_attr_v2 *a2)
+{
+ if (a1->tag < a2->tag)
+ return -1;
+ else if (a1->tag > a2->tag)
+ return 1;
+ else
+ return 0;
+}
+
+/* Find the object attribute matching the given tag (object attributes v2 only).
+ Note: The parameter 'sorted' specifies whether the given list is sorted or
+ not. If the list of attributes is sorted, the linear search stops as soon as
+ it finds an attribute with a greater tag. */
+obj_attr_v2 *
+obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *subsec,
+ uint32_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;
+}
+
+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 */)
+
+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 (obj_attr_subsection_v2));
+ memset ((void *) subsection, 0, sizeof (obj_attr_subsection_v2));
+ subsection->name = name;
+ subsection->scope = scope;
+ subsection->optional = optional;
+ subsection->encoding = encoding;
+ return subsection;
+}
+
+void
+_bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *subsec)
+{
+ for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
+ _bfd_elf_obj_attr_v2_free (attr, subsec->encoding);
+ free (subsec);
+}
+
+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_;
+ attr != NULL;
+ attr = attr->next)
+ {
+ obj_attr_v2* new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding);
+ LINKED_LIST_APPEND(obj_attr_v2) (new_subsec, new_attr);
+ }
+ return new_subsec;
+}
+
+void
+_bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *plist,
+ obj_attr_subsection_v2 *s1,
+ obj_attr_subsection_v2 *s2)
+{
+ SWAP (s1->next, s2->next);
+ SWAP (s1->prev, s2->prev);
+
+ if (plist->first_ == s1)
+ plist->first_ = s2;
+ else if (plist->first_ == s2)
+ plist->first_ = s1;
+
+ if (plist->last_ == s1)
+ plist->last_ = s2;
+ else if (plist->last_ == s2)
+ plist->last_ = s1;
+}
+
+int
+_bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *s1,
+ obj_attr_subsection_v2 *s2)
+{
+ int res = strcmp (s1->name, s2->name);
+ if (res != 0)
+ return res;
+
+ if (s1->optional < s2->optional)
+ return -1;
+ else if (s1->optional > s2->optional)
+ return 1;
+
+ if (s1->encoding < s2->encoding)
+ return -1;
+ if (s1->encoding > s2->encoding)
+ return 1;
+ else
+ return 0;
+}
+
+/* Find the subsection matching the given name.
+ Note: The parameter sorted specified whether the given list is sorted or not.
+ If the list of subsections is sorted, the linear search stops as soon as it
+ finds a subsection name with a greater order. */
+obj_attr_subsection_v2 *
+obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2 *first,
+ const char *name,
+ bool sorted)
+{
+ for (obj_attr_subsection_v2 *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;
+}
+
+LINKED_LIST_MUTATIVE_OPS_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
+LINKED_LIST_MERGE_SORT_DECL(obj_attr_subsection_list, obj_attr_subsection_v2, /* public */)
+
bool _bfd_elf_write_section_build_attributes (bfd *abfd,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
new file mode 100644
@@ -0,0 +1,102 @@
+/* ELF attributes support (based on ARM EABI attributes).
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Written by Cygnus Support.
+
+ 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>
+
+/* --------------------
+ Object attributes v2
+ -------------------- */
+
+typedef enum obj_attr_encoding_v2
+{
+ ULEB128 = 0,
+ NTBS = 1,
+} obj_attr_encoding_v2;
+
+typedef union obj_attr_value_v2 {
+ uint32_t uint_val;
+ const char* string_val;
+} obj_attr_value_v2;
+
+typedef struct obj_attr_v2 {
+ /* The name/tag of an attribute. */
+ uint32_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;
+
+} obj_attr_v2;
+
+typedef enum obj_attr_subsection_scope_v2
+{
+ SUBSEC_PUBLIC = 0,
+ SUBSEC_PRIVATE = 1,
+} 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 ? */
+ bool optional;
+
+ /* The value encoding of attributes in this subsection. */
+ obj_attr_encoding_v2 encoding;
+
+ /* 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_;
+
+ /* The size of the list. */
+ uint32_t size;
+
+} obj_attr_subsection_v2;
+
+typedef struct obj_attr_subsection_list
+{
+ /* A pointer to the first node of the list. */
+ obj_attr_subsection_v2 *first_;
+
+ /* A pointer to the last node of the list. */
+ obj_attr_subsection_v2 *last_;
+
+ /* The size of the list. */
+ uint64_t size;
+} obj_attr_subsection_list;
@@ -24,9 +24,11 @@
#include <stdlib.h>
+#include "double-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
@@ -1630,13 +1632,15 @@ struct elf_backend_data
/* 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) (int);
/* The section type to use for an attributes section. */
unsigned int obj_attrs_section_type;
+ /* The version of object attributes (1 or 2). */
+ unsigned int obj_attrs_version;
+
/* 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
@@ -2160,6 +2164,11 @@ struct elf_obj_tdata
obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
obj_attribute_list *other_obj_attributes[2];
+ /* Object attributes v2: attributes of the same category are stored inside
+ the same subsection. A subsection can only hold attributes with the same
+ data type. */
+ obj_attr_subsection_list 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. */
@@ -2253,6 +2262,7 @@ struct elf_obj_tdata
(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)
@@ -3083,6 +3093,34 @@ extern bool _bfd_elf_merge_unknown_attribute_list (bfd *, bfd *);
extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr (asection *sec);
extern bool elf_read_notes (bfd *, file_ptr, bfd_size_type, size_t);
+extern obj_attr_v2 *_bfd_elf_obj_attr_v2_init (unsigned int,
+ union obj_attr_value_v2);
+extern void _bfd_elf_obj_attr_v2_free (obj_attr_v2 *, obj_attr_encoding_v2);
+extern obj_attr_v2 *_bfd_elf_obj_attr_v2_copy (obj_attr_v2 *,
+ obj_attr_encoding_v2);
+extern void _bfd_elf_obj_attr_v2_swap (obj_attr_subsection_v2 *,
+ obj_attr_v2 *, obj_attr_v2 *);
+extern int _bfd_elf_obj_attr_v2_cmp (obj_attr_v2 *, obj_attr_v2 *);
+extern obj_attr_v2 *
+obj_attr_v2_find_by_tag (obj_attr_subsection_v2 *, uint32_t, bool);
+LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
+_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_v2, extern);
+LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, obj_attr_v2, extern);
+extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_init (const char*,
+ obj_attr_subsection_scope_v2, bool, obj_attr_encoding_v2);
+extern void _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2 *);
+extern obj_attr_subsection_v2 *_bfd_elf_obj_attr_subsection_v2_copy
+ (obj_attr_subsection_v2 const*);
+extern void _bfd_elf_obj_attr_subsection_v2_swap (obj_attr_subsection_list *,
+ obj_attr_subsection_v2 *, obj_attr_subsection_v2 *);
+extern int _bfd_elf_obj_attr_subsection_v2_cmp (obj_attr_subsection_v2 *,
+ obj_attr_subsection_v2 *s2);
+extern obj_attr_subsection_v2 * obj_attr_subsection_v2_find_by_name
+ (obj_attr_subsection_v2 *, const char *, bool);
+LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
+_LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_v2, extern);
+LINKED_LIST_MERGE_SORT_PROTOTYPE(obj_attr_subsection_list, obj_attr_subsection_v2, extern);
+
extern bool _bfd_elf_parse_gnu_properties
(bfd *, Elf_Internal_Note *);
extern elf_property_list * _bfd_elf_find_property
@@ -10760,8 +10760,21 @@ const struct elf_size_info elfNN_aarch64_size_info =
#define elf_backend_extern_protected_data 0
#define elf_backend_hash_symbol elf_aarch64_hash_symbol
+/* elf_backend_obj_attrs_vendor is unused for AArch64. It is replaced by the
+ concept of subsections, each one having its own name defined by the
+ assembly directive "aeabi_subsection". */
+#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
+/* elf_backend_obj_attrs_arg_type is unused as the type of an attribute is
+ determined by looking up at the current subsection, not the value of the
+ tag. */
+#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_obj_attrs_version
+#define elf_backend_obj_attrs_version 2
#include "elfNN-target.h"
@@ -556,6 +556,9 @@
#ifndef elf_backend_obj_attrs_section_type
#define elf_backend_obj_attrs_section_type SHT_GNU_ATTRIBUTES
#endif
+#ifndef elf_backend_obj_attrs_version
+#define elf_backend_obj_attrs_version 1 /* Default version. */
+#endif
#ifndef elf_backend_obj_attrs_order
#define elf_backend_obj_attrs_order NULL
#endif
@@ -808,7 +811,7 @@
#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_OSABI == ELFOSABI_NONE ? 1 : 0)
@@ -934,6 +937,7 @@ static const struct elf_backend_data elfNN_bed =
elf_backend_obj_attrs_section,
elf_backend_obj_attrs_arg_type,
elf_backend_obj_attrs_section_type,
+ elf_backend_obj_attrs_version,
elf_backend_obj_attrs_order,
elf_backend_obj_attrs_handle_unknown,
elf_backend_parse_gnu_properties,
@@ -132,6 +132,7 @@ ecoff.c
ecofflink.c
ecoffswap.h
elf-attrs.c
+elf-attrs.h
elf-bfd.h
elf-eh-frame.c
elf-hppa.h