[PATCH v5 17/20] gnu directives: add support for gnu_attribute and gnu_subsection in OAv2 context

Matthieu Longo matthieu.longo@arm.com
Mon Jul 7 16:49:34 GMT 2025


This patch adds support for the GNU directives .gnu_attribute and
.gnu_subsection, used respectively for OAv1 and OAv2, and for OAv2 only.
These directives behave like their AEABI counterparts, as they are aliases
intended for use by any backends supporting OAv1 and/or OAv2. Their
availability is controlled by the TC_OBJ_ATTR_v1 and TC_OBJ_ATTR_v2 macros,
which are defined via TC_<target>.

Previously, the "gnu" subsection namespace was used only for
"gnu-testing" and defaulted to a private scope. This patch updates the
scope recognition to correctly distinguish between private usage (e.g.,
testing) and public usage (e.g., actual GNU subsections storing public
information).
---
 bfd/elf-attrs.c           |  9 ++---
 binutils/readelf.c        |  4 ++-
 gas/config/obj-elf-attr.c |  9 ++---
 gas/config/obj-elf.c      | 24 +++++++++++++
 gas/doc/as.texi           | 74 +++++++++++++++++++++++++++++++++++----
 5 files changed, 105 insertions(+), 15 deletions(-)

diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
index 575d583dad5..8a756cb62c6 100644
--- a/bfd/elf-attrs.c
+++ b/bfd/elf-attrs.c
@@ -2602,10 +2602,11 @@ oav2_parse_subsection (bfd *abfd,
     }
 
   const char *vendor_name = get_elf_backend_data (abfd)->obj_attrs_vendor;
-  obj_attr_subsection_scope_v2 scope =
-    (strncmp (subsection_name, vendor_name, strlen (vendor_name)) == 0)
-    ? OA_SUBSEC_PUBLIC
-    : OA_SUBSEC_PRIVATE;
+  obj_attr_subsection_scope_v2 scope = OA_SUBSEC_PRIVATE;
+  if (strncmp (subsection_name, vendor_name, strlen (vendor_name)) == 0
+      || (strncmp (subsection_name, "gnu", 3) == 0
+	  && strncmp (subsection_name + 3, "-testing", 8) != 0))
+    scope = OA_SUBSEC_PUBLIC;
 
   obj_attr_subsection_v2 *subsec =
     _bfd_elf_obj_attr_subsection_v2_init (subsection_name, scope, optional_raw,
diff --git a/binutils/readelf.c b/binutils/readelf.c
index afefdc388fe..4bb7bc0d170 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -19619,7 +19619,9 @@ elf_parse_attrs_subsection_v2 (unsigned char *cursor,
       const char *subsec_name = (const char *) cursor;
       printf (_(" - Name:	  %s\n"), subsec_name);
       bool public_subsection =
-	strncmp (subsec_name, public_name, strlen (public_name)) == 0;
+	strncmp (subsec_name, public_name, strlen (public_name)) == 0
+	|| (strncmp (subsec_name, "gnu", 3) == 0
+	    && strncmp (subsec_name + 3, "-testing", 8) != 0);
       cursor += subsection_name_len;
       op.read += subsection_name_len;
 
diff --git a/gas/config/obj-elf-attr.c b/gas/config/obj-elf-attr.c
index 710a93d6c74..0e1591c1955 100644
--- a/gas/config/obj-elf-attr.c
+++ b/gas/config/obj-elf-attr.c
@@ -969,10 +969,11 @@ obj_attr_v2_subsection_record (const char *name,
     {
       const char *vendor_name =
 	get_elf_backend_data (stdoutput)->obj_attrs_vendor;
-      obj_attr_subsection_scope_v2 scope =
-	(strncmp (name, vendor_name, strlen (vendor_name)) == 0)
-	? OA_SUBSEC_PUBLIC
-	: OA_SUBSEC_PRIVATE;
+      obj_attr_subsection_scope_v2 scope = OA_SUBSEC_PRIVATE;
+      if (strncmp (name, vendor_name, strlen (vendor_name)) == 0
+	  || (strncmp (name, "gnu", 3) == 0
+	      && strncmp (name + 3, "-testing", 8) != 0))
+	scope = OA_SUBSEC_PUBLIC;
 
       obj_attr_subsection_v2 *new_subsection =
 	_bfd_elf_obj_attr_subsection_v2_init (name, scope, optional, encoding);
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index bf34a52616d..af7c039419a 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -76,6 +76,9 @@ static void obj_elf_popsection (int);
 #if (TC_OBJ_ATTR_v1 || TC_OBJ_ATTR_v2)
 static void obj_elf_gnu_attribute (int);
 #endif /* (TC_OBJ_ATTR_v1 || TC_OBJ_ATTR_v2) */
+#if (TC_OBJ_ATTR_v2)
+static void obj_elf_gnu_subsection (int);
+#endif /* TC_OBJ_ATTR_v2 */
 #endif /* TC_OBJ_ATTR */
 static void obj_elf_tls_common (int);
 static void obj_elf_lcomm (int);
@@ -125,6 +128,9 @@ static const pseudo_typeS elf_pseudo_table[] =
 #if (TC_OBJ_ATTR_v1 || TC_OBJ_ATTR_v2)
   {"gnu_attribute", obj_elf_gnu_attribute, 0},
 #endif /* (TC_OBJ_ATTR_v1 || TC_OBJ_ATTR_v2) */
+#if (TC_OBJ_ATTR_v2)
+  {"gnu_subsection", obj_elf_gnu_subsection, 0},
+#endif /* TC_OBJ_ATTR_v2 */
 #endif /* TC_OBJ_ATTR */
 
   /* These are used for dwarf2.  */
@@ -2064,6 +2070,24 @@ obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
 }
 #endif /* (TC_OBJ_ATTR_v1 || TC_OBJ_ATTR_v2) */
 
+#if (TC_OBJ_ATTR_v2)
+/* Parse a .gnu_subsection directive.  */
+
+static void
+obj_elf_gnu_subsection (int ignored ATTRIBUTE_UNUSED)
+{
+  obj_attr_version_t version = elf_obj_attr_version (stdoutput);
+  if (version < OBJ_ATTR_V2)
+    {
+      as_bad (_(".gnu_subsection is only available with object attributes v2,"
+		" and the current target only supports object attributes v1"));
+      ignore_rest_of_line ();
+      return;
+    }
+  obj_attr_process_subsection ();
+}
+#endif /* TC_OBJ_ATTR_v2 */
+
 #endif /* TC_OBJ_ATTR */
 
 void
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 52f863f26b8..9fd6b720f11 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -4593,6 +4593,7 @@ Some machine configurations provide additional directives.
 * Func::                        @code{.func}
 * Global::                      @code{.global @var{symbol}}, @code{.globl @var{symbol}}
 @ifset ELF
+* Gnu_subsection::              @code{.gnu_subsection @var{name}, @var{comprehension}, @var{encoding}}
 * Gnu_attribute::               @code{.gnu_attribute @var{tag},@var{value}}
 * Hidden::                      @code{.hidden @var{names}}
 @end ifset
@@ -5740,6 +5741,10 @@ partial programs.  You may need the HPPA-only @code{.EXPORT} directive as well.
 @end ifset
 
 @ifset ELF
+@node Gnu_subsection
+@section @code{.gnu_subsection @var{name}, @var{comprehension}, @var{encoding}}
+Record a @sc{gnu} object attribute subsection for this file.  @xref{Object Attributes}
+
 @node Gnu_attribute
 @section @code{.gnu_attribute @var{tag},@var{value}}
 Record a @sc{gnu} object attribute for this file.  @xref{Object Attributes}.
@@ -7956,6 +7961,25 @@ This information is useful during and after linking.  At link time,
 time, tools like @command{gdb} can use it to process the linked file
 correctly.
 
+Two versions of object attributes are currently in use:
+@itemize @bullet{}
+@item
+Object Attributes version 1 (OAv1) used by: ARC, ARM, C-SKY, MIPS, MSP430, M68K,
+PowerPC, RISC-V, SPARC, s390, and TIC6X.
+@item
+Object Attributes version 2 (OAv2) used by: AArch64.
+@end itemize
+
+@menu
+* Object Attributes v1::                Object Attributes v1
+* Object Attributes v2::                Object Attributes v2
+* GNU Object Attributes::               @sc{gnu} Object Attributes
+* Defining New Object Attributes::      Defining New Object Attributes
+@end menu
+
+@node Object Attributes v1
+@section Object Attributes v1
+
 Compatibility information is recorded as a series of object attributes.  Each
 attribute has a @dfn{vendor}, @dfn{tag}, and @dfn{value}.  The vendor is a
 string, and indicates who sets the meaning of the tag.  The tag is an integer,
@@ -7963,13 +7987,51 @@ and indicates what property the attribute describes.  The value may be a string
 or an integer, and indicates how the property affects this object.  Missing
 attributes are the same as attributes with a zero value or empty string value.
 
-Object attributes were developed as part of the ABI for the ARM Architecture.
-The file format is documented in @cite{ELF for the ARM Architecture}.
+Object Attributes v1 (OAv1) were developed as part of the ABI for the ARM
+Architecture.
+The file format is documented in @cite{Addenda to, and Errata in, the ABI for
+the Arm® Architecture}.
 
-@menu
-* GNU Object Attributes::               @sc{gnu} Object Attributes
-* Defining New Object Attributes::      Defining New Object Attributes
-@end menu
+@node Object Attributes v2
+@section Object Attributes v2
+
+Object Attributes v2 (OAv2) is the successor of OAv1. OAv1's complexity makes
+parsing and skipping subsections or attributes challenging, especially for the
+main consumers, the linkers, which are responsible to merge them, and enforce
+compatibility.
+
+To address these limitations, a new specification for object attributes was
+proposed. Key design goals of OAv2 include:
+@itemize @bullet{}
+@item
+Retaining successful aspects of OAv1.
+@item
+Defining the relationship between build attributes and the existing GNU program
+properties.
+@item
+Separating architectural requirements from software ABI requirements.
+@item
+Simplifying the format to allow consumers to skip a subsection or attribute
+that it does not understand without giving a warning message.
+@end itemize
+
+OAv2 share common concepts of @dfn{vendor}, @dfn{tag} and @dfn{value} with OAv1,
+and also introduce the new ones like @dfn{subsection} and @dfn{scope}.
+Attributes with common properties are grouped into subsections.  All the
+attributes in a subsection share the same encoding, comprehension, and scope.
+A subsection starting with the vendor name is considered public.  The value of
+an attribute may be a string or an integer depending on the encoding set on its
+subsection.
+
+The @code{.gnu_subsection} directive creates a new subsection or switch to the
+subsection if it has already been declared.  The @code{.gnu_attribute} directive
+records an object attribute in the current subsection.
+Those directives are valid on all the architectures that support OAv2.
+
+Object attributes v2 were developed as part of the ABI for the AArch64
+architecture.
+The file format is documented in @cite{Build Attributes for the Arm® 64-bit
+Architecture (AArch64)}
 
 @node GNU Object Attributes
 @section @sc{gnu} Object Attributes
-- 
2.50.0



More information about the Binutils mailing list