diff mbox

[RFC] __cxa_atexit support for AIX (v2)

Message ID CAGWvnykFZOnVeuaTLuSeCG-YMn2OvcX34efCbaYCU+xrLwi70w@mail.gmail.com
State New
Headers show

Commit Message

David Edelsohn Feb. 1, 2013, 3:40 p.m. UTC
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.
diff mbox

Patch

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 (edelsohn@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".  */