[PATCH v8 04/19] gas: implement parsing of object attributes v2

Jan Beulich jbeulich@suse.com
Wed Aug 27 15:45:30 GMT 2025


On 27.08.2025 17:17, Matthieu Longo wrote:
> On 2025-08-06 16:05, Jan Beulich wrote:
>> On 06.08.2025 16:02, Matthieu Longo wrote:
>>> On 2025-07-31 15:40, Jan Beulich wrote:
>>>> On 15.07.2025 13:39, Matthieu Longo wrote:
>>>>> --- a/bfd/elf-attrs.c
>>>>> +++ b/bfd/elf-attrs.c
>>>>> @@ -255,8 +255,152 @@ bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *buffer, bfd_vma size)
>>>>>      write_obj_attr_section_v1 (abfd, buffer, size);
>>>>>    }
>>>>>    
>>>>> +/* The first two tags in gnu-testing namespace are known, and so have a name and
>>>>> +   can be initialized to the default value ('0' or NULL) depending on the
>>>>> +   encoding specified on the subsection.  Any tags above 1 will be considered
>>>>> +   unknown, so will be default initialized in the same way but its status will
>>>>> +   be set to obj_attr_subsection_v2_unknown.  */
>>>>> +static const obj_attr_info_t known_tags_gnu_testing[] =
>>>>> +{
>>>>> +  {
>>>>> +    .tag = {"GNUTestTag_0", .value = {
>>>>> +      .val.u32 = 0,
>>>>> +      .vtype = VALUE_U32
>>>>> +    }},
>>>>> +    .default_value = {.val.u64 = 0, .vtype = VALUE_UNSIGNED_INTEGER},
>>>>> +    .encoding = OA_ENC_ULEB128,
>>>>> +  },
>>>>> +  {
>>>>> +    .tag = {"GNUTestTag_1", .value = {
>>>>> +      .val.u32 = 1,
>>>>> +      .vtype = VALUE_U32
>>>>> +    }},
>>>>> +    .default_value = {.val.u64 = 0, .vtype = VALUE_UNSIGNED_INTEGER},
>>>>> +    .encoding = OA_ENC_ULEB128,
>>>>> +  },
>>>>> +};
>>>>
>>>> I went to look at the doc referenced by [2] in the cover letter, but I couldn't
>>>> find anything there about the known-ness of these two tags.
>>>>
>>>
>>> Those two tags were added for testing purpose only, they are not defined
>>> in the specifications. Ideally they should only be available for testing
>>> via a runtime flag, or maybe developer mode and disabled for release.
>>>
>>> Richard Earnshaw and I discussed this issue off-line previously, he
>>> agreed that it is not ideal to do a release build with those.
>>>
>>> However, there is neither existing define to check whether the project
>>> was compiled in maintainer mode or release mode, nor a runtime flag for
>>> a testing mode. We decided to postpone this discussion later as it would
>>> involve introducing new flags or add a new define for the build mode.
>>> This would extend the scope of the patch series again, and we certainly
>>> don't want that given the size of this patch series.
>>
>> In a recent patch of mine I had the need to tell release builds from debug
>> ones, and I came up with the check you can now find in gas'es
>> perform_an_assembly_pass(). See commit 7b40f4c6587c ("gas: add a means to
>> programmatically determine the assembler version").
>>
> 
> I tried to address this concern as a part of 
> https://inbox.sourceware.org/binutils/20250814151629.174026-1-matthieu.longo@arm.com/.
> 
> I am not sure how to progress on this after the concern you raised on 
> potential conflicts with some distro's versioning, and that I cannot 
> rely on either gas or ld to determine the release mode.

I've replied there with another (not entirely nice, but hopefully workable)
suggestion.

>>>>> +/* Extract an integer literal from the input.
>>>>> +   Anything matched by O_constant is considered an integer literal (see the
>>>>> +   usage of O_constant in expr.c to see all the matches.  */
>>>>
>>>> But an expression the value of is known only at the end of assembly is
>>>> deliberately not permitted?
>>
>> This was left unaddressed (unless ...
> 
> Yes, it is not permitted.

Hmm. May at least want calling out somewhere.

>>>>> +  if (exp.X_op != O_constant)
>>>>> +    {
>>>>> +      as_bad (_("invalid value, expected an integer literal"));
>>>>> +      goto bad;
>>>>> +    }
>>>>> +
>>>>> +  int64_t val = exp.X_add_number;
>>>>
>>>> Any reason not to use offsetT here (and wherever else applicable)?
>>>
>>> offsetT lets think that we are dealing with an offset here whereas we
>>> are not. This type makes the intent of the code more obscure, so I
>>> preferred to use int64_t (offsetT -> bfd_signed_vma -> int64_t).
>>
>> But hidden type conversions can be problematic, too. We use offsetT and
>> its siblings in many places where it's not offsets we're dealing with.
> 
> When you say "hidden type conversion", do you mean that it would not be 
> obvious that a conversion happened if one day for instance, someone was 
> changing offsetT to be unsigned, or being a structure, or something 
> similar ?
> 
> I could add an explicit cast as below to really make it clear that a 
> conversion could potentially happen:
>    int64_t val = (int64_t) exp.X_add_number;
> 
> Using offsetT (a higher abstraction level type) in this part of the code 
> does not really make sense as I mentioned previously. The code for OAv2 
> is dealing with raw integers, strings, then up to the backend to 
> interpret them how it needs.
> 
> What would the real benefit of using offsetT be here ?

That in a future where we want to support 128-bit targets this code wouldn't
silently break (or at least be at risk of breaking). If you absolutely want
to use int64_t, you will need to deal with possible truncation issues, even
though they're entirely theoretical as of now.

>>>>> +/* Parse an argument, and set its type accordingly depending on the input
>>>>> +   value, and the constraints on the expected argument.  */
>>>>> +static bool
>>>>> +obj_attr_parse_arg (arg_token_t expected_ttype,
>>>>> +		    bool (*match_identifier) (char c),
>>>>> +		    bool resolve_identifier,
>>>>> +		    arg_t *arg_out)
>>>>> +{
>>>>> +  const arg_token_t low_ttype = (expected_ttype & LT_MASK);
>>>>> +
>>>>> +  /* Note: symbol look-up for string literals is not available.  */
>>>>> +  if (((low_ttype & STRING) && *input_line_pointer == '"')
>>>>> +      || !(low_ttype & ~STRING))
>>>>> +    return extract_string_literal (arg_out);
>>>>> +
>>>>> +  if (((low_ttype & (UNSIGNED_INTEGER | SIGNED_INTEGER))
>>>>> +      && look_like_integer_literal (input_line_pointer))
>>>>> +      || !(low_ttype & ~(UNSIGNED_INTEGER | SIGNED_INTEGER)))
>>>>> +    return extract_integer_literal (arg_out, (low_ttype & UNSIGNED_INTEGER));
>>>>
>>>> What if someone wants to use an equate?
>>>
>>> What do you mean ?
>>> Something like the below ?
>>>     .aeabi_attribute (123 + 546), ~(2-1)
>>
>> That's expressions, which - yes - also ought to work imo. What I meant
>> with the comment is
>>
>>      .equ x, 1
>>      .eqv y, 2
>>      .aeabi_attribute x, y
>>
>> (as one of the most simple examples).
> 
> The equate is already supported. See the test 
> gas/testsuite/gas/aarch64/build-attributes/ba-1.s in patch 
> "Serialization and dumping tests of Object Attributes v2" as an example.

Hmm, okay, then I must still not have sufficiently grokked how this parsing
works.

Jan


More information about the Binutils mailing list