This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: __cxa_atexit for Darwin


The cctools tarball does not appear to include ld64. Is that needed for ppc64 support for these new features?

Shantonu

On Mar 15, 2006, at 6:23 PM, Geoffrey Keating wrote:


Darwin has had __cxa_atexit since 10.4, but it wasn't being used by default because we didn't have __dso_handle being defined by the linker. Unfortunately it also turned out to be a little buggy. This patch makes it enabled and useful by default, and supplies it even on pre-10.4 systems which don't have it. On those earlier systems it isn't as good as a real system __cxa_atexit but still better than the previous behaviour I hope.

It passes a bootstrap and testrun, but I wouldn't be surprised if
there turns out to be a bug or two in it, so look for follow-up
patches.

This requires cctools-590.36, which I've just uploaded to
gcc.gnu.org.

--
- Geoffrey Keating <geoffk@apple.com>

===File ~/patches/gcc-darwin-cxaatexit-0.patch==============
2006-03-15  Geoffrey Keating  <geoffk@apple.com>

* config.gcc (*-*-darwin*): Don't build crt2.o for all Darwin ports.
Do switch on default_use_cxa_atexit.
(powerpc*-*-darwin*): Build crt2.o on powerpc.
* config/darwin-crt3.o: New.
* config/darwin.h (LINK_SPEC): If -shared-libgcc, make linker default
to 10.3. Pass '-multiply_defined suppress' if crt3.o is in use.
(STARTFILE_SPEC): Add crt3.o when -shared-libgcc and appropriate
OS version.
* config/rs6000/t-darwin: Move crt2.o building to here.
* config/rs6000/darwin.h (C_COMMON_OVERRIDE_OPTIONS): Update
Mac OS version for using __cxa_get_exception_ptr. Don't test versions
of __cxa_atexit.


2006-03-15 Geoffrey Keating <geoffk@apple.com>

	* g++.old-deja/g++.other/init18.C: New.
	* g++.old-deja/g++.other/init5.C: Remove xfail.

Index: testsuite/g++.old-deja/g++.other/init5.C
===================================================================
--- testsuite/g++.old-deja/g++.other/init5.C	(revision 112069)
+++ testsuite/g++.old-deja/g++.other/init5.C	(working copy)
@@ -1,4 +1,4 @@
-// { dg-do run { xfail { ! "powerpc*-*-linux*" } } }
+// { dg-do run }
 // Objects must be destructed in decreasing cnt order
 // Original test attributed to James Kanze <jkanze@otelo.ibmmail.com>

Index: testsuite/g++.old-deja/g++.other/init18.C
===================================================================
--- testsuite/g++.old-deja/g++.other/init18.C	(revision 0)
+++ testsuite/g++.old-deja/g++.other/init18.C	(revision 0)
@@ -0,0 +1,32 @@
+// { dg-do run }
+
+#include <stdlib.h>
+
+static int cnt = 0;
+
+class Foo2
+{
+	public:
+		Foo2() {};
+		~Foo2() { if (++cnt == 2) _Exit (0); };
+};
+
+static Foo2& GetFoo2()
+{
+	static Foo2 foo2;
+	return foo2;
+}
+
+class Foo1
+{
+	public:
+		Foo1() {}
+		~Foo1() { if (++cnt != 1) abort(); GetFoo2(); };
+};
+
+int main( int argc, const char* argv[] )
+{
+	static Foo1 anotherFoo;
+	exit (1);
+}
+
Index: config.gcc
===================================================================
--- config.gcc	(revision 112069)
+++ config.gcc	(working copy)
@@ -368,8 +368,8 @@
   extra_options="${extra_options} darwin.opt"
   c_target_objs="darwin-c.o"
   cxx_target_objs="darwin-c.o"
-  extra_parts="crt2.o"
   extra_objs="darwin.o"
+  default_use_cxa_atexit=yes
   case ${enable_threads} in
     "" | yes | posix) thread_file='posix' ;;
   esac
@@ -1664,6 +1664,7 @@
 	;;
 powerpc-*-darwin*)
 	extra_options="${extra_options} rs6000/darwin.opt"
+	extra_parts="crt2.o"
 	case ${target} in
 	  *-darwin1[0-9]* | *-darwin[8-9]*)
 	    tmake_file="${tmake_file} rs6000/t-darwin8"
Index: config/t-darwin
===================================================================
--- config/t-darwin	(revision 112069)
+++ config/t-darwin	(working copy)
@@ -12,11 +12,12 @@

gt-darwin.h : s-gtype ; @true

-# Explain how to build crt2.o
-$(T)crt2$(objext): $(srcdir)/config/darwin-crt2.c $(GCC_PASSES) \
+# How to build crt3.o
+EXTRA_MULTILIB_PARTS=crt3.o
+$(T)crt3$(objext): $(srcdir)/config/darwin-crt3.c $(GCC_PASSES) \
 	$(TCONFIG_H) stmp-int-hdrs tsystem.h
 	$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) \
-	  -c $(srcdir)/config/darwin-crt2.c -o $(T)crt2$(objext)
+	  -c $(srcdir)/config/darwin-crt3.c -o $(T)crt3$(objext)

# Use unwind-dw2-fde-darwin
LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde- darwin.c \
Index: config/darwin-crt3.c
===================================================================
--- config/darwin-crt3.c (revision 0)
+++ config/darwin-crt3.c (revision 0)
@@ -0,0 +1,208 @@
+/* __cxa_atexit backwards-compatibility support for Darwin.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+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 2, or (at your option) any later
+version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+/* It is incorrect to include config.h here, because this file is being
+ compiled for the target, and hence definitions concerning only the host
+ do not apply. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+
+#include <dlfcn.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/* This file works around two different problems.
+
+ The first problem is that there is no __cxa_atexit on Mac OS versions
+ before 10.4. It fixes this by providing one, and having it called from
+ a destructor. This is not quite as good as having a real __cxa_atexit,
+ but it's good enough to imitate the behaviour that you'd get if
+ you didn't have one.
+
+ The second problem is that on 10.4 Mac OS versions, __cxa_finalize
+ doesn't work right: it doesn't run routines that were registered
+ while other atexit routines are running. This is worked around by
+ installing our own handler so that it runs last, and repeatedly
+ running __cxa_finalize until no new calls to __cxa_atexit are made. */
+
+typedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, void* dso);
+
+#ifdef __ppc__
+void __cxa_finalize (void* dso) __attribute__((weak));
+#else
+void __cxa_finalize (void* dso);
+#endif
+
+/* new_atexit_routines is set if __cxa_finalize exists in the system C
+ library and our copy of __cxa_atexit has been called. */
+
+static bool new_atexit_routines;
+
+/* first_atexit_handler is called after all other atexit routines
+ that were registered before __cxa_finalize is called.
+ It may be called more than once, but is not re-entered. */
+
+static void
+first_atexit_handler(void* dso)
+{
+ /* Keep running __cxa_finalize until no new atexit routines are
+ registered.
+ Note that this means __cxa_finalize will be called at least twice,
+ even if the first call didn't register any new routines. */
+ while (new_atexit_routines) {
+ new_atexit_routines = false;
+ __cxa_finalize (dso);
+ };
+}
+
+/* This is our wrapper around __cxa_atexit that's called if __cxa_finalize
+ exists in the system library. All it does is, on its first call,
+ install first_atexit_handler; and on every call, set new_atexit_routines
+ and pass control to the system __cxa_atexit.
+ This proves to be somewhat more complicated than you might expect,
+ because it may be called in a multithreaded environment. Fortunately
+ it turns out to be possible to do what's needed without resorting
+ to locking. */
+
+static int
+cxa_atexit_wrapper (void (*func) (void*), void* arg, void* dso)
+{
+ static volatile cxa_atexit_p real_cxa_atexit;
+ cxa_atexit_p auto_cxa_atexit = real_cxa_atexit;
+ if (! auto_cxa_atexit)
+ {
+ void* handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD);
+ if (! handle)
+ return -1;
+
+ auto_cxa_atexit = (cxa_atexit_p)dlsym (handle, "__cxa_atexit");
+ if (! auto_cxa_atexit)
+ return -1;
+ }
+ /* At this point, auto_cxa_atexit contains the address of
+ the system __cxa_atexit. */
+ if (! real_cxa_atexit)
+ {
+ /* Install our handler above before any other handlers
+ for this image, so it will be called last. */
+ int result = (*auto_cxa_atexit)(first_atexit_handler, dso, dso);
+ if (result != 0)
+ return result;
+ /* Now set the global real_cxa_atexit to prevent further
+ installations of first_atexit_handler. Do this after
+ the installation so that if another thread sees it is set,
+ it can be sure that first_atexit_handler really has been
+ installed. */
+ real_cxa_atexit = auto_cxa_atexit;
+ }
+ /* At this point, we know that first_atexit_handler has been
+ installed at least once, and real_cxa_atexit is not NULL. */
+ /* It's not necessary to mark new_atexit_routines as volatile, so long
+ as this write eventually happens before this shared object is
+ unloaded. */
+ new_atexit_routines = true;
+ /* Call the original __cxa_atexit for this function. */
+ return (*auto_cxa_atexit)(func, arg, dso);
+}
+
+#ifdef __ppc__
+/* This code is used while running on 10.3.9, when __cxa_atexit doesn't
+ exist in the system library. 10.3.9 only supported regular PowerPC,
+ so this code isn't necessary on x86 or ppc64. */
+
+/* This structure holds a routine to call. */
+struct atexit_routine
+{
+ struct atexit_routine * next;
+ void (*func)(void *);
+ void * arg;
+};
+
+static struct atexit_routine * volatile atexit_routines_list;
+
+/* If __cxa_atexit doesn't exist at all in the system library, this
+ routine is used; it completely emulates __cxa_atexit.
+
+ This routine has to be thread-safe, but fortunately this just means
+ that it has to do atomic list insertion. */
+
+static int
+cxa_atexit_substitute (void (*func) (void*), void* arg,
+ /* The 'dso' value will always be equal to this
+ object's __dso_handle. */
+ void* dso __attribute__((unused)))
+{
+ struct atexit_routine * s = malloc (sizeof (struct atexit_routine));
+ struct atexit_routine * next, * old_next;
+ if (!s)
+ return -1;
+ s->func = func;
+ s->arg = arg;
+ next = atexit_routines_list;
+ do {
+ s->next = old_next = next;
+ next = __sync_val_compare_and_swap (&atexit_routines_list, old_next, s);
+ } while (next != old_next);
+ return 0;
+}
+
+/* The routines added in cxa_atexit_substitute get run here, in a destructor.
+ This routine doesn't have to be thread-safe. */
+
+static void cxa_dtor (void) __attribute__((destructor));
+static void
+cxa_dtor (void)
+{
+ while (atexit_routines_list)
+ {
+ struct atexit_routine * working_list = atexit_routines_list;
+ atexit_routines_list = NULL;
+ while (working_list)
+ {
+ struct atexit_routine * called_routine = working_list;
+ working_list->func (working_list->arg);
+ working_list = working_list->next;
+ free (called_routine);
+ }
+ }
+}
+#endif
+
+int __cxa_atexit (void (*func) (void*), void* arg,
+ void* dso) __attribute__((visibility("hidden")));
+int
+__cxa_atexit (void (*func) (void*), void* arg, void* dso)
+{
+#ifdef __ppc__
+ if (! __cxa_finalize)
+ return cxa_atexit_substitute (func, arg, dso);
+#endif
+ return cxa_atexit_wrapper (func, arg, dso);
+}
Index: config/rs6000/t-darwin
===================================================================
--- config/rs6000/t-darwin (revision 112069)
+++ config/rs6000/t-darwin (working copy)
@@ -25,3 +25,9 @@


 darwin-fpsave.o:	$(srcdir)/config/rs6000/darwin-asm.h
 darwin-tramp.o:		$(srcdir)/config/rs6000/darwin-asm.h
+
+# Explain how to build crt2.o
+$(T)crt2$(objext): $(srcdir)/config/darwin-crt2.c $(GCC_PASSES) \
+	$(TCONFIG_H) stmp-int-hdrs tsystem.h
+	$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) \
+	  -c $(srcdir)/config/darwin-crt2.c -o $(T)crt2$(objext)
Index: config/rs6000/darwin.h
===================================================================
--- config/rs6000/darwin.h	(revision 112069)
+++ config/rs6000/darwin.h	(working copy)
@@ -97,17 +97,11 @@

#define C_COMMON_OVERRIDE_OPTIONS do { \
/* On powerpc, __cxa_get_exception_ptr is available starting in the \
- 10.5 libstdc++.dylib. */ \
+ 10.4.6 libstdc++.dylib. */ \
if ((! darwin_macosx_version_min \
- || strverscmp (darwin_macosx_version_min, "10.5") < 0) \
+ || strverscmp (darwin_macosx_version_min, "10.4.6") < 0) \
&& flag_use_cxa_get_exception_ptr == 2) \
flag_use_cxa_get_exception_ptr = 0; \
- /* On powerpc, __cxa_atexit is available starting in the 10.4 \
- libSystem.dylib. */ \
- if ((! darwin_macosx_version_min \
- || strverscmp (darwin_macosx_version_min, "10.4") < 0) \
- && flag_use_cxa_atexit == 2) \
- flag_use_cxa_atexit = 0; \
} while (0)


/* Darwin has 128-bit long double support in libc in 10.4 and later.
Index: config/darwin.h
===================================================================
--- config/darwin.h (revision 112069)
+++ config/darwin.h (working copy)
@@ -262,9 +262,13 @@
%{Zimage_base*:-image_base %*} \
%{Zinit*:-init %*} \
%{mmacosx-version-min=*:-macosx_version_min %*} \
+ %{!mmacosx-version-min=*:%{shared-libgcc:-macosx_version_min 10.3}} \
%{nomultidefs} \
%{Zmulti_module:-multi_module} %{Zsingle_module:-single_module} \
%{Zmultiply_defined*:-multiply_defined %*} \
+ %{!Zmultiply_defined*:%{shared-libgcc: \
+ %:version-compare(< 10.5 mmacosx-version-min= - multiply_defined) \
+ %:version-compare(< 10.5 mmacosx-version-min= suppress)}} \
%{Zmultiplydefinedunused*:-multiply_defined_unused %*} \
%{prebind} %{noprebind} %{nofixprebinding} % {prebind_all_twolevel_modules} \
%{read_only_relocs} \
@@ -319,19 +323,25 @@
%:version-compare(>= 10.5 mmacosx-version-min= -lgcc_s. 10.5) \
-lgcc}"


-/* We specify crt0.o as -lcrt0.o so that ld will search the library path. */
+/* We specify crt0.o as -lcrt0.o so that ld will search the library path.


+ crt3.o provides __cxa_atexit on systems that don't have it. Since
+ it's only used with C++, which requires passing -shared-libgcc, key
+ off that to avoid unnecessarily adding a destructor to every
+ powerpc program built. */
+
#undef STARTFILE_SPEC
-#define STARTFILE_SPEC \
- "%{!Zdynamiclib:%{Zbundle:%{!static:-lbundle1.o}} \
- %{!Zbundle:%{pg:%{static:-lgcrt0.o} \
- %{!static:%{object:-lgcrt0.o} \
- %{!object:%{preload:-lgcrt0.o} \
- %{!preload:-lgcrt1.o % (darwin_crt2)}}}} \
- %{!pg:%{static:-lcrt0.o} \
- %{!static:%{object:-lcrt0.o} \
- %{!object:%{preload:-lcrt0.o} \
- %{!preload:-lcrt1.o % (darwin_crt2)}}}}}}"
+#define STARTFILE_SPEC \
+ "%{!Zdynamiclib:%{Zbundle:%{!static:-lbundle1.o}} \
+ %{!Zbundle:%{pg:%{static:-lgcrt0.o} \
+ %{!static:%{object:-lgcrt0.o} \
+ %{!object:%{preload:-lgcrt0.o} \
+ %{!preload:-lgcrt1.o % (darwin_crt2)}}}} \
+ %{!pg:%{static:-lcrt0.o} \
+ %{!static:%{object:-lcrt0.o} \
+ %{!object:%{preload:-lcrt0.o} \
+ %{!preload:-lcrt1.o % (darwin_crt2)}}}}}} \
+ %{shared-libgcc:%:version-compare(< 10.5 mmacosx-version-min= - lcrt3.o)}"


/* The native Darwin linker doesn't necessarily place files in the order
that they're specified on the link line. Thus, it is pointless
============================================================


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]