re PR target/33704 (AIX runs c++ constructors in incorrect order)

libgcc:

	PR target/33704
        * config/rs6000/aixinitfini.c: New file.
        * config/rs6000/t-aix-cxa (LIB2ADD_ST): Add aixinitfini.c.
        * config/rs6000/libgcc-aix-cxa.ver (GCC_4.9): Add libgcc initfini
        symbols.

gcc:

	PR target/33704
        * config/rs6000/aix.h (COLLECT_SHARED_INIT_FUNC): Define.
        (COLLECT_SHARED_FINI_FUNC): Define.

        * collect2.c (aix_shared_initname): Declare.
        (aix_shared_fininame): Declare.
        (symkind): Add SYM_AIXI and SYM_AIXD.
        (scanfilter_masks): Add SCAN_AIXI and SCAN_AIXD.
        (struct names special): Add GLOBAL__AIXI_ and GLOBAL__AIXD_.
        (aixlazy_flag): Parse.
        (extract_init_priority): SYM_AIXI and SYM_AIXD have highest priority.
        (scan_prog_file, COFF): Handle SYM_AIXI and SYM_AIXD.

Co-Authored-By: Andrew Dixie <andrewd@gentrack.com>

From-SVN: r205309
This commit is contained in:
David Edelsohn 2013-11-23 10:38:07 -05:00 committed by David Edelsohn
parent cf77a18016
commit 4417887978
7 changed files with 162 additions and 1 deletions

View File

@ -1,3 +1,19 @@
2013-11-23 David Edelson <dje.gcc@gmail.com>
Andrew Dixie <andrewd@gentrack.com>
PR target/33704
* config/rs6000/aix.h (COLLECT_SHARED_INIT_FUNC): Define.
(COLLECT_SHARED_FINI_FUNC): Define.
* collect2.c (aix_shared_initname): Declare.
(aix_shared_fininame): Declare.
(symkind): Add SYM_AIXI and SYM_AIXD.
(scanfilter_masks): Add SCAN_AIXI and SCAN_AIXD.
(struct names special): Add GLOBAL__AIXI_ and GLOBAL__AIXD_.
(aixlazy_flag): Parse.
(extract_init_priority): SYM_AIXI and SYM_AIXD have highest priority.
(scan_prog_file, COFF): Handle SYM_AIXI and SYM_AIXD.
2013-11-23 David Edelsohn <dje.gcc@gmail.com>
* config/rs6000/rs6000.c (IN_NAMED_SECTION): New macro.

View File

@ -182,6 +182,7 @@ static int strip_flag; /* true if -s */
static int export_flag; /* true if -bE */
static int aix64_flag; /* true if -b64 */
static int aixrtl_flag; /* true if -brtl */
static int aixlazy_flag; /* true if -blazy */
#endif
enum lto_mode_d {
@ -215,6 +216,13 @@ static const char *strip_file_name; /* pathname of strip */
const char *c_file_name; /* pathname of gcc */
static char *initname, *fininame; /* names of init and fini funcs */
#ifdef TARGET_AIX_VERSION
static char *aix_shared_initname;
static char *aix_shared_fininame; /* init/fini names as per the scheme
described in config/rs6000/aix.h */
#endif
static struct head constructors; /* list of constructors found */
static struct head destructors; /* list of destructors found */
#ifdef COLLECT_EXPORT_LIST
@ -279,7 +287,9 @@ typedef enum {
SYM_DTOR = 2, /* destructor */
SYM_INIT = 3, /* shared object routine that calls all the ctors */
SYM_FINI = 4, /* shared object routine that calls all the dtors */
SYM_DWEH = 5 /* DWARF exception handling table */
SYM_DWEH = 5, /* DWARF exception handling table */
SYM_AIXI = 6,
SYM_AIXD = 7
} symkind;
static symkind is_ctor_dtor (const char *);
@ -340,6 +350,8 @@ enum scanfilter_masks {
SCAN_INIT = 1 << SYM_INIT,
SCAN_FINI = 1 << SYM_FINI,
SCAN_DWEH = 1 << SYM_DWEH,
SCAN_AIXI = 1 << SYM_AIXI,
SCAN_AIXD = 1 << SYM_AIXD,
SCAN_ALL = ~0
};
@ -589,6 +601,10 @@ is_ctor_dtor (const char *s)
{ "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, SYM_DWEH, 0 },
{ "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, SYM_INIT, 0 },
{ "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, SYM_FINI, 0 },
#ifdef TARGET_AIX_VERSION
{ "GLOBAL__AIXI_", sizeof ("GLOBAL__AIXI_")-1, SYM_AIXI, 0 },
{ "GLOBAL__AIXD_", sizeof ("GLOBAL__AIXD_")-1, SYM_AIXD, 0 },
#endif
{ NULL, 0, SYM_REGULAR, 0 }
};
@ -1034,6 +1050,8 @@ main (int argc, char **argv)
aixrtl_flag = 1;
else if (strcmp (argv[i], "-bnortl") == 0)
aixrtl_flag = 0;
else if (strcmp (argv[i], "-blazy") == 0)
aixlazy_flag = 1;
#endif
}
vflag = debug;
@ -1728,6 +1746,11 @@ main (int argc, char **argv)
if (! exports.first)
*ld2++ = concat ("-bE:", export_file, NULL);
#ifdef TARGET_AIX_VERSION
add_to_list (&exports, aix_shared_initname);
add_to_list (&exports, aix_shared_fininame);
#endif
#ifndef LD_INIT_SWITCH
add_to_list (&exports, initname);
add_to_list (&exports, fininame);
@ -2020,6 +2043,19 @@ extract_init_priority (const char *name)
{
int pos = 0, pri;
#ifdef TARGET_AIX_VERSION
/* Run dependent module initializers before any constructors in this
module. */
switch (is_ctor_dtor (name))
{
case SYM_AIXI:
case SYM_AIXD:
return INT_MIN;
default:
break;
}
#endif
while (name[pos] == '_')
++pos;
pos += 10; /* strlen ("GLOBAL__X_") */
@ -2180,11 +2216,22 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED)
initname = concat ("_GLOBAL__FI_", prefix, NULL);
fininame = concat ("_GLOBAL__FD_", prefix, NULL);
#ifdef TARGET_AIX_VERSION
aix_shared_initname = concat ("_GLOBAL__AIXI_", prefix, NULL);
aix_shared_fininame = concat ("_GLOBAL__AIXD_", prefix, NULL);
#endif
free (prefix);
/* Write the tables as C code. */
/* This count variable is used to prevent multiple calls to the
constructors/destructors.
This guard against multiple calls is important on AIX as the initfini
functions are deliberately invoked multiple times as part of the
mechanisms GCC uses to order constructors across different dependent
shared libraries (see config/rs6000/aix.h).
*/
fprintf (stream, "static int count;\n");
fprintf (stream, "typedef void entry_pt();\n");
write_list_with_asm (stream, "extern entry_pt ", constructors.first);
@ -2531,6 +2578,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
*end = '\0';
switch (is_ctor_dtor (name))
{
case SYM_CTOR:
@ -2892,6 +2940,25 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
switch (is_ctor_dtor (name))
{
#if TARGET_AIX_VERSION
/* Add AIX shared library initalisers/finalisers
to the constructors/destructors list of the
current module. */
case SYM_AIXI:
if (! (filter & SCAN_CTOR))
break;
if (is_shared && !aixlazy_flag)
add_to_list (&constructors, name);
break;
case SYM_AIXD:
if (! (filter & SCAN_DTOR))
break;
if (is_shared && !aixlazy_flag)
add_to_list (&destructors, name);
break;
#endif
case SYM_CTOR:
if (! (filter & SCAN_CTOR))
break;

View File

@ -47,6 +47,35 @@
collect has a chance to see them, so scan the object files directly. */
#define COLLECT_EXPORT_LIST
/* On AIX, initialisers specified with -binitfini are called in breadth-first
order.
e.g. if a.out depends on lib1.so, the init function for a.out is called before
the init function for lib1.so.
To ensure global C++ constructors in linked libraries are run before global
C++ constructors from the current module, there is additional symbol scanning
logic in collect2.
The global initialiser/finaliser functions are named __GLOBAL_AIXI_{libname}
and __GLOBAL_AIXD_{libname} and are exported from each shared library.
collect2 will detect these symbols when they exist in shared libraries that
the current program is being linked against. All such initiliser functions
will be called prior to the constructors of the current program, and
finaliser functions called after destructors.
Reference counting generated by collect2 will ensure that constructors are
only invoked once in the case of multiple dependencies on a library.
-binitfini is still used in parallel to this solution.
This handles the case where a library is loaded through dlopen(), and also
handles the option -blazy.
*/
#define COLLECT_SHARED_INIT_FUNC(STREAM, FUNC) \
fprintf ((STREAM), "void %s() {\n\t%s();\n}\n", aix_shared_initname, (FUNC))
#define COLLECT_SHARED_FINI_FUNC(STREAM, FUNC) \
fprintf ((STREAM), "void %s() {\n\t%s();\n}\n", aix_shared_fininame, (FUNC))
#if HAVE_AS_REF
/* Issue assembly directives that create a reference to the given DWARF table
identifier label from the current function section. This is defined to

View File

@ -1,3 +1,12 @@
2013-11-23 David Edelson <dje.gcc@gmail.com>
Andrew Dixie <andrewd@gentrack.com>
PR target/33704
* config/rs6000/aixinitfini.c: New file.
* config/rs6000/t-aix-cxa (LIB2ADD_ST): Add aixinitfini.c.
* config/rs6000/libgcc-aix-cxa.ver (GCC_4.9): Add libgcc initfini
symbols.
2013-11-22 Yuri Rumyantsev <ysrumyan@gmail.com>
* config/i386/cpuinfo.c (get_intel_cpu): Add Silvermont cases.

View File

@ -0,0 +1,33 @@
/* FIXME: rename this file */
/*
Artificially create _GLOBAL_AIX[ID]_shr_o symbols in libgcc.a.
This means that libstdc++.a can invoke these symbols and they are resolved
regardless of whether libstdc++.a is linked against libgcc_s.a or libgcc.a.
The symbols are created in libgcc_s.a by collect2 as there are exception
frames to register for LIB2_DIVMOD_FUNCS.
The symbols are NOT created by collect2 for libgcc.a, because libgcc.a is
a 'real' archive containing objects and collect2 is not invoked.
libstdc++.a is linked against libgcc.a when handling the command line
options '-static-libgcc -static-libstdc++'.
*/
void _GLOBAL__AIXI_shr_o (void);
void _GLOBAL__AIXD_shr_o (void);
void
_GLOBAL__AIXI_shr_o (void)
{
return;
}
void
_GLOBAL__AIXD_shr_o (void)
{
return;
}

View File

@ -2,3 +2,8 @@ GCC_4.8 {
__cxa_atexit
__cxa_finalize
}
GCC_4.9 {
_GLOBAL__AIXI_shr_o
_GLOBAL__AIXD_shr_o
}

View File

@ -1,6 +1,8 @@
LIB2ADDEH += $(srcdir)/config/rs6000/cxa_atexit.c \
$(srcdir)/config/rs6000/cxa_finalize.c
LIB2ADD_ST += $(srcdir)/config/rs6000/aixinitfini.c
SHLIB_MAPFILES += $(srcdir)/config/rs6000/libgcc-aix-cxa.ver
crtcxa.o: $(srcdir)/config/rs6000/crtcxa.c