[PATCH v1 05/14] bfd: write Object Attributes v2
Matthieu Longo
matthieu.longo@arm.com
Fri Mar 21 17:14:39 GMT 2025
From: Richard Ball <richard.ball@arm.com>
This patch adds the serialization logic to write Object Attributes v2 (OAv2)
into the ELF section specified by the backend (.ARM.attributes for AARch64).
OAv2, once processed by the parser, are stored in the order they were
declared in the assembly, so not necessarily sorted. Sorting them
simplifies the comparison of the data between several files. Since
sorting OAv2 is clearly not the responsibility of readelf, they need
to be sorted by the producers (i.e. gas or ld).
The linker sorts the subsections and attributes as a pre-requisite of
the merge. Since the merge preserves the ordering, no final sort is
required before the serialization, contrarilly to the assembler.
Today, two methods are used for the serialization:
- bfd_elf_obj_attr_size: compute the size of the section.
- bfd_elf_obj_set_obj_attr_contents: write the data to the section.
Moving the final sort for gas into set_obj_attr_contents would mean
that a sort would be performed on an already-sorted collections. In
order to avoid this useless operation at link time, we added a new
finalization step called only by gas: bfd_elf_obj_attr_finalize_content.
As previously mentioned, the logic of OAv1 and OAv2 is kept separated.
Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
---
bfd/elf-attrs.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++--
bfd/elf-bfd.h | 1 +
gas/write.c | 2 +
3 files changed, 155 insertions(+), 5 deletions(-)
diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
index e58f47b2c43..002b7fe3c59 100644
--- a/bfd/elf-attrs.c
+++ b/bfd/elf-attrs.c
@@ -105,7 +105,7 @@ vendor_obj_attrs_v1_size (bfd *abfd, int vendor)
list = list->next)
size += obj_attr_v1_size (list->tag, &list->attr);
- /* <size> <vendor_name> NUL 0x1 <size> */
+ /* <size> <vendor_name> NUL 0x1 <size> */
return (size
? size + 10 + strlen (vendor_name)
: 0);
@@ -118,7 +118,51 @@ bfd_elf_obj_attrs_v1_size (bfd *abfd)
size = vendor_obj_attrs_v1_size (abfd, OBJ_ATTR_PROC);
size += vendor_obj_attrs_v1_size (abfd, OBJ_ATTR_GNU);
if (size > 0)
- size += sizeof(uint8_t); /* <format-version: ‘A’> */
+ size += sizeof(uint8_t); /* <format-version: 'A'> */
+ return size;
+}
+
+/* Return the size of a single attribute. */
+static bfd_vma
+obj_attr_v2_size (obj_attr_v2 *attr, obj_attr_encoding_v2 type)
+{
+ bfd_vma size;
+
+ size = uleb128_size (attr->tag);
+ if (type == ULEB128)
+ size += uleb128_size (attr->vals.uint_val);
+ if (type == NTBS)
+ size += strlen (attr->vals.string_val) + 1; /* +1 for '\0'. */
+ return size;
+}
+
+/* Return the size of a subsection. */
+static bfd_vma
+obj_attr_subsection_v2_size (obj_attr_subsection_v2 *subsec)
+{
+ bfd_vma size = sizeof(uint32_t); /* <uint32: subsection-length> */
+ size += strlen (subsec->name) + 1; /* NTBS: vendor-name so +1 for '\0'. */
+ size += 2 * sizeof(uint8_t); /* <uint8: optional> <uint8: parameter type> */
+ /* <attribute>* */
+ for (obj_attr_v2 *attr = subsec->first_;
+ attr != NULL;
+ attr = attr->next)
+ size += obj_attr_v2_size (attr, subsec->encoding);
+ return size;
+}
+
+/* Return the size of an build attributes section. */
+static bfd_vma
+vendor_section_obj_attr_v2_size (bfd *abfd)
+{
+ obj_attr_subsection_v2 *subsec = elf_obj_attr_subsections (abfd).first_;
+ if (subsec == NULL)
+ return 0;
+
+ bfd_vma size = sizeof(uint8_t); /* <format-version: 'A'> */
+ /* [ <uint32: subsection-length> NTBS: vendor-name <bytes: vendor-data> ]* */
+ for (; subsec != NULL; subsec = subsec->next)
+ size += obj_attr_subsection_v2_size (subsec);
return size;
}
@@ -126,7 +170,9 @@ bfd_elf_obj_attrs_v1_size (bfd *abfd)
bfd_vma
bfd_elf_obj_attr_size (bfd *abfd)
{
- return bfd_elf_obj_attrs_v1_size (abfd);
+ return (get_elf_backend_data (abfd)->obj_attrs_version == 2)
+ ? vendor_section_obj_attr_v2_size (abfd)
+ : bfd_elf_obj_attrs_v1_size (abfd);
}
/* Write VAL in uleb128 format to P, returning a pointer to the
@@ -213,7 +259,7 @@ write_obj_attr_section_v1 (bfd *abfd, bfd_byte *buffer, bfd_vma size)
{
bfd_byte *p = buffer;
- /* <format-version: ‘A’> */
+ /* <format-version: 'A'> */
*(p++) = 'A';
for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor)
@@ -228,11 +274,112 @@ write_obj_attr_section_v1 (bfd *abfd, bfd_byte *buffer, bfd_vma size)
BFD_ASSERT (p <= buffer + size);
}
+static bfd_byte *
+write_obj_attr_v2 (bfd_byte *p, obj_attr_v2* attr, obj_attr_encoding_v2 type)
+{
+ p = write_uleb128 (p, attr->tag);
+ switch (type)
+ {
+ case ULEB128:
+ {
+ p = write_uleb128 (p, attr->vals.uint_val);
+ }
+ break;
+ case NTBS:
+ {
+ size_t len = strlen (attr->vals.string_val) + 1; /* +1 for '\0'. */
+ memcpy (p, attr->vals.string_val, len);
+ p += len;
+ }
+ break;
+ }
+ return p;
+}
+
+static bfd_byte *
+write_obj_attr_subsection_v2 (bfd *abfd,
+ obj_attr_subsection_v2* subsec,
+ bfd_byte *p)
+{
+ /* <uint32: subsection-length> */
+ bfd_vma subsec_size = obj_attr_subsection_v2_size (subsec);
+ bfd_put_32 (abfd, subsec_size, p);
+ p += sizeof (uint32_t);
+
+ /* NTBS: vendor-name */
+ size_t vendor_name_size = strlen (subsec->name) + 1; /* +1 for '\0'. */
+ memcpy (p, subsec->name, vendor_name_size);
+ p += vendor_name_size;
+
+ /* -- <bytes: vendor-data> -- */
+ /* <uint8: optional> */
+ p = write_uleb128 (p, subsec->optional);
+ /* <uint8: parameter type> */
+ p = write_uleb128 (p, subsec->encoding);
+ /* <attribute>* */
+ for (obj_attr_v2 *attr = subsec->first_; attr != NULL; attr = attr->next)
+ p = write_obj_attr_v2 (p, attr, subsec->encoding);
+ return p;
+}
+
+static void
+obj_attr_subsection_v2_sort (obj_attr_subsection_list *plist)
+{
+ for (obj_attr_subsection_v2 *subsec = plist->first_;
+ subsec != NULL;
+ subsec = subsec->next)
+ LINKED_LIST_MERGE_SORT(obj_attr_v2) (subsec, _bfd_elf_obj_attr_v2_cmp);
+
+ LINKED_LIST_MERGE_SORT(obj_attr_subsection_v2)
+ (plist, _bfd_elf_obj_attr_subsection_v2_cmp);
+}
+
+static void
+write_obj_attr_section_v2 (bfd *abfd, bfd_byte *buffer, bfd_vma size)
+{
+ bfd_vma section_size = vendor_section_obj_attr_v2_size (abfd);
+ if (section_size == 0)
+ return;
+
+ bfd_byte *p = buffer;
+
+ /* <format-version: 'A'> */
+ *(p++) = 'A';
+
+ /* [ <uint32: subsection-length> NTBS: vendor-name <bytes: vendor-data> ]* */
+ for (obj_attr_subsection_v2* subsec = elf_obj_attr_subsections (abfd).first_;
+ subsec != NULL;
+ subsec = subsec->next)
+ p = write_obj_attr_subsection_v2 (abfd, subsec, p);
+
+ /* We didn't overrun the buffer. */
+ BFD_ASSERT (p <= buffer + size);
+ /* We wrote as many data as it was computed by
+ vendor_section_obj_attr_using_subsections_size(). */
+ BFD_ASSERT (section_size == (long unsigned int)(p - buffer));
+}
+
+/* Finalize the content of object attributes before writing. */
+void
+bfd_elf_obj_attr_finalize_content (bfd *abfd)
+{
+ if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
+ /* Before dumping the data, sort subsections in alphabetical order, and
+ attributes according to their tag in numerical order. This is useful
+ for diagnostic tools so that they dump the same output even if the
+ subsections or their attributes were not declared in the same order in
+ different files. */
+ obj_attr_subsection_v2_sort (&elf_obj_attr_subsections (abfd));
+}
+
/* Write the contents of the object attributes section to CONTENTS. */
void
bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *buffer, bfd_vma size)
{
- write_obj_attr_section_v1 (abfd, buffer, size);
+ if (get_elf_backend_data (abfd)->obj_attrs_version == 2)
+ write_obj_attr_section_v2 (abfd, buffer, size);
+ else
+ write_obj_attr_section_v1 (abfd, buffer, size);
}
/* Allocate/find an object attribute. */
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 6c326d5db72..3e825299a56 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -3064,6 +3064,7 @@ extern bfd *_bfd_elf64_bfd_from_remote_memory
int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type));
extern bfd_vma bfd_elf_obj_attr_size (bfd *);
+extern void bfd_elf_obj_attr_finalize_content (bfd *);
extern void bfd_elf_set_obj_attr_contents (bfd *, bfd_byte *, bfd_vma);
extern int bfd_elf_get_obj_attr_int (bfd *, int, unsigned int);
extern obj_attribute *bfd_elf_add_obj_attr_int
diff --git a/gas/write.c b/gas/write.c
index 476d8e42081..2b5da1970a8 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1939,6 +1939,8 @@ create_obj_attrs_section (void)
bfd_set_section_flags (s, SEC_READONLY | SEC_HAS_CONTENTS | SEC_DATA);
frag_now_fix ();
char *p = frag_more (size);
+
+ bfd_elf_obj_attr_finalize_content (stdoutput);
bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size);
subsegs_finish_section (s);
--
2.49.0
More information about the Binutils
mailing list