From 39da74401a8eb9031a8d1e0e3556d0a47964e04f Mon Sep 17 00:00:00 2001 From: dje Date: Sat, 23 Nov 2013 15:38:07 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205309 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 16 ++++++++ gcc/collect2.c | 69 ++++++++++++++++++++++++++++++++- gcc/config/rs6000/aix.h | 29 ++++++++++++++ libgcc/ChangeLog | 9 +++++ libgcc/config/rs6000/aixinitfini.c | 33 ++++++++++++++++ libgcc/config/rs6000/libgcc-aix-cxa.ver | 5 +++ libgcc/config/rs6000/t-aix-cxa | 2 + 7 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 libgcc/config/rs6000/aixinitfini.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c4f56ba..fee3273 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2013-11-23 David Edelson + Andrew Dixie + + 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 * config/rs6000/rs6000.c (IN_NAMED_SECTION): New macro. diff --git a/gcc/collect2.c b/gcc/collect2.c index 84cf6b4..95f817d 100644 --- a/gcc/collect2.c +++ b/gcc/collect2.c @@ -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; diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h index a11bd57..1a879da 100644 --- a/gcc/config/rs6000/aix.h +++ b/gcc/config/rs6000/aix.h @@ -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 diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index a3521da..1e7731a 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,12 @@ +2013-11-23 David Edelson + Andrew Dixie + + 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 * config/i386/cpuinfo.c (get_intel_cpu): Add Silvermont cases. diff --git a/libgcc/config/rs6000/aixinitfini.c b/libgcc/config/rs6000/aixinitfini.c new file mode 100644 index 0000000..e955758 --- /dev/null +++ b/libgcc/config/rs6000/aixinitfini.c @@ -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; +} + diff --git a/libgcc/config/rs6000/libgcc-aix-cxa.ver b/libgcc/config/rs6000/libgcc-aix-cxa.ver index 083067d..f89df23 100644 --- a/libgcc/config/rs6000/libgcc-aix-cxa.ver +++ b/libgcc/config/rs6000/libgcc-aix-cxa.ver @@ -2,3 +2,8 @@ GCC_4.8 { __cxa_atexit __cxa_finalize } + +GCC_4.9 { + _GLOBAL__AIXI_shr_o + _GLOBAL__AIXD_shr_o +} diff --git a/libgcc/config/rs6000/t-aix-cxa b/libgcc/config/rs6000/t-aix-cxa index 4ef8185..4755c20 100644 --- a/libgcc/config/rs6000/t-aix-cxa +++ b/libgcc/config/rs6000/t-aix-cxa @@ -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 -- 2.7.4