[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 --- Comment #8 from Andrew Pinski --- (In reply to Erez Strauss from comment #7) > Hi Andrew, > > Here is a very simple test program, under clang++ its output is 3, as > expected. Right I already mentioned this is a dup of still opened bug 88061 . The problem is clang might be emitting really really broken assembly and only can be resolved at link time. Take: template void funcB() { static funcP init_func [[gnu::used, gnu::section(".init_array")]] { []()->void{++X;} }; } - CUT - funcB::init_func has to be the same between TUs and that means emiting it in the comdat section. In fact the use of X here might actually cause this code to be full on invalid anyways.
[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 --- Comment #7 from Erez Strauss --- Hi Andrew, Here is a very simple test program, under clang++ its output is 3, as expected. Its output is 2 in case of g++ 11.2.1 20210728 (Red Hat 11.2.1-1) #include static int X; typedef void (*funcP)(); static funcP g_init_func [[gnu::used, gnu::section(".init_array")]] { []()->void{++X;} }; void funcA() { static funcP init_func [[gnu::used, gnu::section(".init_array")]] { []()->void{++X;} }; } template void funcB() { static funcP init_func [[gnu::used, gnu::section(".init_array")]] { []()->void{++X;} }; } void testT() { funcB(); } int main() { std::cout << X << std::endl; testT(); return 0; } Please test the above to generate 3 as output with g++. Thanks, Erez
[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 Andrew Pinski changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution|--- |DUPLICATE --- Comment #6 from Andrew Pinski --- Dup of bug 88061. Though I suspect both PR 88061 and PR 70435 are invalid. *** This bug has been marked as a duplicate of bug 88061 ***
[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 --- Comment #5 from Erez Strauss --- Yes, thanks, the asm() works - but if it can be expressed in C++, why add the dependency on assembly? 1. attribute constructor - fails to compile 2. placing the address into the .init_array fails to generate the proper code. 3. assembly is required for gcc, but not for clang. I minimized the program by avoiding any include files, having three different macros for the different options. I would expect that gcc will handle correctly the first two options, as other compilers do. See https://godbolt.org/z/Mr1794 - for the three compilers: gcc clang icc $ cat init_array_minimized.cpp extern "C" int write(int, const char *, long); extern "C" unsigned long strlen(const char *); extern "C" int snprintf(char *, unsigned long, const char *, ...); #define SIMPLE_LOCAL_FUNC_INIT_ARRAY() \ do \ { \ struct Local \ { \ static void init() \ { \ char buffer[256]; \ snprintf(buffer, sizeof(buffer), "%p: %s:%d: %s\n", (void*)&init, __FILE__, __LINE__, \ __PRETTY_FUNCTION__); \ write(1, buffer, strlen(buffer)); \ } \ }; \ static void *volatile initp __attribute__((__used__, section(".init_array"))){(void *)&Local::init}; \ } while (0) #define SIMPLE_LOCAL_FUNC_CONSTRUCTOR() \ do \ { \ struct Local \ { \ static void init() __attribute__((constructor)) \ { \ char buffer[256]; \ snprintf(buffer, sizeof(buffer), "%p: %s:%d: %s\n", (void*)&init, __FILE__, __LINE__, \ __PRETTY_FUNCTION__); \ write(1, buffer, strlen(buffer)); \ } \ }; \ } while (0) #define SIMPLE_LOCAL_FUNC_INIT_ASM() \ do \ { \ struct Local \ { \ static void init() \ { \ char buffer[256]; \ snprintf(buffer, sizeof(buffer), "%p: %s:%d: %s\n", (void*)&init, __FILE__, __LINE__, \ __PRETTY_FUNCTION__); \ write(1, buffer, strlen(buffer)); \ } \ }; \ __asm (".section .init_array, \"aw\",%%init_array; .balign %P0; .%P0byte %P1; .previous" : : "i" (sizeof (void *)), "g" ((void*)&Local::init)); \ } while (0) //#define LOCAL_INIT_FUNC() SIMPLE_LOCAL_FUNC_INIT_ARRAY() //#define LOCAL_INIT_FUNC() SIMPLE_LOCAL_FUNC_CONSTRUCTOR() #define LOCAL_INIT_FUNC() SIMPLE_LOCAL_FUNC_INIT_ASM() void funcA() { LOCAL_INIT_FUNC(); LOCAL_INIT_FUNC(); } inline void funcB() { LOCAL_INIT_FUNC(); } template void funcT(int) { LOCAL_INIT_FUN
[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 Jakub Jelinek changed: What|Removed |Added CC||jason at gcc dot gnu.org --- Comment #4 from Jakub Jelinek --- That is about the assembler warning (which isn't fatal though); for the uses in inline functions or templates anothing thing is that the comdat sections from comdat take priority over the section attribute. Now, when assembler doesn't support comdat groups, there is really no way around it, section attribute has to be ignored and one needs to use .gnu.linkonce.* etc. sections, because otherwise it wouldn't act as comdat. With comdat groups, we could use the section name from the section attribute and just put it into the comdat group, but don't do that.
[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 Jakub Jelinek changed: What|Removed |Added CC||jakub at gcc dot gnu.org --- Comment #3 from Jakub Jelinek --- What you are doing is certainly wrong. .init_array section needs to be @init_array, there is no way to create initialized variables in anything but @progbits. The section attribute doesn't have any list of magic sections that should be treated differently from anything else. constructor attribute indeed is only allowed on file-scope functions. Why don't you use inline asm? I'd suggest __asm (".section .init_array, \"aw\",%%init_array; .balign %P0; .%P0byte %P1; .previous" : : "i" (sizeof (void *)), "g" ((void *)&Local::init)); instead of your initp declaration.
[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 --- Comment #2 from Erez Strauss --- Thanks, I tried, it fails with: $ g++ -O2 -std=c++20 init_array5c.cpp -o init_array5c init_array5c.cpp: In function ‘void localFunc(const char*)’: init_array5c.cpp:17:55: warning: ‘constructor’ attribute ignored [-Wattributes] 17 | static void init() __attribute__((constructor)) | ^ === $ ./init_array5c main() started post-main-start: X1 init_array5c.cpp 37 &count: 0x4041d4 count: 1 void localFunc(const char*) [with const std::experimental::fundamentals_v2::source_location& X = s] post-main-start: X2 init_array5c.cpp 38 &count: 0x4041dc count: 1 void localFunc(const char*) [with const std::experimental::fundamentals_v2::source_location& X = s] === clang++ accepts correctly the attribute: $ clang++ -O2 -std=c++20 init_array5c.cpp -o init_array5c === $ ./init_array5c pre-main-start init from localFunc: init_array5c.cpp 37 &count: 0x4041d8 count: 1 okFunc1 / static void localFunc(const char *)::Local::init() pre-main-start init from localFunc: init_array5c.cpp 38 &count: 0x4041dc count: 1 okFunc2 / static void localFunc(const char *)::Local::init() main() started post-main-start: X1 init_array5c.cpp 37 &count: 0x4041d8 count: 2 void localFunc(const char *) [X = s] post-main-start: X2 init_array5c.cpp 38 &count: 0x4041dc count: 2 void localFunc(const char *) [X = s] === $ cat init_array5c.cpp #include #include using namespace std::experimental; template void localFunc(const char* name) { static int count{0}; volatile ::std::ios_base::Init dummy{}; std::cout << "post-main-start: " << name << " " << X.file_name() << " " << X.line() << " &count: " << (void*)&count << " count: " << (++count) << " " << __PRETTY_FUNCTION__ << std::endl; struct Local { static void init() __attribute__((constructor)) { volatile ::std::ios_base::Init dummy{}; std::cout << "pre-main-start init from localFunc: " << X.file_name() << " " << X.line() << " &count: " << (void*)&count << " count: " << (++count) << " " << X.function_name() << " / " << __PRETTY_FUNCTION__ << std::endl; } }; //static void* volatile initp __attribute__((__used__, section(".init_array"))){(void*)&Local::init}; } #define LOCAL_FUNC(NAME) \ do\ { \ constexpr static auto s = source_location::current(); \ localFunc((const char*)&(NAME)[0]);\ } while (0) void okFunc1() { LOCAL_FUNC("X1"); } inline void okFunc2() { LOCAL_FUNC("X2"); } int main() { std::cout << "main() started" << std::endl; okFunc1(); okFunc2(); return 0; }
[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771 Richard Biener changed: What|Removed |Added Keywords||wrong-code --- Comment #1 from Richard Biener --- I think the GCC "portable" way of doing this is to attach the constructor attribute to Local::init.