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'.
This commit is contained in:
Jan Beulich
2025-08-15 12:19:59 +02:00
parent 21ff588912
commit 98e6d3f5bd
7 changed files with 71 additions and 30 deletions

View File

@@ -869,20 +869,16 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
else if ((flags & SEC_LOAD) != 0) else if ((flags & SEC_LOAD) != 0)
flags |= SEC_DATA; flags |= SEC_DATA;
if ((hdr->sh_flags & SHF_MERGE) != 0) if ((hdr->sh_flags & SHF_MERGE) != 0)
{ flags |= SEC_MERGE;
flags |= SEC_MERGE;
newsect->entsize = hdr->sh_entsize;
}
if ((hdr->sh_flags & SHF_STRINGS) != 0) 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) if ((hdr->sh_flags & SHF_TLS) != 0)
flags |= SEC_THREAD_LOCAL; flags |= SEC_THREAD_LOCAL;
if ((hdr->sh_flags & SHF_EXCLUDE) != 0) if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
flags |= SEC_EXCLUDE; flags |= SEC_EXCLUDE;
newsect->entsize = hdr->sh_entsize;
switch (elf_elfheader (abfd)->e_ident[EI_OSABI]) switch (elf_elfheader (abfd)->e_ident[EI_OSABI])
{ {
/* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE, /* 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) if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE)
this_hdr->sh_flags |= SHF_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 /* If the section has relocs, set up a section header for the
SHT_REL[A] section. If two relocation sections are required for SHT_REL[A] section. If two relocation sections are required for
this section, it is up to the processor-specific back-end to this section, it is up to the processor-specific back-end to

View File

@@ -1,5 +1,8 @@
-*- text -*- -*- text -*-
* ELF targets can now have section entity size specified for arbitrary
sections, using the new attribute letter 'E'.
* NaCl target support is removed. * NaCl target support is removed.
Changes in 2.45: Changes in 2.45:

View File

@@ -792,7 +792,7 @@ change_section (const char *name,
= match_p->linked_to_symbol_name; = match_p->linked_to_symbol_name;
bfd_set_section_flags (sec, flags); bfd_set_section_flags (sec, flags);
if (flags & (SEC_MERGE | SEC_STRINGS)) if (entsize != 0)
sec->entsize = entsize; sec->entsize = entsize;
elf_group_name (sec) = match_p->group_name; elf_group_name (sec) = match_p->group_name;
@@ -847,7 +847,7 @@ change_section (const char *name,
processor or application specific attribute as suspicious? */ processor or application specific attribute as suspicious? */
elf_section_flags (sec) = attr; elf_section_flags (sec) = attr;
if ((flags & (SEC_MERGE | SEC_STRINGS)) if (entsize != 0
&& old_sec->entsize != (unsigned) entsize) && old_sec->entsize != (unsigned) entsize)
as_bad (_("changed section entity size for %s"), name); as_bad (_("changed section entity size for %s"), name);
} }
@@ -871,7 +871,8 @@ obj_elf_change_section (const char *name,
static bfd_vma static bfd_vma
obj_elf_parse_section_letters (char *str, size_t len, bool push, 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; bfd_vma attr = 0;
@@ -913,6 +914,9 @@ obj_elf_parse_section_letters (char *str, size_t len, bool push,
case 'x': case 'x':
attr |= SHF_EXECINSTR; attr |= SHF_EXECINSTR;
break; break;
case 'E':
*has_entsize = true;
break;
case 'G': case 'G':
attr |= SHF_GROUP; attr |= SHF_GROUP;
break; 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"), as_bad (_("unrecognized .%ssection attribute: want %s%s%s,? or number"),
push ? "push" : "", push ? "push" : "",
gnu_attr != NULL ? "a,d,e,o,w,x,G,M,R,S,T" gnu_attr != NULL ? "a,d,e,o,w,x,E,G,M,R,S,T"
: "a,e,o,w,x,G,M,S,T", : "a,e,o,w,x,E,G,M,S,T",
md_extra != NULL ? "," : "", md_extra); md_extra != NULL ? "," : "", md_extra);
return attr; return attr;
} }
@@ -1187,7 +1191,7 @@ obj_elf_section (int push)
bfd_vma attr; bfd_vma attr;
bfd_vma gnu_attr; bfd_vma gnu_attr;
int entsize; int entsize;
bool linkonce; bool linkonce, has_entsize;
subsegT new_subsection = 0; subsegT new_subsection = 0;
struct elf_section_match match; struct elf_section_match match;
unsigned long linked_to_section_index = -1UL; unsigned long linked_to_section_index = -1UL;
@@ -1232,6 +1236,7 @@ obj_elf_section (int push)
attr = 0; attr = 0;
gnu_attr = 0; gnu_attr = 0;
entsize = 0; entsize = 0;
has_entsize = false;
linkonce = 0; linkonce = 0;
if (*input_line_pointer == ',') if (*input_line_pointer == ',')
@@ -1276,7 +1281,8 @@ obj_elf_section (int push)
== ELFOSABI_GNU) == ELFOSABI_GNU)
|| (bed->elf_osabi || (bed->elf_osabi
== ELFOSABI_FREEBSD) == ELFOSABI_FREEBSD)
? &gnu_attr : NULL); ? &gnu_attr : NULL,
&has_entsize);
if (inherit > 0) if (inherit > 0)
attr |= elf_section_flags (now_seg); attr |= elf_section_flags (now_seg);
@@ -1285,6 +1291,9 @@ obj_elf_section (int push)
if (inherit) if (inherit)
type = elf_section_type (now_seg); type = elf_section_type (now_seg);
if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0)
has_entsize = true;
SKIP_WHITESPACE (); SKIP_WHITESPACE ();
if (*input_line_pointer == ',') if (*input_line_pointer == ',')
{ {
@@ -1324,16 +1333,18 @@ obj_elf_section (int push)
} }
SKIP_WHITESPACE (); SKIP_WHITESPACE ();
if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 if (has_entsize && *input_line_pointer == ',')
&& *input_line_pointer == ',')
{ {
++input_line_pointer; ++input_line_pointer;
SKIP_WHITESPACE (); SKIP_WHITESPACE ();
if (inherit && *input_line_pointer == ',' 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) && (bfd_section_flags (now_seg)
& (SEC_MERGE | SEC_STRINGS)) != 0) & (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 /* ??? This is here for older versions of gcc that
test for gas string merge support with test for gas string merge support with
@@ -1341,7 +1352,7 @@ obj_elf_section (int push)
Unfortunately '@' begins a comment on arm. Unfortunately '@' begins a comment on arm.
This isn't as_warn because gcc tests with This isn't as_warn because gcc tests with
--fatal-warnings. */ --fatal-warnings. */
as_tsktsk (_("missing merge / string entity size, 1 assumed")); as_tsktsk (_("missing section entity size, 1 assumed"));
entsize = 1; entsize = 1;
} }
else else
@@ -1350,15 +1361,17 @@ obj_elf_section (int push)
SKIP_WHITESPACE (); SKIP_WHITESPACE ();
if (entsize <= 0) if (entsize <= 0)
{ {
as_warn (_("invalid merge / string entity size")); as_warn (_("invalid section entity size"));
attr &= ~(SHF_MERGE | SHF_STRINGS); attr &= ~(SHF_MERGE | SHF_STRINGS);
has_entsize = false;
entsize = 0; entsize = 0;
} }
} }
} }
else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && inherit else if (has_entsize && inherit
&& (bfd_section_flags (now_seg) && ((bfd_section_flags (now_seg)
& (SEC_MERGE | SEC_STRINGS)) != 0) & (SEC_MERGE | SEC_STRINGS)) != 0
|| now_seg->entsize))
{ {
fetch_entsize: fetch_entsize:
entsize = now_seg->entsize; entsize = now_seg->entsize;
@@ -1369,6 +1382,7 @@ obj_elf_section (int push)
entsize must be specified if SHF_MERGE is set. */ entsize must be specified if SHF_MERGE is set. */
as_warn (_("entity size for SHF_MERGE not specified")); as_warn (_("entity size for SHF_MERGE not specified"));
attr &= ~(SHF_MERGE | SHF_STRINGS); attr &= ~(SHF_MERGE | SHF_STRINGS);
has_entsize = false;
} }
else if ((attr & SHF_STRINGS) != 0) else if ((attr & SHF_STRINGS) != 0)
{ {
@@ -1378,6 +1392,11 @@ obj_elf_section (int push)
compatibility. */ compatibility. */
entsize = 1; 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) if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && type == SHT_NOBITS)
as_warn (_("bogus SHF_MERGE / SHF_STRINGS for SHT_NOBITS section")); as_warn (_("bogus SHF_MERGE / SHF_STRINGS for SHT_NOBITS section"));

View File

@@ -7004,12 +7004,14 @@ section) in the same file.
section is writable section is writable
@item x @item x
section is executable 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 @item M
section is mergeable section is mergeable
@item S @item S
section contains zero terminated strings section contains zero terminated strings
@item G
section is a member of a section group
@item T @item T
section is used for thread-local-storage section is used for thread-local-storage
@item ? @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 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. 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 Note: If both one of @var{M}, @var{S}, or @var{E} and @var{o} flags are present,
fields for the Merge/String flag should come first, like this: then the type and entry size fields should come first, like this:
@smallexample @smallexample
.section @var{name},"@var{flags}"Mo,@@@var{type},@var{entsize},@var{SymbolName} .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 an alias for comdat
@end table @end table
Note: Uf both one of @var{M} or @var{S} and @var{G} flags are present then the Note: If both one of @var{M}, @var{S}, or @var{E} and @var{G} flags are present
fields for the Merge/String flag should come first, like this: then the type and entry size fields should come first, like this:
@smallexample @smallexample
.section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}] .section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}]

View File

@@ -293,6 +293,7 @@ if { [is_elf_format] } then {
run_dump_test "sh-link-zero" run_dump_test "sh-link-zero"
run_dump_test "string" run_dump_test "string"
run_dump_test "size" run_dump_test "size"
run_dump_test "entsize"
run_dump_test "dwarf2-1" $dump_opts run_dump_test "dwarf2-1" $dump_opts
run_dump_test "dwarf2-2" $dump_opts run_dump_test "dwarf2-2" $dump_opts
run_dump_test "dwarf2-3" $dump_opts run_dump_test "dwarf2-3" $dump_opts

View File

@@ -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

View File

@@ -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