[v0,05/15] bfd: write object attributes v2

Message ID 20250310175131.1217374-6-matthieu.longo@arm.com
State New
Headers
Series AArch64 AEABI build attributes (a.k.a. object attributes v2) |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

Matthieu Longo March 10, 2025, 5:51 p.m. UTC
  From: Richard Ball <richard.ball@arm.com>

Co-Authored-By: Matthieu Longo <matthieu.longo@arm.com>
---
 bfd/elf-attrs.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++--
 bfd/elf-bfd.h   |   1 +
 gas/write.c     |   2 +
 3 files changed, 154 insertions(+), 4 deletions(-)
  

Comments

Jan Beulich March 11, 2025, 8:10 a.m. UTC | #1
On 10.03.2025 18:51, Matthieu Longo wrote:
> --- a/bfd/elf-attrs.c
> +++ b/bfd/elf-attrs.c
> @@ -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>*

Style nit (again here and elsewhere): Style-conforming comments please.

Jan
  
Matthieu Longo March 20, 2025, 2:17 p.m. UTC | #2
On 2025-03-11 08:10, Jan Beulich wrote:
> On 10.03.2025 18:51, Matthieu Longo wrote:
>> --- a/bfd/elf-attrs.c
>> +++ b/bfd/elf-attrs.c
>> @@ -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>*
> 
> Style nit (again here and elsewhere): Style-conforming comments please.
> 
> Jan

Fixed.
  

Patch

diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
index 634843b5162..ab3c80573e5 100644
--- a/bfd/elf-attrs.c
+++ b/bfd/elf-attrs.c
@@ -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);