summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/collect2.c69
-rw-r--r--gcc/config/rs6000/aix.h29
-rw-r--r--libgcc/ChangeLog9
-rw-r--r--libgcc/config/rs6000/aixinitfini.c33
-rw-r--r--libgcc/config/rs6000/libgcc-aix-cxa.ver5
-rw-r--r--libgcc/config/rs6000/t-aix-cxa2
7 files changed, 162 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c4f56ba6fbd..fee3273a300 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/collect2.c b/gcc/collect2.c
index 84cf6b476e4..95f817d307a 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 a11bd57284d..1a879da49cc 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 a3521da0935..1e7731a5992 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -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.
diff --git a/libgcc/config/rs6000/aixinitfini.c b/libgcc/config/rs6000/aixinitfini.c
new file mode 100644
index 00000000000..e95575820e2
--- /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 083067d141b..f89df2312a3 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 4ef818558a7..4755c20c964 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