This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH to support __cxa_atexit
- To: gcc-patches at gcc dot gnu dot org
- Subject: PATCH to support __cxa_atexit
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Thu, 16 Dec 1999 23:44:48 -0800
- Organization: CodeSourcery, LLC
There's a long-standing bug in many C++ implementations that can be
seen with the following program:
test.C
======
#include <dlfcn.h>
#include <stdio.h>
struct S {
~S () { printf ("Goodbye, world.\n"); }
};
typedef void (*fn_t)();
void f () { static S s; }
int main ()
{
void *lib1;
fn_t gp;
printf ("In main\n");
lib1 = dlopen ("/home/mitchell/tmp/test2.so", RTLD_LAZY);
gp = (fn_t) dlsym (lib1, "g");
(*gp) ();
printf ("Back in main\n");
f ();
dlclose (lib1);
exit (0);
}
test2.C
=======
#include <stdio.h>
struct T {
~T () { printf ("Shared object going away...\n"); }
};
extern "C" void g ()
{
printf ("In shared object\n");
static T t;
}
Now, suppose that `test2.C' is compiled into a shared library, and
`test.C' is used as the main program. When run, we get a crash:
linux1.codesourcery.com% test-g++2 -shared -o test2.so test2.C
linux1.codesourcery.com% test-g++2 test.C -ldl
linux1.codesourcery.com% ./a.out
In main
In shared object
Back in main
Goodbye, world.
Segmentation fault
The reason is that when the main program exits we run the destructor
for the local static `t' in the shared object. But, the shared object
is already gone.
The IA64 C++ ABI (also the new g++ ABI) addresses this problem by
adding two new library entry points: `__cxa_atexit' and
`__cxa_finalize'. It is implied that these new entry points will
become a part of the C library; the require integration with `atexit'
and `exit'.
These patches make G++ use these facilities, under control of a new
switch (-fuse-cxa-atexit). I'll also submit GNU libc patches to the
appropriate list, but, in theory, these facilities could be used on
systems where the C library is not GNU libc, providing that it
supports __cxa_atexit/__cxa_finalize.
This message contains the patches to language-independent code. I'd
particularly like an expert's opinion on the crtstuff.c patch, even
though I've checked it in already. The next message will contain the
C++ front-end patches.
With these changes, the program does:
linux1.codesourcery.com% ./a.out
In main
In shared object
Back in main
Shared object going away...
Goodbye, world.
which is correct.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
1999-12-16 Mark Mitchell <mark@codesourcery.com>
* crtstuff.c (__dso_handle): Declare.
(__cxa_finalize): Likewise.
(do_global_dtors_aux): Call __cxa_finalize if __dso_handle is
non-NULL.
* invoke.texi: Document -fuse-cxa-atexit.
* tree.h (ptr_type_node): Document.
(const_ptr_type_node): Likewise.
Index: crtstuff.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/crtstuff.c,v
retrieving revision 1.20
diff -c -p -r1.20 crtstuff.c
*** crtstuff.c 1999/09/20 18:59:09 1.20
--- crtstuff.c 1999/12/17 06:36:26
*************** typedef void (*func_ptr) (void);
*** 129,134 ****
--- 129,147 ----
#ifdef OBJECT_FORMAT_ELF
+ /* Declare the __dso_handle variable. It should have a unique value
+ in every shared-object; in a main program its value is zero. */
+
+ #ifdef CRTSTUFFS_O
+ void *__dso_handle = &__dso_handle;
+ #else
+ void *__dso_handle = 0;
+ #endif
+
+ /* The __cxa_finalize function may not be available so we use only a
+ weak declaration. */
+ extern void __cxa_finalize (void *) TARGET_ATTRIBUTE_WEAK;
+
/* Run all the global destructors on exit from the program. */
/* Some systems place the number of pointers in the first word of the
*************** __do_global_dtors_aux (void)
*** 158,163 ****
--- 171,179 ----
if (completed)
return;
+
+ if (__dso_handle && __cxa_finalize)
+ __cxa_finalize (__dso_handle);
while (*p)
{
Index: invoke.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/invoke.texi,v
retrieving revision 1.163
diff -c -p -r1.163 invoke.texi
*** invoke.texi 1999/12/10 21:00:33 1.163
--- invoke.texi 1999/12/17 06:36:32
*************** in the following sections.
*** 109,115 ****
-fhonor-std -fhuge-objects -fno-implicit-templates -finit-priority
-fno-implement-inlines -fname-mangling-version-@var{n} -fno-default-inline
-foperator-names -fno-optional-diags -fpermissive -frepo -fstrict-prototype
! -fsquangle -ftemplate-depth-@var{n} -fvtable-thunks
-nostdinc++ -Wctor-dtor-privacy -Wno-deprecated -Weffc++
-Wno-non-template-friend
-Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual
--- 109,115 ----
-fhonor-std -fhuge-objects -fno-implicit-templates -finit-priority
-fno-implement-inlines -fname-mangling-version-@var{n} -fno-default-inline
-foperator-names -fno-optional-diags -fpermissive -frepo -fstrict-prototype
! -fsquangle -ftemplate-depth-@var{n} -fuse-cxa-atexit -fvtable-thunks
-nostdinc++ -Wctor-dtor-privacy -Wno-deprecated -Weffc++
-Wno-non-template-friend
-Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual
*************** Set the maximum instantiation depth for
*** 1216,1221 ****
--- 1216,1228 ----
A limit on the template instantiation depth is needed to detect
endless recursions during template class instantiation. ANSI/ISO C++
conforming programs must not rely on a maximum depth greater than 17.
+
+ @item -fuse-cxa-atexit
+ Register destructors for objects with static storage duration with the
+ @code{__cxa_atexit} function rather than the @code{atexit} function.
+ This option is required for fully standards-compliant handling of static
+ destructors, but will only work if your C library supports
+ @code{__cxa_atexit}.
@item -fvtable-thunks
Use @samp{thunks} to implement the virtual function dispatch table
Index: tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.108
diff -c -p -r1.108 tree.h
*** tree.h 1999/12/05 17:53:14 1.108
--- tree.h 1999/12/17 06:36:34
*************** extern tree global_trees[TI_MAX];
*** 1539,1545 ****
--- 1539,1547 ----
#define complex_long_double_type_node global_trees[TI_COMPLEX_LONG_DOUBLE_TYPE]
#define void_type_node global_trees[TI_VOID_TYPE]
+ /* The C type `void *'. */
#define ptr_type_node global_trees[TI_PTR_TYPE]
+ /* The C type `const void *'. */
#define const_ptr_type_node global_trees[TI_CONST_PTR_TYPE]
#define ptrdiff_type_node global_trees[TI_PTRDIFF_TYPE]
#define va_list_type_node global_trees[TI_VA_LIST_TYPE]