Richard Stallman has given permission to include code derived from GNU
C Library in libgcc for AIX using the GCC Runtime Exception license.

The updated patch is appended.  The GNU C Library code (cxa_atexit.c,
cxa_finalize.c, exit.h) is modified, so I am not exactly certain if my
reference to the GNU C Library origin is correct.

This has been bootstrapped on powerpc-ibm-aix7.1.0.0 using --enable-cxa_atexit.

Any comments, especially about the header for the files derived from
GNU C Library?

Thanks, David

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/
        * config/rs6000/aix61.h (STARTFILE_SPEC): Add crtcxa.

Index: libgcc/config.host
===================================================================
--- libgcc/config.host  (revision 195639)
+++ libgcc/config.host  (working copy)
@@ -899,7 +899,8 @@
        ;;
 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"
Index: libgcc/config/rs6000/exit.h
===================================================================
--- libgcc/config/rs6000/exit.h (revision 0)
+++ libgcc/config/rs6000/exit.h (revision 0)
@@ -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  */
Index: libgcc/config/rs6000/cxa_atexit.c
===================================================================
--- libgcc/config/rs6000/cxa_atexit.c   (revision 0)
+++ libgcc/config/rs6000/cxa_atexit.c   (revision 0)
@@ -0,0 +1,130 @@
+/* Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+Derived from cxa_atexit.c 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/>.  */
+
+#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;
+}
Index: libgcc/config/rs6000/t-aix-cxa
===================================================================
--- libgcc/config/rs6000/t-aix-cxa      (revision 0)
+++ libgcc/config/rs6000/t-aix-cxa      (revision 0)
@@ -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 $<
Index: libgcc/config/rs6000/crtcxa.c
===================================================================
--- libgcc/config/rs6000/crtcxa.c       (revision 0)
+++ libgcc/config/rs6000/crtcxa.c       (revision 0)
@@ -0,0 +1,42 @@
+/* __dso_handle initialization for AIX.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by David Edelsohn (edels...@gnu.org).
+
+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);
+}
+
Index: libgcc/config/rs6000/libgcc-aix-cxa.ver
===================================================================
--- libgcc/config/rs6000/libgcc-aix-cxa.ver     (revision 0)
+++ libgcc/config/rs6000/libgcc-aix-cxa.ver     (revision 0)
@@ -0,0 +1,4 @@
+GCC_4.8 {
+  __cxa_atexit
+  __cxa_finalize
+}
Index: libgcc/config/rs6000/cxa_finalize.c
===================================================================
--- libgcc/config/rs6000/cxa_finalize.c (revision 0)
+++ libgcc/config/rs6000/cxa_finalize.c (revision 0)
@@ -0,0 +1,84 @@
+/* Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+Derived from cxa_finalize.c 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/>.  */
+
+#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
+}
Index: gcc/config/rs6000/aix61.h
===================================================================
--- gcc/config/rs6000/aix61.h   (revision 195639)
+++ gcc/config/rs6000/aix61.h   (working copy)
@@ -163,7 +163,8 @@
    %{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".  */

Reply via email to