[PATCH 3/4] ELF: SHF_STRINGS isn't really tied to SHF_MERGE
Richard Sandiford
richard.sandiford@arm.com
Wed Jan 15 18:03:52 GMT 2025
Jan Beulich <jbeulich@suse.com> writes:
> It's not overly useful without it, but the spec doesn't name any
> dependency between the two. People may want to use it for purely
> informational purposes, for example. Adjust, in particular, entity size
> processing to be engaged if either flag is set, as mandated by the spec.
>
> --- a/bfd/elf.c
> +++ b/bfd/elf.c
> @@ -846,7 +846,10 @@ _bfd_elf_make_section_from_shdr (bfd *ab
> newsect->entsize = hdr->sh_entsize;
> }
> if ((hdr->sh_flags & SHF_STRINGS) != 0)
> - flags |= SEC_STRINGS;
> + {
> + flags |= SEC_STRINGS;
> + newsect->entsize = hdr->sh_entsize;
> + }
> if ((hdr->sh_flags & SHF_TLS) != 0)
> flags |= SEC_THREAD_LOCAL;
> if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
> @@ -3709,7 +3712,10 @@ elf_fake_sections (bfd *abfd, asection *
> this_hdr->sh_entsize = asect->entsize;
> }
> if ((asect->flags & SEC_STRINGS) != 0)
> - this_hdr->sh_flags |= SHF_STRINGS;
> + {
> + this_hdr->sh_flags |= SHF_STRINGS;
> + this_hdr->sh_entsize = asect->entsize;
> + }
> if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
> this_hdr->sh_flags |= SHF_GROUP;
> if ((asect->flags & SEC_THREAD_LOCAL) != 0)
> --- a/gas/doc/as.texi
> +++ b/gas/doc/as.texi
> @@ -7001,17 +7001,18 @@ Note - some sections, eg @code{.text} an
> special and have fixed types. Any attempt to declare them with a different
> type will generate an error from the assembler.
>
> -If @var{flags} contains the @code{M} symbol then the @var{type} argument must
> -be specified as well as an extra argument---@var{entsize}---like this:
> +If @var{flags} contains the @code{M} and/or @code{S} symbol then the @var{type}
> +argument must be specified as well as an extra argument---@var{entsize}---like
> +this:
>
> @smallexample
> .section @var{name} , "@var{flags}"M, @@@var{type}, @var{entsize}
> @end smallexample
>
> Sections with the @code{M} flag but not @code{S} flag must contain fixed size
> -constants, each @var{entsize} octets long. Sections with both @code{M} and
> -@code{S} must contain zero terminated strings where each character is
> -@var{entsize} bytes long. The linker may remove duplicates within sections with
> +constants, each @var{entsize} octets long. Sections with @code{S} must contain
> +zero terminated strings where each character is @var{entsize} bytes long. For
> +@code{M} sections the linker may remove duplicates within sections with
> the same name, same entity size and same flags. @var{entsize} must be an
> absolute expression. For sections with both @code{M} and @code{S}, a string
> which is a suffix of a larger string is considered a duplicate. Thus
We have a codebase that made a lot of use of constructs like:
.section .rodata.foo, "aS"
foo:
.asciz "..."
which after this patch need to become:
.section .rodata.foo, "aS", @progbits, 1
foo:
.asciz "..."
The codebase is being changed to use the longer form. But it kind-of
feels a bit redundant. How about assuming that the entry size for
a string is 1 (i.e. that the string is has single-byte characters)
if no size is explicitly given, just like we assume @progbits for most
sections when no type is given?
If instead we require users to update their code, it would be worth
mentioning the change in gas/NEWS.
Thanks,
Richard
> @@ -7031,8 +7032,8 @@ is not generally a good idea as section
> time, but the facility is provided for testing purposes. An index of zero is
> allowed. It indicates that the linked-to section has already been discarded.
>
> -Note: If both the @var{M} and @var{o} flags are present, then the fields
> -for the Merge flag should come first, like this:
> +Note: If both one of @var{M} or @var{S} and @var{o} flags are present, then the
> +fields for the Merge/String flag should come first, like this:
>
> @smallexample
> .section @var{name},"@var{flags}"Mo,@@@var{type},@var{entsize},@var{SymbolName}
> @@ -7055,8 +7056,8 @@ indicates that only one copy of this sec
> an alias for comdat
> @end table
>
> -Note: if both the @var{M} and @var{G} flags are present then the fields for
> -the Merge flag should come first, like this:
> +Note: Uf both one of @var{M} or @var{S} and @var{G} flags are present then the
> +fields for the Merge/String flag should come first, like this:
>
> @smallexample
> .section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}]
> --- a/gas/config/obj-elf.c
> +++ b/gas/config/obj-elf.c
> @@ -809,7 +809,7 @@ change_section (const char *name,
> = match_p->linked_to_symbol_name;
>
> bfd_set_section_flags (sec, flags);
> - if (flags & SEC_MERGE)
> + if (flags & (SEC_MERGE | SEC_STRINGS))
> sec->entsize = entsize;
> elf_group_name (sec) = match_p->group_name;
>
> @@ -864,7 +864,8 @@ change_section (const char *name,
> processor or application specific attribute as suspicious? */
> elf_section_flags (sec) = attr;
>
> - if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
> + if ((flags & (SEC_MERGE | SEC_STRINGS))
> + && old_sec->entsize != (unsigned) entsize)
> as_bad (_("changed section entity size for %s"), name);
> }
> }
> @@ -1318,36 +1319,39 @@ obj_elf_section (int push)
> }
>
> SKIP_WHITESPACE ();
> - if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',')
> + if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0
> + && *input_line_pointer == ',')
> {
> ++input_line_pointer;
> SKIP_WHITESPACE ();
> if (inherit && *input_line_pointer == ','
> - && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
> + && (bfd_section_flags (now_seg)
> + & (SEC_MERGE | SEC_STRINGS)) != 0)
> goto fetch_entsize;
> entsize = get_absolute_expression ();
> SKIP_WHITESPACE ();
> if (entsize <= 0)
> {
> - as_warn (_("invalid merge entity size"));
> - attr &= ~SHF_MERGE;
> + as_warn (_("invalid merge / string entity size"));
> + attr &= ~(SHF_MERGE | SHF_STRINGS);
> entsize = 0;
> }
> }
> - else if ((attr & SHF_MERGE) != 0 && inherit
> - && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
> + else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && inherit
> + && (bfd_section_flags (now_seg)
> + & (SEC_MERGE | SEC_STRINGS)) != 0)
> {
> fetch_entsize:
> entsize = now_seg->entsize;
> }
> - else if ((attr & SHF_MERGE) != 0)
> + else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0)
> {
> - as_warn (_("entity size for SHF_MERGE not specified"));
> - attr &= ~SHF_MERGE;
> + as_warn (_("entity size for SHF_MERGE / SHF_STRINGS not specified"));
> + attr &= ~(SHF_MERGE | SHF_STRINGS);
> }
>
> - if ((attr & SHF_MERGE) != 0 && type == SHT_NOBITS)
> - as_warn (_("bogus SHF_MERGE for SHT_NOBITS section"));
> + if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && type == SHT_NOBITS)
> + as_warn (_("bogus SHF_MERGE / SHF_STRINGS for SHT_NOBITS section"));
>
> if ((attr & SHF_LINK_ORDER) != 0 && *input_line_pointer == ',')
> {
> --- a/gas/write.c
> +++ b/gas/write.c
> @@ -1864,7 +1864,7 @@ subsegs_finish_section (asection *s)
> do_not_pad_sections_to_alignment = 1;
>
> alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
> - if ((bfd_section_flags (now_seg) & SEC_MERGE)
> + if ((bfd_section_flags (now_seg) & (SEC_MERGE | SEC_STRINGS))
> && now_seg->entsize)
> {
> unsigned int entsize = now_seg->entsize;
More information about the Binutils
mailing list