Bug 94342 - GCC ignores attribute((section(...))) for static variables inside templates
Summary: GCC ignores attribute((section(...))) for static variables inside templates
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.2.1
: P3 normal
Target Milestone: 14.0
Assignee: Patrick Palka
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2020-03-26 11:43 UTC by Anton
Modified: 2024-08-02 00:27 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-08-13 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Anton 2020-03-26 11:43:21 UTC
GCC ignores the section attribute for static variables declared inside templates:

template <typename T>                                                                                                                                                                                                                   
void Index(int i) {                                                                                                                                                                                                                     
  static int VAR __attribute__((used,section("NEW_SECTION"))) = i;                                                                                                                                                                       }                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                    
template void Index<int>(int);

Objdump shows that the VAR symbol is still located in .bss (not NEW_SECTION):

objdump -tC result.o
...
0000000000000000 u     O .bss._ZZ5IndexIiEviE3VAR       0000000000000004 Index<int>(int)::VAR
...

Tested on gcc-9.2.1. Clang's behaviour is as expected.
Comment 1 Martin Liška 2020-03-26 11:50:27 UTC
Confirmed, it started with GCC 4.9.0 if I see correctly.
Comment 2 Richard Biener 2020-03-26 13:25:20 UTC
I think it should belong to the same .comdat group as other parts of the
template instantiation (there's one static var per instantiation) so I don't
see how the section specification can be easily honored.

But at least a diagnostic would be appropriate.

That is, consider two TUs with instantiations of Index<int>, how will you
make linking work?  Force the definition WEAK?
Comment 3 Richard Biener 2020-03-26 13:29:13 UTC
Hmm, I see clang produces

COMDAT group section [    3] `.group' [_Z5IndexIiEvi] contains 2 sections:
   [Index]    Name
   [    4]   .text._Z5IndexIiEvi
   [    5]   .rela.text._Z5IndexIiEvi

COMDAT group section [    6] `.group' [_ZZ5IndexIiEviE3VAR] contains 1 sections:
   [Index]    Name
   [    7]   NEW_SECTION

COMDAT group section [    8] `.group' [_ZGVZ5IndexIiEviE3VAR] contains 1 sections:
   [Index]    Name
   [    9]   .bss._ZGVZ5IndexIiEviE3VAR

and if I add a Index<float> specialization it ends up emitting two
distinct sections with the same name NEW_SECTION and

COMDAT group section [    3] `.group' [_Z5IndexIiEvi] contains 2 sections:
   [Index]    Name
   [    4]   .text._Z5IndexIiEvi
   [    5]   .rela.text._Z5IndexIiEvi

COMDAT group section [    6] `.group' [_Z5IndexIfEvi] contains 2 sections:
   [Index]    Name
   [    7]   .text._Z5IndexIfEvi
   [    8]   .rela.text._Z5IndexIfEvi

COMDAT group section [    9] `.group' [_ZZ5IndexIiEviE3VAR] contains 1 sections:
   [Index]    Name
   [   10]   NEW_SECTION

COMDAT group section [   11] `.group' [_ZGVZ5IndexIiEviE3VAR] contains 1 sections:
   [Index]    Name
   [   12]   .bss._ZGVZ5IndexIiEviE3VAR

COMDAT group section [   13] `.group' [_ZZ5IndexIfEviE3VAR] contains 1 sections:
   [Index]    Name
   [   14]   NEW_SECTION

COMDAT group section [   15] `.group' [_ZGVZ5IndexIfEviE3VAR] contains 1 sections:
   [Index]    Name
   [   16]   .bss._ZGVZ5IndexIfEviE3VAR
Comment 4 Richard Biener 2020-03-26 13:31:11 UTC
So the section attribute then only provides naming of the comdat section used and cannot be used to group things.  Not sure that is what you are looking after.
Comment 5 Anton 2020-03-26 17:17:21 UTC
Looking at the COMDAT groups for the example with 2 instantiations (Index<int> and Index<float>), I think this is what is actually expected: section for Index<int> must not be grouped with section for Index<float>. In general, different instantiations must be kept in different COMDAT groups. Otherwise, it would not work e.g. if one TU instantiates Index<int>, the other TU instantiates Index<int> and Index<float>.
Comment 6 Anton 2020-03-26 17:29:44 UTC
I also don't understand why all the parts of a template instantiation need to be kept in the same COMDAT group. Neither clang nor gcc does it:

template <typename T>                                                                                                                                                                                                                   
void Index(int i) {                                                                                                                                                                                                                     
  static int VAR1 = i;
  static int VAR2 = i;                                                                                                                                                                       }                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                    
template void Index<int>(int);
template void Index<float>(int);

This gives:

COMDAT group section [    1] `.group' [void Index<int>(int)] contains 2 sections:
   [Index]    Name
   [   14]   .text._Z5IndexIiEvi
   [   15]   .rela.text._Z5IndexIiEvi

COMDAT group section [    2] `.group' [void Index<float>(int)] contains 2 sections:
   [Index]    Name
   [   16]   .text._Z5IndexIfEvi
   [   17]   .rela.text._Z5IndexIfEvi

COMDAT group section [    3] `.group' [Index<int>(int)::VAR] contains 1 sections:
   [Index]    Name
   [   18]   .bss._ZZ5IndexIiEviE3VAR

COMDAT group section [    4] `.group' [guard variable for Index<int>(int)::VAR] contains 1 sections:
   [Index]    Name
   [   19]   .bss._ZGVZ5IndexIiEviE3VAR

COMDAT group section [    5] `.group' [Index<int>(int)::VAR2] contains 1 sections:
   [Index]    Name
   [   20]   .bss._ZZ5IndexIiEviE4VAR2

COMDAT group section [    6] `.group' [guard variable for Index<int>(int)::VAR2] contains 1 sections:
   [Index]    Name
   [   21]   .bss._ZGVZ5IndexIiEviE4VAR2

COMDAT group section [    7] `.group' [Index<float>(int)::VAR] contains 1 sections:
   [Index]    Name
   [   22]   .bss._ZZ5IndexIfEviE3VAR

COMDAT group section [    8] `.group' [guard variable for Index<float>(int)::VAR] contains 1 sections:
   [Index]    Name
   [   23]   .bss._ZGVZ5IndexIfEviE3VAR

COMDAT group section [    9] `.group' [Index<float>(int)::VAR2] contains 1 sections:
   [Index]    Name
   [   24]   .bss._ZZ5IndexIfEviE4VAR2

COMDAT group section [   10] `.group' [guard variable for Index<float>(int)::VAR2] contains 1 sections:
   [Index]    Name
   [   25]   .bss._ZGVZ5IndexIfEviE4VAR2


I might have misunderstood, but I think that COMDAT groups are orthogonal to section naming.
Comment 7 Richard Biener 2020-03-27 07:55:29 UTC
Yes, they are orthogonal.  But I expected that when I use __attribute__((section"foo")) twice then both instances will be in the
same section which is not the case here.  Here just the names of the sections
are equal.
Comment 8 Anton 2020-03-27 10:03:45 UTC
Yeah, the generated sections are different yet have the same name. The user would rely on the static linker to merge the sections into a single one.
Comment 9 Jakub Jelinek 2020-03-27 11:06:05 UTC
COMDAT is implemented in different ways.  If it is through the ELF comdat groups, then in theory this can be handled, by putting the COMDAT variable (from template instantiation, or inline variable, static var in inline function etc.) into the section with the given name and use the comdat group we would normally use.
If ELF comdat groups aren't supported, then we use .gnu.linkonce.* sections and in that case it can't be really supported.  Nor in the non-ELF cases...
Comment 10 Anton 2020-03-27 11:40:38 UTC
I think there are two ways to handle the problem for targets that don't support COMDAT:
1) issue a diagnostic that the section attribute will be ignored (because it'll go to .gnu.linkone.*);
2) fallback to weak symbols (which IIUC would be not space efficient).
Comment 11 Corey Tabaka 2020-04-08 18:20:44 UTC
Clang already (In reply to Jakub Jelinek from comment #9)
> COMDAT is implemented in different ways.  If it is through the ELF comdat
> groups, then in theory this can be handled, by putting the COMDAT variable
> (from template instantiation, or inline variable, static var in inline
> function etc.) into the section with the given name and use the comdat group
> we would normally use.
> If ELF comdat groups aren't supported, then we use .gnu.linkonce.* sections
> and in that case it can't be really supported.  Nor in the non-ELF cases...

Clang already takes the approach of applying the given section name and using the normal COMDAT group for ELF targets. It would be helpful for GCC and Clang to match behaviors.

Example: https://godbolt.org/z/w-Hy-z
Comment 12 Roland McGrath 2020-11-10 23:15:11 UTC
I think the correct behavior here is clear for ELF targets, which is what Clang does.  Using section attributes always highly target-specific semantics, so I think it would be fine for it to continue to behave as it does now for non-ELF targets or to give a diagnostic.  With ELF COMDAT semantics, I think it's straightforward and obviously consistent with general use of COMDAT what you'd want here, so I don't see any controversy here.  Is this difficult to implement?
Comment 13 Patrick Palka 2023-12-16 18:05:29 UTC
The attribute propagation issue which caused us to effectively ignore the section attribute on templated entities is fixed (naively, see PR88061#c11) for GCC 14 by r14-6595