re PR c++/54601 (AIX uses atexit which causes unloading of shared modules to break)
authorDavid Edelsohn <dje.gcc@gmail.com>
Fri, 1 Feb 2013 20:26:24 +0000 (20:26 +0000)
committerDavid Edelsohn <dje@gcc.gnu.org>
Fri, 1 Feb 2013 20:26:24 +0000 (15:26 -0500)
        PR target/54601
libgcc/
        * config.host (powerpc-ibm-aix[56789]): Add t-aix-cxa to tmake_file.
        Add crtcxa to extra_parts.
        * config/rs6000/exit.h: New file.
        * config/rs6000/cxa_atexit.c: New file.
        * config/rs6000/cxa_finalize.c: New file.
        * config/rs6000/crtcxa.c: New file.
        * config/rs6000/t-aix-cxa: New file.
        * config/rs6000/libgcc-aix-cxa.ver: New file.

gcc/
        * configure.ac (cxa_atexit): Add AIX.
        * configure: Regenerate.

        * config/rs6000/aix61.h (STARTFILE_SPEC): Add crtcxa.o.

From-SVN: r195675

12 files changed:
gcc/ChangeLog
gcc/config/rs6000/aix61.h
gcc/configure
gcc/configure.ac
libgcc/ChangeLog
libgcc/config.host
libgcc/config/rs6000/crtcxa.c [new file with mode: 0644]
libgcc/config/rs6000/cxa_atexit.c [new file with mode: 0644]
libgcc/config/rs6000/cxa_finalize.c [new file with mode: 0644]
libgcc/config/rs6000/exit.h [new file with mode: 0644]
libgcc/config/rs6000/libgcc-aix-cxa.ver [new file with mode: 0644]
libgcc/config/rs6000/t-aix-cxa [new file with mode: 0644]

index bbe5a665f1d246478571c3c725dfdae92d8e0a9c..8af4967c718346a28004cfbb3cf1ebfdd9235576 100644 (file)
@@ -1,3 +1,11 @@
+2013-02-01  David Edelsohn  <dje.gcc@gmail.com>
+
+       PR target/54601
+       * configure.ac (use_cxa_atexit): Add AIX.
+       * configure: Regenerate.
+
+       * config/rs6000/aix61.h (STARTFILE_SPEC): Add crtcxa.o.
+
 2013-02-01  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/54793
index d8387fa52a5d340853ce0cc7dace5490183e8db0..42f4ba54a700970388cc8310f7090a3a7086f937 100644 (file)
@@ -163,7 +163,8 @@ do {                                                                        \
    %{maix64:%{pg:gcrt0_64%O%s}%{!pg:%{p:mcrt0_64%O%s}%{!p:crt0_64%O%s}}}\
    %{!maix64:\
      %{pthread:%{pg:gcrt0_r%O%s}%{!pg:%{p:mcrt0_r%O%s}%{!p:crt0_r%O%s}}}\
-     %{!pthread:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}}}"
+     %{!pthread:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}}}\
+   %{shared:crtcxa_s%O%s;:crtcxa%O%s}"
 
 /* AIX V5 typedefs ptrdiff_t as "long" while earlier releases used "int".  */
 
index 6711c0feb5f7f8d3682bb8b4c39bb4394efaaf49..d4f49bbeceb8d2bed6c0f7f01494364f276ac135 100755 (executable)
@@ -11136,6 +11136,9 @@ if test x$enable___cxa_atexit = xyes || \
       *-*-mingw32*)
        use_cxa_atexit=yes
        ;;
+      powerpc-ibm-aix*)
+       use_cxa_atexit=yes
+       ;;
       *)
        ac_fn_c_check_func "$LINENO" "__cxa_atexit" "ac_cv_func___cxa_atexit"
 if test "x$ac_cv_func___cxa_atexit" = x""yes; then :
@@ -17825,7 +17828,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 17828 "configure"
+#line 17831 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -17931,7 +17934,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 17934 "configure"
+#line 17937 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
index 9ae560489059d1c4a6cfe5e92b3bc3434f7b97a2..811c296cb81c30d7224b76061858432f54cb60c6 100644 (file)
@@ -1455,6 +1455,9 @@ if test x$enable___cxa_atexit = xyes || \
       *-*-mingw32*)
        use_cxa_atexit=yes
        ;;
+      powerpc-ibm-aix*)
+       use_cxa_atexit=yes
+       ;;
       *)
        AC_CHECK_FUNC(__cxa_atexit,[use_cxa_atexit=yes],
          [echo "__cxa_atexit can't be enabled on this target"])
index b99f8032fb39bad8d3fc86d34840a017e0e53e17..fc7ebd00d52e43f708dd3809163ab3f44e447bb8 100644 (file)
@@ -1,3 +1,15 @@
+2013-02-01  David Edelsohn  <dje.gcc@gmail.com>
+
+       PR target/54601
+       * config.host (powerpc-ibm-aix[56789]): Add t-aix-cxa to tmake_file.
+       Add crtcxa to extra_parts.
+       * config/rs6000/exit.h: New file.
+       * config/rs6000/cxa_atexit.c: New file.
+       * config/rs6000/cxa_finalize.c: New file.
+       * config/rs6000/crtcxa.c: New file.
+       * config/rs6000/t-aix-cxa: New file.
+       * config/rs6000/libgcc-aix-cxa.ver: New file.
+
 2013-01-31  Nick Clifton  <nickc@redhat.com>
 
        * config/v850/lib1funcs.S: Add support for e3v5 architecture
index 94b3985c0653fbfaafd2241de437fef5c6cd9b4d..ff2d6a4fe89c26f6fdb1f307ef63f73d88ce7054 100644 (file)
@@ -899,7 +899,8 @@ rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1.*)
        ;;
 rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*)
        md_unwind_header=rs6000/aix-unwind.h
-       tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble"
+       tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble rs6000/t-aix-cxa"
+       extra_parts="crtcxa.o crtcxa_s.o"
        ;;
 rl78-*-elf)
        tmake_file="$tm_file t-fdpbit rl78/t-rl78"
diff --git a/libgcc/config/rs6000/crtcxa.c b/libgcc/config/rs6000/crtcxa.c
new file mode 100644 (file)
index 0000000..bff0d2c
--- /dev/null
@@ -0,0 +1,42 @@
+/* __dso_handle initialization for AIX.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Written by David Edelsohn, IBM.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#ifdef SHARED
+void *__dso_handle = &__dso_handle;
+#else
+void *__dso_handle = 0;
+#endif
+
+extern void __cxa_finalize (void *);
+
+/* Add __cxa_finalize call to beginning of destructors list.  */
+void __init_aix_libgcc_cxa_atexit (void) __attribute__ ((destructor (65535)));
+
+void
+__init_aix_libgcc_cxa_atexit (void)
+{
+  __cxa_finalize (__dso_handle);
+}
+
diff --git a/libgcc/config/rs6000/cxa_atexit.c b/libgcc/config/rs6000/cxa_atexit.c
new file mode 100644 (file)
index 0000000..91118ab
--- /dev/null
@@ -0,0 +1,131 @@
+/* Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+   NOTE: This source is derived from an old version taken from the GNU C
+   Library (glibc).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "exit.h"
+
+#undef __cxa_atexit
+
+#define atomic_write_barrier() __asm__ ("eieio" ::: "memory")
+
+int
+attribute_hidden
+__internal_atexit (void (*func) (void *), void *arg, void *d,
+                  struct exit_function_list **listp)
+{
+  struct exit_function *new = __new_exitfn (listp);
+
+  if (new == NULL)
+    return -1;
+
+#ifdef PTR_MANGLE
+  PTR_MANGLE (func);
+#endif
+  new->func.cxa.fn = (void (*) (void *, int)) func;
+  new->func.cxa.arg = arg;
+  new->func.cxa.dso_handle = d;
+  atomic_write_barrier ();
+  new->flavor = ef_cxa;
+  return 0;
+}
+
+
+/* Register a function to be called by exit or when a shared library
+   is unloaded.  This function is only called from code generated by
+   the C++ compiler.  */
+int
+__cxa_atexit (void (*func) (void *), void *arg, void *d)
+{
+  return __internal_atexit (func, arg, d, &__exit_funcs);
+}
+INTDEF(__cxa_atexit)
+
+
+static struct exit_function_list initial;
+struct exit_function_list *__exit_funcs = &initial;
+uint64_t __new_exitfn_called;
+
+struct exit_function *
+__new_exitfn (struct exit_function_list **listp)
+{
+  struct exit_function_list *p = NULL;
+  struct exit_function_list *l;
+  struct exit_function *r = NULL;
+  size_t i = 0;
+
+  for (l = *listp; l != NULL; p = l, l = l->next)
+    {
+      for (i = l->idx; i > 0; --i)
+       if (l->fns[i - 1].flavor != ef_free)
+         break;
+
+      if (i > 0)
+       break;
+
+      /* This block is completely unused.  */
+      l->idx = 0;
+    }
+
+  if (l == NULL || i == sizeof (l->fns) / sizeof (l->fns[0]))
+    {
+      /* The last entry in a block is used.  Use the first entry in
+        the previous block if it exists.  Otherwise create a new one.  */
+      if (p == NULL)
+       {
+         assert (l != NULL);
+         p = (struct exit_function_list *)
+           calloc (1, sizeof (struct exit_function_list));
+         if (p != NULL)
+           {
+             p->next = *listp;
+             *listp = p;
+           }
+       }
+
+      if (p != NULL)
+       {
+         r = &p->fns[0];
+         p->idx = 1;
+       }
+    }
+  else
+    {
+      /* There is more room in the block.  */
+      r = &l->fns[i];
+      l->idx = i + 1;
+    }
+
+  /* Mark entry as used, but we don't know the flavor now.  */
+  if (r != NULL)
+    {
+      r->flavor = ef_us;
+      ++__new_exitfn_called;
+    }
+
+  return r;
+}
diff --git a/libgcc/config/rs6000/cxa_finalize.c b/libgcc/config/rs6000/cxa_finalize.c
new file mode 100644 (file)
index 0000000..623c609
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+   NOTE: This source is derived from an old version taken from the GNU C
+   Library (glibc).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "exit.h"
+
+
+static boolean_t
+catomic_compare_and_exchange_bool_acq (long *mem, long newval, long oldval)
+{
+  return __atomic_compare_exchange (mem, &oldval, &newval, 0,
+                                   __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+/* If D is non-NULL, call all functions registered with `__cxa_atexit'
+   with the same dso handle.  Otherwise, if D is NULL, call all of the
+   registered handlers.  */
+void
+__cxa_finalize (void *d)
+{
+  struct exit_function_list *funcs;
+
+ restart:
+  for (funcs = __exit_funcs; funcs; funcs = funcs->next)
+    {
+      struct exit_function *f;
+
+      for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
+       {
+         void (*cxafn) (void *arg, int status);
+         void *cxaarg;
+
+         if ((d == NULL || d == f->func.cxa.dso_handle)
+             /* We don't want to run this cleanup more than once.  */
+             && (cxafn = f->func.cxa.fn,
+                 cxaarg = f->func.cxa.arg,
+                 ! catomic_compare_and_exchange_bool_acq (&f->flavor, ef_free,
+                                                          ef_cxa)))
+           {
+             uint64_t check = __new_exitfn_called;
+
+#ifdef PTR_DEMANGLE
+             PTR_DEMANGLE (cxafn);
+#endif
+             cxafn (cxaarg, 0);
+
+             /* It is possible that that last exit function registered
+                more exit functions.  Start the loop over.  */
+             if (__builtin_expect (check != __new_exitfn_called, 0))
+               goto restart;
+           }
+       }
+    }
+
+  /* Remove the registered fork handlers.  We do not have to
+     unregister anything if the program is going to terminate anyway.  */
+#ifdef UNREGISTER_ATFORK
+  if (d != NULL)
+    UNREGISTER_ATFORK (d);
+#endif
+}
diff --git a/libgcc/config/rs6000/exit.h b/libgcc/config/rs6000/exit.h
new file mode 100644 (file)
index 0000000..0797252
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (C) 1991-2013 Free Software Foundation, Inc.
+
+Derived from exit.h in GNU C Library.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef        _EXIT_H
+#define _EXIT_H 1
+
+#define attribute_hidden
+#define INTDEF(name)
+
+#include <stdbool.h>
+#include <stdint.h>
+
+enum
+{
+  ef_free,     /* `ef_free' MUST be zero!  */
+  ef_us,
+  ef_on,
+  ef_at,
+  ef_cxa
+};
+
+struct exit_function
+  {
+    /* `flavour' should be of type of the `enum' above but since we need
+       this element in an atomic operation we have to use `long int'.  */
+    long int flavor;
+    union
+      {
+       void (*at) (void);
+       struct
+         {
+           void (*fn) (int status, void *arg);
+           void *arg;
+         } on;
+       struct
+         {
+           void (*fn) (void *arg, int status);
+           void *arg;
+           void *dso_handle;
+         } cxa;
+      } func;
+  };
+struct exit_function_list
+  {
+    struct exit_function_list *next;
+    size_t idx;
+    struct exit_function fns[32];
+  };
+extern struct exit_function_list *__exit_funcs attribute_hidden;
+extern struct exit_function_list *__quick_exit_funcs attribute_hidden;
+
+extern struct exit_function *__new_exitfn (struct exit_function_list **listp);
+extern uint64_t __new_exitfn_called attribute_hidden;
+
+extern void __run_exit_handlers (int status, struct exit_function_list **listp,
+                                bool run_list_atexit)
+  attribute_hidden __attribute__ ((__noreturn__));
+
+extern int __internal_atexit (void (*func) (void *), void *arg, void *d,
+                             struct exit_function_list **listp)
+  attribute_hidden;
+extern int __cxa_at_quick_exit (void (*func) (void *), void *d);
+
+extern int __cxa_atexit (void (*func) (void *), void *arg, void *d);
+extern int __cxa_atexit_internal (void (*func) (void *), void *arg, void *d)
+     attribute_hidden;
+
+extern void __cxa_finalize (void *d);
+
+#endif /* exit.h  */
diff --git a/libgcc/config/rs6000/libgcc-aix-cxa.ver b/libgcc/config/rs6000/libgcc-aix-cxa.ver
new file mode 100644 (file)
index 0000000..083067d
--- /dev/null
@@ -0,0 +1,4 @@
+GCC_4.8 {
+  __cxa_atexit
+  __cxa_finalize
+}
diff --git a/libgcc/config/rs6000/t-aix-cxa b/libgcc/config/rs6000/t-aix-cxa
new file mode 100644 (file)
index 0000000..4ef8185
--- /dev/null
@@ -0,0 +1,10 @@
+LIB2ADDEH += $(srcdir)/config/rs6000/cxa_atexit.c \
+       $(srcdir)/config/rs6000/cxa_finalize.c
+
+SHLIB_MAPFILES += $(srcdir)/config/rs6000/libgcc-aix-cxa.ver
+
+crtcxa.o: $(srcdir)/config/rs6000/crtcxa.c
+       $(crt_compile) -c $<
+
+crtcxa_s.o: $(srcdir)/config/rs6000/crtcxa.c
+       $(crt_compile) -DSHARED -c $<