__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