Bug 33370 - gas: monolithic .sframe violates COMDAT group rule
Summary: gas: monolithic .sframe violates COMDAT group rule
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2025-09-04 07:19 UTC by Fangrui Song
Modified: 2025-09-05 19:26 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
Project(s) to access:
ssh public key:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Fangrui Song 2025-09-04 07:19:39 UTC
https://maskray.me/blog/2021-07-25-comdat-and-section-group#group-signature-localization
The generic ABI says:

> A symbol table entry with STB_LOCAL binding that is defined relative to one of a group's sections, and that is contained in a symbol table section that is not part of the group, must be discarded if the group members are discarded. References to this symbol table entry from outside the group are not allowed.

Generally, if you want to reference a local symbol relative to a section in a COMDAT group, the referencing section should be part of the same group.

.sframe

cat > a.cc <<'eof'
[[gnu::noinline]] inline int inl() { return 0; }
auto *fa = inl;
eof
cat > b.cc <<'eof'
[[gnu::noinline]] inline int inl() { return 0; }
auto *fb = inl;
eof
~/opt/gcc-15/bin/g++ -Wa,--gsframe -c a.cc b.cc

% ld.lld a.o b.o
ld.lld: error: relocation refers to a discarded section: .text._Z3inlv
>>> defined in b.o
>>> referenced by b.cc
>>>               b.o:(.sframe+0x1c)
% gold a.o b.o
b.o(.sframe+0x1c): error: relocation refers to local symbol ".text._Z3inlv" [2], which is defined in a discarded section
  section group signature: "inl()"
  prevailing definition is from a.o

% readelf -W -S a.o | grep sframe
  [11] .sframe           PROGBITS        0000000000000000 0000b0 00003f 00   A  0   0  8
  [12] .rela.sframe      RELA            0000000000000000 0001b0 000018 18   I 13  11  8

.sframe violates this rule.
Comment 1 Fangrui Song 2025-09-04 17:12:20 UTC
Such SHF_ALLOC metadata sections that reference the text section should be placed in separate sections. 

See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93195  for the __patchable_function_entries section fix on the GCC side. See also .gcc_except_table . I have some notes at https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order
Comment 2 Indu Bhagat 2025-09-04 18:15:13 UTC
Reading up on a few things, but meanwhile...I'd expect the sframe section type to be SHT_GNU_SFRAME. Starting Binutils 2.45.
Comment 3 Indu Bhagat 2025-09-05 03:05:33 UTC
I think the core issue is that SFrame sections (section type SHT_GNU_SFRAME) need to be merged and not concatenated by the linker.  An abiding linker should also then remove SFrame data corresponding to a discarded symbol.

An SFrame section has a SFrame header, followed by a list of fixed length entries (Frame Descriptor Entries, one each for a function), and then a list of variable length entries (Frame row entries, a function may have any number of FREs).  Note the rearrangement of FDE and FRE data necessary to be done for the output section due to this layout.

Relying on COMDAT/SHT_GROUP addresses the issue when the section contents are amenable to concatenation.   SFrame sections cannot be concatenated.  Similar reasoning for SHF_LINK_ORDER.

I think we need to fix ld.lld to error out till it has the functionality to merge SFrame sections.
Comment 4 Fangrui Song 2025-09-05 04:57:24 UTC
(In reply to Indu Bhagat from comment #3)
> I think the core issue is that SFrame sections (section type SHT_GNU_SFRAME) need to be merged and not concatenated by the linker.  An abiding linker should also then remove SFrame data corresponding to a discarded symbol.

A design that permits concatenated components would be a more robust approach and fits into the ELF spirit well.
Modern metadata sections should move beyond the .eh_frame style hack.

When a.o:inl and b.o:inl are COMDAT groups with the same signature, and a.o:inl is the prevailing copy, does GNU ld discard the '.sframe' element that describes b.o:inl?
This is a crucial in cases of ODR (One Definition Rule) violation, where it's essential to retain the metadata for the prevailing copy.

---

In the following example, does linker garbage collection properly discard the .sframe element that describes `unused`? 

% cat a.cc
[[gnu::noinline]] inline int inl() { return 0; }
int unused() { return 1; }

extern "C" void _start() {
  inl();
}

% $HOME/Dev/binutils-gdb/out/debug/bin/ld --version | head -n 1
GNU ld (GNU Binutils) 2.45.50.20250905
% ~/opt/gcc-15/bin/g++ -B$HOME/Dev/binutils-gdb/out/debug/bin -ffunction-sections -Wa,--gsframe  -c a.cc
% ~/Dev/binutils-gdb/out/debug/ld/ld-new a.o --gc-sections --print-gc-sections
/home/ray/Dev/binutils-gdb/out/debug/ld/ld-new: removing unused section '.sframe' in file 'a.o'

This seems worse than I thought. .sframe is just entirely discarded.

If the .sframe element for `unused` is in a separate section (a la __patchable_function_entries), and it has SHF_LINK_ORDER flag, the default linker garbage collection will discard it.

In a generic linker design, section content finalization occurs after COMDAT section deduplication and section based garbage collection.
This allows for smart, linker-generated content to function correctly alongside standard ELF features. We could further reduce .sframe content if the linker wants to implement such features.
Comment 5 Indu Bhagat 2025-09-05 18:45:31 UTC
(In reply to Fangrui Song from comment #4)
> (In reply to Indu Bhagat from comment #3)
> > I think the core issue is that SFrame sections (section type SHT_GNU_SFRAME) need to be merged and not concatenated by the linker.  An abiding linker should also then remove SFrame data corresponding to a discarded symbol.
> 
> A design that permits concatenated components would be a more robust
> approach and fits into the ELF spirit well.
> Modern metadata sections should move beyond the .eh_frame style hack.
> 
> When a.o:inl and b.o:inl are COMDAT groups with the same signature, and
> a.o:inl is the prevailing copy, does GNU ld discard the '.sframe' element
> that describes b.o:inl?
> This is a crucial in cases of ODR (One Definition Rule) violation, where
> it's essential to retain the metadata for the prevailing copy.
> 

Yes, I tested a bit. GNU ld will discard SFrame FDE for the respective discarded symbol.

> ---
> 
> In the following example, does linker garbage collection properly discard
> the .sframe element that describes `unused`? 
> 
> % cat a.cc
> [[gnu::noinline]] inline int inl() { return 0; }
> int unused() { return 1; }
> 
> extern "C" void _start() {
>   inl();
> }
> 
> % $HOME/Dev/binutils-gdb/out/debug/bin/ld --version | head -n 1
> GNU ld (GNU Binutils) 2.45.50.20250905
> % ~/opt/gcc-15/bin/g++ -B$HOME/Dev/binutils-gdb/out/debug/bin
> -ffunction-sections -Wa,--gsframe  -c a.cc
> % ~/Dev/binutils-gdb/out/debug/ld/ld-new a.o --gc-sections
> --print-gc-sections
> /home/ray/Dev/binutils-gdb/out/debug/ld/ld-new: removing unused section
> '.sframe' in file 'a.o'
> 
> This seems worse than I thought. .sframe is just entirely discarded.
> 
> If the .sframe element for `unused` is in a separate section (a la
> __patchable_function_entries), and it has SHF_LINK_ORDER flag, the default
> linker garbage collection will discard it.
> 

Yes, the --gc-sections issue is tracked here https://sourceware.org/bugzilla/show_bug.cgi?id=33370. I plan to fix it before 2.46 release.
Comment 6 Indu Bhagat 2025-09-05 18:54:40 UTC
(In reply to Fangrui Song from comment #4)
> In a generic linker design, section content finalization occurs after COMDAT
> section deduplication and section based garbage collection.

Right. In current context, GNU ld behavior aligns to above for SFrame sections.

> This allows for smart, linker-generated content to function correctly
> alongside standard ELF features. We could further reduce .sframe content if
> the linker wants to implement such features.

What further reduction does the alternative bring ?