[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat

2021-08-28 Thread erstrauss at gmail dot com via Gcc-bugs
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

2020-11-10 Thread erstrauss at gmail dot com via Gcc-bugs
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*), __FILE__, __LINE__,  \
 __PRETTY_FUNCTION__); 
 \
write(1, buffer, strlen(buffer));  
 \
}  
 \
}; 
 \
static void *volatile initp __attribute__((__used__,
section(".init_array"))){(void *)::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*), __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*), __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*)::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_FUNC(); }

int main()
{

[Bug c++/97771] gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat

2020-11-10 Thread erstrauss at gmail dot com via Gcc-bugs
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 : 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 : 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 : 0x4041d8 count:
1 okFunc1 / static void localFunc(const char *)::Local::init()
pre-main-start init from localFunc: init_array5c.cpp 38 : 0x4041dc count:
1 okFunc2 / static void localFunc(const char *)::Local::init()
main() started
post-main-start: X1 init_array5c.cpp 37 : 0x4041d8 count: 2 void
localFunc(const char *) [X = s]
post-main-start: X2 init_array5c.cpp 38 : 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()
  << " : " << (void*) << " 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() << " : " << (void*)
  << " count: " << (++count) << " " << X.function_name() <<
" / " << __PRETTY_FUNCTION__
  << std::endl;
}
};

//static void* volatile initp __attribute__((__used__,
section(".init_array"))){(void*)::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] New: gcc/g++ failed to generate proper .init_array entries for local scope function, should create "axG", .init_array comdat

2020-11-09 Thread erstrauss at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97771

Bug ID: 97771
   Summary: gcc/g++ failed to generate proper .init_array entries
for local scope function, should create "axG",
.init_array comdat
   Product: gcc
   Version: 10.2.1
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: erstrauss at gmail dot com
  Target Milestone: ---

The the program below creates a local function inside a Local structure, and
adds the
local function address into the .init_array section in order to call that local
function at process start.

The localFunc template function is using a source_location const static
variable as template parameter.


g++ fails to place the address of the Local::init() functions inside the
.init_array.


$ cat init_array5.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()
  << " : " << (void*) << " count: " << (++count) << " "
  << __PRETTY_FUNCTION__ << std::endl;

struct Local
{
static void init()
{
volatile ::std::ios_base::Init dummy{};
std::cout << "pre-main-start init from localFunc: " <<
X.file_name() << " "
  << X.line() << " : " << (void*)
  << " count: " << (++count) << " " << X.function_name() <<
" / " << __PRETTY_FUNCTION__
  << std::endl;
}
};

static void* volatile initp
__attribute__((__used__, section(".init_array"))){(void*)::init};
  // not places into .init_array.
}

#define LOCAL_FUNC(NAME)  \
do\
{ \
constexpr static auto s = source_location::current(); \
localFunc((const char*)&(NAME)[0]);\
} while (0)

void okFunc1() { LOCAL_FUNC("X1"); }
void okFunc2() { LOCAL_FUNC("X2"); }

int main()
{
std::cout << "main() started" << std::endl;
okFunc1();
okFunc2();
return 0;
}


==
output of the g++ compiled code, without the calls to the Local::init()
functions.

$ g++ -O2 -std=c++20 init_array5.cpp -o init_array5
$ ./init_array5
main() started
post-main-start: X1 init_array5.cpp 38 : 0x4041d8 count: 1 void
localFunc(const char*) [with const
std::experimental::fundamentals_v2::source_location& X = s]
post-main-start: X2 init_array5.cpp 39 : 0x4041d4 count: 1 void
localFunc(const char*) [with const
std::experimental::fundamentals_v2::source_location& X = s]


In case the same code is compiled using clang++, the pre-main local functions
are being called.

$ clang++ -O2 -std=c++20 init_array5.cpp -o init_array5
$ ./init_array5
pre-main-start init from localFunc: init_array5.cpp 38 : 0x4041d8 count:
1 okFunc1 / static void localFunc(const char *)::Local::init()
pre-main-start init from localFunc: init_array5.cpp 39 : 0x4041dc count:
1 okFunc2 / static void localFunc(const char *)::Local::init()
main() started
post-main-start: X1 init_array5.cpp 38 : 0x4041d8 count: 2 void
localFunc(const char *) [X = s]
post-main-start: X2 init_array5.cpp 39 : 0x4041dc count: 2 void
localFunc(const char *) [X = s]


g++ version information:
$ g++ --version -v
Using built-in specs.
COLLECT_AS_OPTIONS='--version'
COLLECT_GCC=/usr/bin/g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/10/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
g++ (GCC) 10.2.1 20201016 (Red Hat 10.2.1-6)
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap
--enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,lto --prefix=/usr
--mandir=/usr/share/man --infodir=/usr/share/info
--with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared
--enable-threads=posix --enable-checking=release --enable-multilib
--with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions
--enable-gnu-unique-object --enable-linker-build-id
--with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin
--enable-initfini-array --with-isl --enable-offload-targets=nvptx-none
--without-cuda-driver --enable-gnu-indirect-function --enable-cet
--with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.1 20201016 (Red Hat 10.2.1-6) (GCC) 
COLLECT_GCC_OPTIONS='--version' '-v'