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:
parent
cf77a18016
commit
4417887978
|
@ -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>
|
2013-11-23 David Edelsohn <dje.gcc@gmail.com>
|
||||||
|
|
||||||
* config/rs6000/rs6000.c (IN_NAMED_SECTION): New macro.
|
* config/rs6000/rs6000.c (IN_NAMED_SECTION): New macro.
|
||||||
|
|
|
@ -182,6 +182,7 @@ static int strip_flag; /* true if -s */
|
||||||
static int export_flag; /* true if -bE */
|
static int export_flag; /* true if -bE */
|
||||||
static int aix64_flag; /* true if -b64 */
|
static int aix64_flag; /* true if -b64 */
|
||||||
static int aixrtl_flag; /* true if -brtl */
|
static int aixrtl_flag; /* true if -brtl */
|
||||||
|
static int aixlazy_flag; /* true if -blazy */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum lto_mode_d {
|
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 */
|
const char *c_file_name; /* pathname of gcc */
|
||||||
static char *initname, *fininame; /* names of init and fini funcs */
|
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 constructors; /* list of constructors found */
|
||||||
static struct head destructors; /* list of destructors found */
|
static struct head destructors; /* list of destructors found */
|
||||||
#ifdef COLLECT_EXPORT_LIST
|
#ifdef COLLECT_EXPORT_LIST
|
||||||
|
@ -279,7 +287,9 @@ typedef enum {
|
||||||
SYM_DTOR = 2, /* destructor */
|
SYM_DTOR = 2, /* destructor */
|
||||||
SYM_INIT = 3, /* shared object routine that calls all the ctors */
|
SYM_INIT = 3, /* shared object routine that calls all the ctors */
|
||||||
SYM_FINI = 4, /* shared object routine that calls all the dtors */
|
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;
|
} symkind;
|
||||||
|
|
||||||
static symkind is_ctor_dtor (const char *);
|
static symkind is_ctor_dtor (const char *);
|
||||||
|
@ -340,6 +350,8 @@ enum scanfilter_masks {
|
||||||
SCAN_INIT = 1 << SYM_INIT,
|
SCAN_INIT = 1 << SYM_INIT,
|
||||||
SCAN_FINI = 1 << SYM_FINI,
|
SCAN_FINI = 1 << SYM_FINI,
|
||||||
SCAN_DWEH = 1 << SYM_DWEH,
|
SCAN_DWEH = 1 << SYM_DWEH,
|
||||||
|
SCAN_AIXI = 1 << SYM_AIXI,
|
||||||
|
SCAN_AIXD = 1 << SYM_AIXD,
|
||||||
SCAN_ALL = ~0
|
SCAN_ALL = ~0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -589,6 +601,10 @@ is_ctor_dtor (const char *s)
|
||||||
{ "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, SYM_DWEH, 0 },
|
{ "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, SYM_DWEH, 0 },
|
||||||
{ "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, SYM_INIT, 0 },
|
{ "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, SYM_INIT, 0 },
|
||||||
{ "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, SYM_FINI, 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 }
|
{ NULL, 0, SYM_REGULAR, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1034,6 +1050,8 @@ main (int argc, char **argv)
|
||||||
aixrtl_flag = 1;
|
aixrtl_flag = 1;
|
||||||
else if (strcmp (argv[i], "-bnortl") == 0)
|
else if (strcmp (argv[i], "-bnortl") == 0)
|
||||||
aixrtl_flag = 0;
|
aixrtl_flag = 0;
|
||||||
|
else if (strcmp (argv[i], "-blazy") == 0)
|
||||||
|
aixlazy_flag = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
vflag = debug;
|
vflag = debug;
|
||||||
|
@ -1728,6 +1746,11 @@ main (int argc, char **argv)
|
||||||
if (! exports.first)
|
if (! exports.first)
|
||||||
*ld2++ = concat ("-bE:", export_file, NULL);
|
*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
|
#ifndef LD_INIT_SWITCH
|
||||||
add_to_list (&exports, initname);
|
add_to_list (&exports, initname);
|
||||||
add_to_list (&exports, fininame);
|
add_to_list (&exports, fininame);
|
||||||
|
@ -2020,6 +2043,19 @@ extract_init_priority (const char *name)
|
||||||
{
|
{
|
||||||
int pos = 0, pri;
|
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] == '_')
|
while (name[pos] == '_')
|
||||||
++pos;
|
++pos;
|
||||||
pos += 10; /* strlen ("GLOBAL__X_") */
|
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);
|
initname = concat ("_GLOBAL__FI_", prefix, NULL);
|
||||||
fininame = concat ("_GLOBAL__FD_", 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);
|
free (prefix);
|
||||||
|
|
||||||
/* Write the tables as C code. */
|
/* 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, "static int count;\n");
|
||||||
fprintf (stream, "typedef void entry_pt();\n");
|
fprintf (stream, "typedef void entry_pt();\n");
|
||||||
write_list_with_asm (stream, "extern entry_pt ", constructors.first);
|
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';
|
*end = '\0';
|
||||||
|
|
||||||
switch (is_ctor_dtor (name))
|
switch (is_ctor_dtor (name))
|
||||||
{
|
{
|
||||||
case SYM_CTOR:
|
case SYM_CTOR:
|
||||||
|
@ -2892,6 +2940,25 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
|
||||||
|
|
||||||
switch (is_ctor_dtor (name))
|
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:
|
case SYM_CTOR:
|
||||||
if (! (filter & SCAN_CTOR))
|
if (! (filter & SCAN_CTOR))
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -47,6 +47,35 @@
|
||||||
collect has a chance to see them, so scan the object files directly. */
|
collect has a chance to see them, so scan the object files directly. */
|
||||||
#define COLLECT_EXPORT_LIST
|
#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
|
#if HAVE_AS_REF
|
||||||
/* Issue assembly directives that create a reference to the given DWARF table
|
/* Issue assembly directives that create a reference to the given DWARF table
|
||||||
identifier label from the current function section. This is defined to
|
identifier label from the current function section. This is defined to
|
||||||
|
|
|
@ -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>
|
2013-11-22 Yuri Rumyantsev <ysrumyan@gmail.com>
|
||||||
|
|
||||||
* config/i386/cpuinfo.c (get_intel_cpu): Add Silvermont cases.
|
* config/i386/cpuinfo.c (get_intel_cpu): Add Silvermont cases.
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -2,3 +2,8 @@ GCC_4.8 {
|
||||||
__cxa_atexit
|
__cxa_atexit
|
||||||
__cxa_finalize
|
__cxa_finalize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GCC_4.9 {
|
||||||
|
_GLOBAL__AIXI_shr_o
|
||||||
|
_GLOBAL__AIXD_shr_o
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
LIB2ADDEH += $(srcdir)/config/rs6000/cxa_atexit.c \
|
LIB2ADDEH += $(srcdir)/config/rs6000/cxa_atexit.c \
|
||||||
$(srcdir)/config/rs6000/cxa_finalize.c
|
$(srcdir)/config/rs6000/cxa_finalize.c
|
||||||
|
|
||||||
|
LIB2ADD_ST += $(srcdir)/config/rs6000/aixinitfini.c
|
||||||
|
|
||||||
SHLIB_MAPFILES += $(srcdir)/config/rs6000/libgcc-aix-cxa.ver
|
SHLIB_MAPFILES += $(srcdir)/config/rs6000/libgcc-aix-cxa.ver
|
||||||
|
|
||||||
crtcxa.o: $(srcdir)/config/rs6000/crtcxa.c
|
crtcxa.o: $(srcdir)/config/rs6000/crtcxa.c
|
||||||
|
|
Loading…
Reference in New Issue