From 98e6d3f5bd4e7e3cbd2718151cc54692f6740b65 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 15 Aug 2025 12:19:59 +0200 Subject: [PATCH] gas/ELF: allow specifying entity size for arbitrary sections The spec doesn't tie entity size to just SHF_MERGE and SHF_STRINGS sections. Introduce a new "section letter" 'E' to allow recording (and checking) of entity size even without 'M' or 'S'. --- bfd/elf.c | 15 +++++----- gas/NEWS | 3 ++ gas/config/obj-elf.c | 51 ++++++++++++++++++++++----------- gas/doc/as.texi | 14 +++++---- gas/testsuite/gas/elf/elf.exp | 1 + gas/testsuite/gas/elf/entsize.d | 9 ++++++ gas/testsuite/gas/elf/entsize.s | 8 ++++++ 7 files changed, 71 insertions(+), 30 deletions(-) create mode 100644 gas/testsuite/gas/elf/entsize.d create mode 100644 gas/testsuite/gas/elf/entsize.s diff --git a/bfd/elf.c b/bfd/elf.c index 596c1ec3de2..589400ec681 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -869,20 +869,16 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, else if ((flags & SEC_LOAD) != 0) flags |= SEC_DATA; if ((hdr->sh_flags & SHF_MERGE) != 0) - { - flags |= SEC_MERGE; - newsect->entsize = hdr->sh_entsize; - } + flags |= SEC_MERGE; if ((hdr->sh_flags & SHF_STRINGS) != 0) - { - flags |= SEC_STRINGS; - newsect->entsize = hdr->sh_entsize; - } + flags |= SEC_STRINGS; if ((hdr->sh_flags & SHF_TLS) != 0) flags |= SEC_THREAD_LOCAL; if ((hdr->sh_flags & SHF_EXCLUDE) != 0) flags |= SEC_EXCLUDE; + newsect->entsize = hdr->sh_entsize; + switch (elf_elfheader (abfd)->e_ident[EI_OSABI]) { /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE, @@ -3770,6 +3766,9 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE) this_hdr->sh_flags |= SHF_EXCLUDE; + if (this_hdr->sh_entsize == 0) + this_hdr->sh_entsize = asect->entsize; + /* If the section has relocs, set up a section header for the SHT_REL[A] section. If two relocation sections are required for this section, it is up to the processor-specific back-end to diff --git a/gas/NEWS b/gas/NEWS index a9858939f06..5908f769fdd 100644 --- a/gas/NEWS +++ b/gas/NEWS @@ -1,5 +1,8 @@ -*- text -*- +* ELF targets can now have section entity size specified for arbitrary + sections, using the new attribute letter 'E'. + * NaCl target support is removed. Changes in 2.45: diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c index b39c59e54b8..ccf020f5a84 100644 --- a/gas/config/obj-elf.c +++ b/gas/config/obj-elf.c @@ -792,7 +792,7 @@ change_section (const char *name, = match_p->linked_to_symbol_name; bfd_set_section_flags (sec, flags); - if (flags & (SEC_MERGE | SEC_STRINGS)) + if (entsize != 0) sec->entsize = entsize; elf_group_name (sec) = match_p->group_name; @@ -847,7 +847,7 @@ change_section (const char *name, processor or application specific attribute as suspicious? */ elf_section_flags (sec) = attr; - if ((flags & (SEC_MERGE | SEC_STRINGS)) + if (entsize != 0 && old_sec->entsize != (unsigned) entsize) as_bad (_("changed section entity size for %s"), name); } @@ -871,7 +871,8 @@ obj_elf_change_section (const char *name, static bfd_vma obj_elf_parse_section_letters (char *str, size_t len, bool push, - bool *is_clone, int *inherit, bfd_vma *gnu_attr) + bool *is_clone, int *inherit, bfd_vma *gnu_attr, + bool *has_entsize) { bfd_vma attr = 0; @@ -913,6 +914,9 @@ obj_elf_parse_section_letters (char *str, size_t len, bool push, case 'x': attr |= SHF_EXECINSTR; break; + case 'E': + *has_entsize = true; + break; case 'G': attr |= SHF_GROUP; break; @@ -978,8 +982,8 @@ obj_elf_parse_section_letters (char *str, size_t len, bool push, { as_bad (_("unrecognized .%ssection attribute: want %s%s%s,? or number"), push ? "push" : "", - gnu_attr != NULL ? "a,d,e,o,w,x,G,M,R,S,T" - : "a,e,o,w,x,G,M,S,T", + gnu_attr != NULL ? "a,d,e,o,w,x,E,G,M,R,S,T" + : "a,e,o,w,x,E,G,M,S,T", md_extra != NULL ? "," : "", md_extra); return attr; } @@ -1187,7 +1191,7 @@ obj_elf_section (int push) bfd_vma attr; bfd_vma gnu_attr; int entsize; - bool linkonce; + bool linkonce, has_entsize; subsegT new_subsection = 0; struct elf_section_match match; unsigned long linked_to_section_index = -1UL; @@ -1232,6 +1236,7 @@ obj_elf_section (int push) attr = 0; gnu_attr = 0; entsize = 0; + has_entsize = false; linkonce = 0; if (*input_line_pointer == ',') @@ -1276,7 +1281,8 @@ obj_elf_section (int push) == ELFOSABI_GNU) || (bed->elf_osabi == ELFOSABI_FREEBSD) - ? &gnu_attr : NULL); + ? &gnu_attr : NULL, + &has_entsize); if (inherit > 0) attr |= elf_section_flags (now_seg); @@ -1285,6 +1291,9 @@ obj_elf_section (int push) if (inherit) type = elf_section_type (now_seg); + if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0) + has_entsize = true; + SKIP_WHITESPACE (); if (*input_line_pointer == ',') { @@ -1324,16 +1333,18 @@ obj_elf_section (int push) } SKIP_WHITESPACE (); - if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 - && *input_line_pointer == ',') + if (has_entsize && *input_line_pointer == ',') { ++input_line_pointer; SKIP_WHITESPACE (); if (inherit && *input_line_pointer == ',' + && ((bfd_section_flags (now_seg) + & (SEC_MERGE | SEC_STRINGS)) != 0 + || now_seg->entsize)) + goto fetch_entsize; + if (is_end_of_stmt (*input_line_pointer) && (bfd_section_flags (now_seg) & (SEC_MERGE | SEC_STRINGS)) != 0) - goto fetch_entsize; - if (is_end_of_stmt (*input_line_pointer)) { /* ??? This is here for older versions of gcc that test for gas string merge support with @@ -1341,7 +1352,7 @@ obj_elf_section (int push) Unfortunately '@' begins a comment on arm. This isn't as_warn because gcc tests with --fatal-warnings. */ - as_tsktsk (_("missing merge / string entity size, 1 assumed")); + as_tsktsk (_("missing section entity size, 1 assumed")); entsize = 1; } else @@ -1350,15 +1361,17 @@ obj_elf_section (int push) SKIP_WHITESPACE (); if (entsize <= 0) { - as_warn (_("invalid merge / string entity size")); + as_warn (_("invalid section entity size")); attr &= ~(SHF_MERGE | SHF_STRINGS); + has_entsize = false; entsize = 0; } } } - else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && inherit - && (bfd_section_flags (now_seg) - & (SEC_MERGE | SEC_STRINGS)) != 0) + else if (has_entsize && inherit + && ((bfd_section_flags (now_seg) + & (SEC_MERGE | SEC_STRINGS)) != 0 + || now_seg->entsize)) { fetch_entsize: entsize = now_seg->entsize; @@ -1369,6 +1382,7 @@ obj_elf_section (int push) entsize must be specified if SHF_MERGE is set. */ as_warn (_("entity size for SHF_MERGE not specified")); attr &= ~(SHF_MERGE | SHF_STRINGS); + has_entsize = false; } else if ((attr & SHF_STRINGS) != 0) { @@ -1378,6 +1392,11 @@ obj_elf_section (int push) compatibility. */ entsize = 1; } + else if (has_entsize) + { + as_warn (_("entity size not specified")); + has_entsize = false; + } if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && type == SHT_NOBITS) as_warn (_("bogus SHF_MERGE / SHF_STRINGS for SHT_NOBITS section")); diff --git a/gas/doc/as.texi b/gas/doc/as.texi index 1cb1fd879a4..2db5f4896ee 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -7004,12 +7004,14 @@ section) in the same file. section is writable @item x section is executable +@item E +section has a (non-zero) element/entry size +@item G +section is a member of a section group @item M section is mergeable @item S section contains zero terminated strings -@item G -section is a member of a section group @item T section is used for thread-local-storage @item ? @@ -7118,8 +7120,8 @@ is not generally a good idea as section indices are rarely known at assembly 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 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: +Note: If both one of @var{M}, @var{S}, or @var{E} and @var{o} flags are present, +then the type and entry size fields should come first, like this: @smallexample .section @var{name},"@var{flags}"Mo,@@@var{type},@var{entsize},@var{SymbolName} @@ -7142,8 +7144,8 @@ indicates that only one copy of this section should be retained an alias for comdat @end table -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: +Note: If both one of @var{M}, @var{S}, or @var{E} and @var{G} flags are present +then the type and entry size fields should come first, like this: @smallexample .section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}] diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp index ab97e5e751b..1988788fbcd 100644 --- a/gas/testsuite/gas/elf/elf.exp +++ b/gas/testsuite/gas/elf/elf.exp @@ -293,6 +293,7 @@ if { [is_elf_format] } then { run_dump_test "sh-link-zero" run_dump_test "string" run_dump_test "size" + run_dump_test "entsize" run_dump_test "dwarf2-1" $dump_opts run_dump_test "dwarf2-2" $dump_opts run_dump_test "dwarf2-3" $dump_opts diff --git a/gas/testsuite/gas/elf/entsize.d b/gas/testsuite/gas/elf/entsize.d new file mode 100644 index 00000000000..77835cbd893 --- /dev/null +++ b/gas/testsuite/gas/elf/entsize.d @@ -0,0 +1,9 @@ +#readelf: -SW +#name: sections with entity size + +#... +[ ]*\[.*\][ ]+\.merge[ ]+PROGBITS[ ]+0+[ ]+[0-9a-f]+[ ]+0+18[ ]+0c[ ]+AM[ ].* +[ ]*\[.*\][ ]+\.string[ ]+PROGBITS[ ]+0+[ ]+[0-9a-f]+[ ]+0+6[ ]+02[ ]+AS[ ].* +[ ]*\[.*\][ ]+\.custom[ ]+PROGBITS[ ]+0+[ ]+[0-9a-f]+[ ]+0+c[ ]+06[ ]+A[ ].* +[ ]*\[.*\][ ]+\.bss\.custom[ ]+NOBITS[ ]+0+[ ]+[0-9a-f]+[ ]+0+1e[ ]+06[ ]+WA[ ].* +#pass diff --git a/gas/testsuite/gas/elf/entsize.s b/gas/testsuite/gas/elf/entsize.s new file mode 100644 index 00000000000..490de3446a6 --- /dev/null +++ b/gas/testsuite/gas/elf/entsize.s @@ -0,0 +1,8 @@ + .section .merge, "aM", 12 + .dc.l 1, 2, 3, 4, 5, 6 + .section .string, "aS", %progbits, 2 + .dc.w 0x0020, 0x0021, 0x0022 + .section .custom, "aE", 6 + .dc.w 5, 6, 7, 8, 9, 0 + .section .bss.custom, "awE", %nobits, 6 + .skip 30 -- 2.47.3