__cxa_atexit for Darwin

Geoffrey Keating geoffk@apple.com
Thu Mar 16 02:37:00 GMT 2006


On 15/03/2006, at 6:32 PM, Shantonu Sen wrote:

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

Now that you mention it, I'm not entirely sure.  I guess the  
regression tester will tell me if it's needed, in which case I'll be  
backing out the change to config.gcc...

> 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
>> ============================================================
>

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2408 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20060316/bd17bcbe/attachment.p7s>


More information about the Gcc-patches mailing list