[PATCH v9 16/19] gnu directives: add support for gnu_attribute and gnu_subsection in OAv2 context
Matthieu Longo
matthieu.longo@arm.com
Thu Nov 6 16:39:51 GMT 2025
On 31/10/2025 12:48, Jan Beulich wrote:
> On 01.09.2025 18:56, Matthieu Longo wrote:
>> 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>.
>
> This last part of the sentence looks stale?
>
Fixed in the next revision. I removed the last part of the sentence that
is not relevant anymore.
>> --- a/bfd/elf-attrs.c
>> +++ b/bfd/elf-attrs.c
>> @@ -2667,10 +2667,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
>> + && !gnu_testing_namespace (subsection_name)))
>> + scope = OA_SUBSEC_PUBLIC;
>>
>> *subsec = _bfd_elf_obj_attr_subsection_v2_init
>> (subsection_name, scope, comprehension_raw, value_encoding);
>> --- a/binutils/readelf.c
>> +++ b/binutils/readelf.c
>> @@ -20014,7 +20014,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;
>>
>> --- a/gas/config/obj-elf-attr.c
>> +++ b/gas/config/obj-elf-attr.c
>> @@ -1078,10 +1078,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;
>
> Three times the effectively same check - shouldn't there be a helper centralizing
> this?
>
See my reply in patch 9/19.
I moved the code to this helper:
/* Identify the scope of a subsection from its name. */
obj_attr_subsection_scope_v2
bfd_elf_obj_attr_subsection_v2_scope (bfd *abfd, const char *subsec_name)
{
const char *vendor_name = get_elf_backend_data (abfd)->obj_attrs_vendor;
obj_attr_subsection_scope_v2 scope = OA_SUBSEC_PRIVATE;
size_t vendor_name_len = strlen (vendor_name);
if ((strncmp (subsec_name, vendor_name, vendor_name_len) == 0
&& subsec_name[vendor_name_len] == '_')
|| (strncmp (subsec_name, "gnu_", 4) == 0
&& !gnu_testing_namespace (subsec_name)))
scope = OA_SUBSEC_PUBLIC;
return scope;
}
>> --- a/gas/config/obj-elf.c
>> +++ b/gas/config/obj-elf.c
>> @@ -75,6 +75,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)
>
> No need for parentheses?
>
Fixed in the next revision.
>> @@ -2092,6 +2098,41 @@ obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
>> }
>> #endif /* (TC_OBJ_ATTR_v1 || TC_OBJ_ATTR_v2) */
>>
>> +#if (TC_OBJ_ATTR_v2)
>> +/* Return True if the VERSION of object attributes supports subsections, False
>> + otherwise. */
>> +
>> +static inline bool
>> +attr_fmt_has_subsections (obj_attr_version_t version)
>> +{
>> + switch (version)
>> + {
>> + case OBJ_ATTR_V1:
>> + return false;
>> + case OBJ_ATTR_V2:
>> + return true;
>> + default:
>> + abort (); /* Unsupported format. */
>> + }
>> +}
>> +
>> +/* 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 (! attr_fmt_has_subsections (version))
>> + {
>> + as_bad (_(".gnu_subsection is only available with object attributes v2,"
>> + " and the current target only supports object attributes v1"));
>
> This message, first of all, is liable to go stale the moment some target supports
> both v1 and v2.
The version specified in the backend corresponds to the only-supported
output format for a given backend. If a backend wants to migrate, and
sets this to OAv2, it means that no object with OAv1 can be generated
with this version of binutils. However, OAv1 objects would be accepted
at link time, but the resulting build artifact will only contain OAv2. I
said "would" because this requires a translation layer implemented by
the backend, and there is no such example today.
How is this relevant to parsing ?
For parsing, nowhere the spec mentioned a way to indicate what version
of OAv1 or OAv2 is used in an assembly file. If you look at the cover
letter, I proposed a flag --obj-attr=[OAv1|OAv2] for such a use case,
but I would say that adding such an option is out of scope for this
patch series. This option would allow a period where files can be
migrated one by one, instead of migrating everything at the same time.
If the approach of a command line option were adopted, the check should
use a value other than elf_obj_attr_version (stdoutput) (i.e. the
preferred output format), which would store the command line option value.
Given that this option is hypothetical until someone decides to go
through a migration, I would recommend not to pay too much attention to
this check. What is you opinion about this given the previous explanation ?
> I also think (see other respective remarks elsewhere) that the>
diagnostic is too long. AT the very least the second "object attributes"
looks
> redundant, for example.
>
Yes, I agree. What about this simpler sentence, but a bit vague in my
opinion.
".gnu_subsection is only available with object attributes v2"
or
"unknown directive '.gnu_subsection'. Do you mean using object
attributes v2 instead ?"
The issue with this last sentence is that I would expect a suggestion
with an option like:
"'--obj-attr=OAv1' is not compatible with '.gnu_subsection'. Remove this
option to use the latest version."
OAv2 being the default when no option is specified.
But again, binutils does not provide such an option for now.
What would you suggest ?
>> @@ -5745,6 +5746,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}
>
> Here you document the new directive, whereas ...
>
>> @@ -7954,32 +7959,62 @@ Many architectures support incompatible variations. For instance, floating
>> point arguments might be passed in floating point registers if the object file
>> requires hardware floating point support---or floating point arguments might be
>> passed in integer registers if the object file supports processors with no
>> -hardware floating point unit. Or, if two objects are built for different
>> -generations of the same architecture, the combination may require the
>> -newer generation at run-time.
>> -
>> -This information is useful during and after linking. At link time,
>> -@command{@value{LD}} can warn about incompatible object files. After link
>> -time, tools like @command{gdb} can use it to process the linked file
>> -correctly.
>> +hardware floating point unit. Another example might be when two object files
>> +make use of different architectural extensions: the final image will require
>> +both features to be supported at runtime; or if the features are mutually
>> +exclusive, the linker can issue a diagnostic.
>>
>> -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,
>> -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.
>> +@command{@value{AS}} currently supports two versions of object attributes:
>> +@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
>>
>> -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 are only supported when generating ELF format.
>>
>> @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
>> +
>> +In Object Attributes v1 (OAv1) Compatibility information is recorded as a series
>> +of object attributes. Each attribute has a @dfn{vendor}, @dfn{tag}, and
>> +@dfn{value}. The @dfn{vendor} is a string, and indicates who sets the meaning
>> +of the tag. The @dfn{tag} is an integer, and indicates what property the
>> +attribute describes. The @dfn{value} may be a string or an integer, and
>> +indicates how the property affects this object. Integer tags generally default
>> +to 0, while string tags default to the empty string. Tags are only recorded in
>> +the file if they have a non-default value.
>> +
>> +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}.
>> +
>> +@node Object Attributes v2
>> +@section Object Attributes v2
>> +
>> +Object Attributes v2 (OAv2) share common concepts of @dfn{vendor}, @dfn{tag}
>> +and @dfn{value} with OAv1, but 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.
>> +
>> +OAv2 is only used by AArch64. Directives are documented in @ref{AArch64
>> +Directives}. The file format is documented in @cite{Build Attributes for the
>> +Arm 64-bit Architecture (AArch64)}.
>
> ... here you refer to something living elsewhere.
>
> Jan
I am not sure that I understand what your concern is with the current
documentation.
Do you mean that I should remove the reference "@xref{Object
Attributes}" because the link between this directive, and the
explanation of what OAv2 are is not clear, or at least not directly
related ?
Please could you elaborate ?
Matthieu
More information about the Binutils
mailing list