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.
Confirmed, it started with GCC 4.9.0 if I see correctly.
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?
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
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.
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>.
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.
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.
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.
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...
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).
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
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?
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