]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/33704 (AIX runs c++ constructors in incorrect order)
authorDavid Edelsohn <dje.gcc@gmail.com>
Sat, 23 Nov 2013 15:38:07 +0000 (10:38 -0500)
committerDavid Edelsohn <dje@gcc.gnu.org>
Sat, 23 Nov 2013 15:38:07 +0000 (10:38 -0500)
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

gcc/ChangeLog
gcc/collect2.c
gcc/config/rs6000/aix.h
libgcc/ChangeLog
libgcc/config/rs6000/aixinitfini.c [new file with mode: 0644]
libgcc/config/rs6000/libgcc-aix-cxa.ver
libgcc/config/rs6000/t-aix-cxa

index c4f56ba6fbd57df73d85d3ab3c4e920b57ff434c..fee3273a3004524d491f0665b4b27f0261a4c7b1 100644 (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.
index 84cf6b476e41c100aaea421d8ce5fcab6af21f5e..95f817d307ac345ef79efb6b839c39fc29124d62 100644 (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;
index a11bd57284d4646c341c30a83da263ca8ad00275..1a879da49ccdde33f4bd6665364a5c238300150c 100644 (file)
    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
index a3521da0935b36f7e7eb41d2ccea589747d14443..1e7731a59928dfdc83a12f0409e8185cd8e7d7bb 100644 (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.
diff --git a/libgcc/config/rs6000/aixinitfini.c b/libgcc/config/rs6000/aixinitfini.c
new file mode 100644 (file)
index 0000000..e955758
--- /dev/null
@@ -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;
+}
+
index 083067d141bc4cf92b9dcc77f4f9192073c5c9c3..f89df2312a30d5a88fe34beec638ab7f7666081a 100644 (file)
@@ -2,3 +2,8 @@ GCC_4.8 {
   __cxa_atexit
   __cxa_finalize
 }
+
+GCC_4.9 {
+  _GLOBAL__AIXI_shr_o
+  _GLOBAL__AIXD_shr_o
+}
index 4ef818558a7c503c45dc1645ece83cab2431f94b..4755c20c9649105480486b582368006e3e873d5e 100644 (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