OSDN Git Service

* libgcc2.c (__do_global_ctors): Call atexit with one arg.
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index cd65676..a27caa3 100644 (file)
@@ -1,6 +1,6 @@
 /* More subroutines needed by GCC output code on some machines.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1989, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -31,6 +31,17 @@ Boston, MA 02111-1307, USA.  */
    do not apply.  */
 
 #include "tconfig.h"
+
+/* We disable this when inhibit_libc, so that gcc can still be built without
+   needing header files first.  */
+/* ??? This is not a good solution, since prototypes may be required in
+   some cases for correct code.  See also frame.c.  */
+#ifndef inhibit_libc
+/* fixproto guarantees these system headers exist. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
 #include "machmode.h"
 #include "defaults.h" 
 #ifndef L_trampoline
@@ -42,10 +53,6 @@ Boston, MA 02111-1307, USA.  */
 #undef abort
 #endif
 
-#if (SUPPORTS_WEAK == 1) && (defined (ASM_OUTPUT_DEF) || defined (ASM_OUTPUT_WEAK_ALIAS))
-#define WEAK_ALIAS
-#endif
-
 /* In a cross-compilation situation, default to inhibiting compilation
    of routines that use libc.  */
 
@@ -61,6 +68,10 @@ Boston, MA 02111-1307, USA.  */
 #define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
 #endif
 
+#ifndef LIBGCC2_LONG_DOUBLE_TYPE_SIZE
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE LONG_DOUBLE_TYPE_SIZE
+#endif
+
 /* In the first part of this file, we are interfacing to calls generated
    by the compiler itself.  These calls pass values into these routines
    which have very specific modes (rather than very specific types), and
@@ -79,10 +90,10 @@ typedef unsigned int UDItype        __attribute__ ((mode (DI)));
 typedef        float SFtype    __attribute__ ((mode (SF)));
 typedef                float DFtype    __attribute__ ((mode (DF)));
 
-#if LONG_DOUBLE_TYPE_SIZE == 96
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 typedef                float XFtype    __attribute__ ((mode (XF)));
 #endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 typedef                float TFtype    __attribute__ ((mode (TF)));
 #endif
 
@@ -133,10 +144,10 @@ typedef union
 
 extern DItype __fixunssfdi (SFtype a);
 extern DItype __fixunsdfdi (DFtype a);
-#if LONG_DOUBLE_TYPE_SIZE == 96
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 extern DItype __fixunsxfdi (XFtype a);
 #endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 extern DItype __fixunstfdi (TFtype a);
 #endif
 \f
@@ -391,8 +402,13 @@ __udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
 #else
 /* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
 USItype
-__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
-{}
+__udiv_w_sdiv (USItype *rp __attribute__ ((__unused__)),
+              USItype a1 __attribute__ ((__unused__)),
+              USItype a0 __attribute__ ((__unused__)),
+              USItype d __attribute__ ((__unused__)))
+{
+  return 0;
+}
 #endif
 #endif
 \f
@@ -752,7 +768,7 @@ __ucmpdi2 (DItype a, DItype b)
 }
 #endif
 \f
-#if defined(L_fixunstfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
@@ -784,7 +800,7 @@ __fixunstfdi (TFtype a)
 }
 #endif
 
-#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
 DItype
 __fixtfdi (TFtype a)
 {
@@ -794,7 +810,7 @@ __fixtfdi (TFtype a)
 }
 #endif
 
-#if defined(L_fixunsxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
@@ -826,7 +842,7 @@ __fixunsxfdi (XFtype a)
 }
 #endif
 
-#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
 DItype
 __fixxfdi (XFtype a)
 {
@@ -924,7 +940,7 @@ __fixsfdi (SFtype a)
 }
 #endif
 
-#if defined(L_floatdixf) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
@@ -933,21 +949,17 @@ XFtype
 __floatdixf (DItype u)
 {
   XFtype d;
-  SItype negate = 0;
-
-  if (u < 0)
-    u = -u, negate = 1;
 
-  d = (USItype) (u >> WORD_SIZE);
+  d = (SItype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
   d += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
-#if defined(L_floatditf) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
@@ -956,17 +968,13 @@ TFtype
 __floatditf (DItype u)
 {
   TFtype d;
-  SItype negate = 0;
-
-  if (u < 0)
-    u = -u, negate = 1;
 
-  d = (USItype) (u >> WORD_SIZE);
+  d = (SItype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
   d += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
@@ -979,17 +987,13 @@ DFtype
 __floatdidf (DItype u)
 {
   DFtype d;
-  SItype negate = 0;
 
-  if (u < 0)
-    u = -u, negate = 1;
-
-  d = (USItype) (u >> WORD_SIZE);
+  d = (SItype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
   d += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
@@ -1034,10 +1038,6 @@ __floatdisf (DItype u)
      so that we don't lose any of the precision of the high word
      while multiplying it.  */
   DFtype f;
-  SItype negate = 0;
-
-  if (u < 0)
-    u = -u, negate = 1;
 
   /* Protect against double-rounding error.
      Represent any low-order bits, that might be truncated in DFmode,
@@ -1049,22 +1049,23 @@ __floatdisf (DItype u)
       && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
     {
 #define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
-      if (u >= ((UDItype) 1 << DF_SIZE))
+      if (! (- ((DItype) 1 << DF_SIZE) < u
+            && u < ((DItype) 1 << DF_SIZE)))
        {
          if ((USItype) u & (REP_BIT - 1))
            u |= REP_BIT;
        }
     }
-  f = (USItype) (u >> WORD_SIZE);
+  f = (SItype) (u >> WORD_SIZE);
   f *= HIGH_HALFWORD_COEFF;
   f *= HIGH_HALFWORD_COEFF;
   f += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (SFtype) (negate ? -f : f);
+  return (SFtype) f;
 }
 #endif
 
-#if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
+#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 /* Reenable the normal types, in case limits.h needs them.  */
 #undef char
 #undef short
@@ -1402,9 +1403,12 @@ __builtin_saveregs ()
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
 #include <stdio.h>
 /* This is used by the `assert' macro.  */
+extern void __eprintf (const char *, const char *, unsigned int, const char *)
+  __attribute__ ((__noreturn__));
+
 void
 __eprintf (const char *string, const char *expression,
-          int line, const char *filename)
+          unsigned int line, const char *filename)
 {
   fprintf (stderr, string, expression, line, filename);
   fflush (stderr);
@@ -1497,10 +1501,6 @@ __bb_exit_func (void)
          if ((da_file = fopen (ptr->filename, "r")) != 0)
            {
              long n_counts = 0;
-             unsigned char tmp;
-             int i;
-             int ret = 0;
-
              
              if (__read_long (&n_counts, da_file, 8) != 0)
                {
@@ -1516,9 +1516,6 @@ __bb_exit_func (void)
                  for (i = 0; i < n_counts; i++)
                    {
                      long v = 0;
-                     unsigned char tmp;
-                     int j;
-                     int ret = 0;
 
                      if (__read_long (&v, da_file, 8) != 0)
                        {
@@ -1708,11 +1705,9 @@ __bb_init_func (struct bb *blocks)
   if (blocks->zero_word)
     return;
 
-#ifdef ON_EXIT
   /* Initialize destructor.  */
   if (!bb_head)
-    ON_EXIT (__bb_exit_func, 0);
-#endif
+    atexit (__bb_exit_func);
 
   /* Set up linked list.  */
   blocks->zero_word = 1;
@@ -1883,7 +1878,6 @@ __bb_exit_trace_func ()
 {
   FILE *file = fopen ("bb.out", "a");
   struct bb_func *f;
-  struct bb_edge *e;
   struct bb *b;
         
   if (!file)
@@ -1918,7 +1912,7 @@ __bb_exit_trace_func ()
         {
           for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
             {
-              if (!ptr->filename || p->filename != (char *) 0 && strcmp (p->filename, ptr->filename))
+              if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
                 continue;
               for (blk = 0; blk < ptr->ncounts; blk++)
                 {
@@ -2019,7 +2013,7 @@ found:        ;
                for ( ; bucket; bucket = bucket->next )
                  {
                    fprintf (file, "Jump from block 0x%.*lx to "
-                                  "block 0x%.*lx executed %*d time(s)\n", 
+                                  "block 0x%.*lx executed %*lu time(s)\n", 
                             addr_len, bucket->src_addr, 
                             addr_len, bucket->dst_addr, 
                             cnt_len, bucket->count);
@@ -2077,17 +2071,15 @@ found:        ;
 static void
 __bb_init_prg ()
 {
-
   FILE *file;
   char buf[BBINBUFSIZE];
   const char *p;
   const char *pos;
   enum bb_func_mode m;
+  int i;
 
-#ifdef ON_EXIT
   /* Initialize destructor.  */
-  ON_EXIT (__bb_exit_func, 0);
-#endif
+  atexit (__bb_exit_func);
 
   if (!(file = fopen ("bb.in", "r")))
     return;
@@ -2119,7 +2111,7 @@ __bb_init_prg ()
             {
               unsigned long l;
               f->next = bb_func_head;
-              if (pos = strchr (p, ':'))
+              if ((pos = strchr (p, ':')))
                 {
                   if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
                     continue;
@@ -2164,7 +2156,10 @@ __bb_init_prg ()
       bb_hashbuckets = (struct bb_edge **) 
                    malloc (BB_BUCKETS * sizeof (struct bb_edge *));
       if (bb_hashbuckets)
-        bzero ((char *) bb_hashbuckets, BB_BUCKETS);
+       /* Use a loop here rather than calling bzero to avoid having to
+          conditionalize its existance.  */
+       for (i = 0; i < BB_BUCKETS; i++)
+         bb_hashbuckets[i] = 0;
     }
 
   if (bb_mode & 12)
@@ -2173,11 +2168,8 @@ __bb_init_prg ()
       bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
     }
 
-#ifdef ON_EXIT
-      /* Initialize destructor.  */
-      ON_EXIT (__bb_exit_trace_func, 0);
-#endif
-
+  /* Initialize destructor.  */
+  atexit (__bb_exit_trace_func);
 }
 
 /* Called upon entering a basic block.  */
@@ -2576,7 +2568,7 @@ __clear_cache (char *beg, char *end)
 
 /* Jump to a trampoline, loading the static chain address.  */
 
-#if defined(WINNT) && ! defined(__CYGWIN32__)
+#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
 
 long getpagesize()
 {
@@ -2615,7 +2607,7 @@ mprotect (char *addr, int len, int prot)
     return -1;
 }
 
-#endif
+#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
 
 #ifdef TRANSFER_FROM_TRAMPOLINE 
 TRANSFER_FROM_TRAMPOLINE 
@@ -2717,6 +2709,51 @@ __enable_execute_stack ()
 
 #endif /* __sysV88__ */
 
+#ifdef __sysV68__
+
+#include <sys/signal.h>
+#include <errno.h>
+
+/* Motorola forgot to put memctl.o in the libp version of libc881.a,
+   so define it here, because we need it in __clear_insn_cache below */
+/* On older versions of this OS, no memctl or MCT_TEXT are defined;
+   hence we enable this stuff only if MCT_TEXT is #define'd.  */
+
+#ifdef MCT_TEXT
+asm("\n\
+       global memctl\n\
+memctl:\n\
+       movq &75,%d0\n\
+       trap &0\n\
+       bcc.b noerror\n\
+       jmp cerror%\n\
+noerror:\n\
+       movq &0,%d0\n\
+       rts");
+#endif
+
+/* Clear instruction cache so we can call trampolines on stack.
+   This is called from FINALIZE_TRAMPOLINE in mot3300.h.  */
+
+void
+__clear_insn_cache ()
+{
+#ifdef MCT_TEXT
+  int save_errno;
+
+  /* Preserve errno, because users would be surprised to have
+  errno changing without explicitly calling any system-call. */
+  save_errno = errno;
+
+  /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache. 
+     No need to use an address derived from _start or %sp, as 0 works also. */
+  memctl(0, 4096, MCT_TEXT);
+  errno = save_errno;
+#endif
+}
+
+#endif /* __sysV68__ */
+
 #ifdef __pyr__
 
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
@@ -2769,6 +2806,7 @@ cacheflush (char *beg, int size, int flag)
 #endif /* sony_news */
 #endif /* L_trampoline */
 \f
+#ifndef __CYGWIN__
 #ifdef L__main
 
 #include "gbl-ctors.h"
@@ -2787,6 +2825,15 @@ cacheflush (char *beg, int size, int flag)
 #endif
 
 #if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
+
+/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
+   code to run constructors.  In that case, we need to handle EH here, too.  */
+
+#ifdef EH_FRAME_SECTION
+#include "frame.h"
+extern unsigned char __EH_FRAME_BEGIN__[];
+#endif
+
 /* Run all the global destructors on exit from the program.  */
 
 void
@@ -2802,28 +2849,26 @@ __do_global_dtors ()
       (*(p-1)) ();
     }
 #endif
+#ifdef EH_FRAME_SECTION
+  __deregister_frame_info (__EH_FRAME_BEGIN__);
+#endif
 }
 #endif
 
 #ifndef HAS_INIT_SECTION
 /* Run all the global constructors on entry to the program.  */
 
-#ifndef ON_EXIT
-#define ON_EXIT(a, b)
-#else
-/* Make sure the exit routine is pulled in to define the globals as
-   bss symbols, just in case the linker does not automatically pull
-   bss definitions from the library.  */
-
-extern int _exit_dummy_decl;
-int *_exit_dummy_ref = &_exit_dummy_decl;
-#endif /* ON_EXIT */
-
 void
 __do_global_ctors ()
 {
+#ifdef EH_FRAME_SECTION
+  {
+    static struct object object;
+    __register_frame_info (__EH_FRAME_BEGIN__, &object);
+  }
+#endif
   DO_GLOBAL_CTORS_BODY;
-  ON_EXIT (__do_global_dtors, 0);
+  atexit (__do_global_dtors);
 }
 #endif /* no HAS_INIT_SECTION */
 
@@ -2850,6 +2895,7 @@ SYMBOL__MAIN ()
 #endif /* no HAS_INIT_SECTION or INVOKE__main */
 
 #endif /* L__main */
+#endif /* __CYGWIN__ */
 \f
 #ifdef L_ctors
 
@@ -2861,10 +2907,15 @@ SYMBOL__MAIN ()
    the right values.  */
 
 /* We declare the lists here with two elements each,
-   so that they are valid empty lists if no other definition is loaded.  */
+   so that they are valid empty lists if no other definition is loaded.
+
+   If we are using the old "set" extensions to have the gnu linker
+   collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__
+   must be in the bss/common section.
+
+   Long term no port should use those extensions.  But many still do.  */
 #if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
-#if defined(__NeXT__) || defined(_AIX)
-/* After 2.3, try this definition on all systems.  */
+#if defined (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2)
 func_ptr __CTOR_LIST__[2] = {0, 0};
 func_ptr __DTOR_LIST__[2] = {0, 0};
 #else
@@ -2879,22 +2930,17 @@ func_ptr __DTOR_LIST__[2];
 #include "gbl-ctors.h"
 
 #ifdef NEED_ATEXIT
-# ifdef ON_EXIT
-#  undef ON_EXIT
-# endif
-int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
-#endif
 
-#ifndef ON_EXIT
+#ifndef HAVE_ON_EXIT
 
-#ifdef NEED_ATEXIT
 # include <errno.h>
 
 static func_ptr *atexit_chain = 0;
 static long atexit_chain_length = 0;
 static volatile long last_atexit_chain_slot = -1;
 
-int atexit (func_ptr func)
+int
+atexit (func_ptr func)
 {
   if (++last_atexit_chain_slot == atexit_chain_length)
     {
@@ -2916,22 +2962,13 @@ int atexit (func_ptr func)
   atexit_chain[last_atexit_chain_slot] = func;
   return (0);
 }
-#endif /* NEED_ATEXIT */
-
-/* If we have no known way of registering our own __do_global_dtors
-   routine so that it will be invoked at program exit time, then we
-   have to define our own exit routine which will get this to happen.  */
 
-extern void __do_global_dtors ();
-extern void __bb_exit_func ();
 extern void _cleanup ();
 extern void _exit () __attribute__ ((noreturn));
 
 void 
 exit (int status)
 {
-#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
-#ifdef NEED_ATEXIT
   if (atexit_chain)
     {
       for ( ; last_atexit_chain_slot-- >= 0; )
@@ -2942,13 +2979,6 @@ exit (int status)
       free (atexit_chain);
       atexit_chain = 0;
     }
-#else /* No NEED_ATEXIT */
-  __do_global_dtors ();
-#endif /* No NEED_ATEXIT */
-#endif
-#ifndef inhibit_libc
-  __bb_exit_func ();
-#endif
 #ifdef EXIT_BODY
   EXIT_BODY;
 #else
@@ -2957,9 +2987,17 @@ exit (int status)
   _exit (status);
 }
 
-#else
-int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
-#endif
+#else /* HAVE_ON_EXIT */
+
+/* Simple; we just need a wrapper for ON_EXIT.  */
+int
+atexit (func_ptr func)
+{
+  return ON_EXIT (func);
+}
+
+#endif /* HAVE_ON_EXIT */
+#endif /* NEED_ATEXIT */
 
 #endif /* L_exit */
 \f
@@ -2969,6 +3007,8 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
 
 /* Shared exception handling support routines.  */
 
+extern void __default_terminate (void) __attribute__ ((__noreturn__));
+
 void
 __default_terminate ()
 {
@@ -3000,18 +3040,13 @@ __empty ()
 {
 }
 \f
-/* EH context structure. */
 
-struct eh_context
-{
-  void **dynamic_handler_chain;
-  /* This is language dependent part of the eh context. */
-  void *info;
-};
-
-/* This is a safeguard for dynamic handler chain. */
+/* Include definitions of EH context and table layout */
 
-static void *top_elt[2];
+#include "eh-common.h"
+#ifndef inhibit_libc
+#include <stdio.h>
+#endif
 
 /* Allocate and return a new EH context structure. */
 
@@ -3020,15 +3055,26 @@ extern void __throw ();
 static void *
 new_eh_context ()
 {
-  struct eh_context *eh = (struct eh_context *) malloc (sizeof *eh);
-  if (! eh)
+  struct eh_full_context {
+    struct eh_context c;
+    void *top_elt[2];
+  } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
+
+  if (! ehfc)
     __terminate ();
 
-  memset (eh, 0, sizeof *eh);
+  memset (ehfc, 0, sizeof *ehfc);
 
-  eh->dynamic_handler_chain = top_elt;
+  ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
 
-  return eh;
+  /* This should optimize out entirely.  This should always be true,
+     but just in case it ever isn't, don't allow bogus code to be
+     generated.  */
+
+  if ((void*)(&ehfc->c) != (void*)ehfc)
+    __terminate ();
+
+  return &ehfc->c;
 }
 
 #if __GTHREADS
@@ -3095,7 +3141,11 @@ eh_context_initialize ()
 #if __GTHREADS
 
   static __gthread_once_t once = __GTHREAD_ONCE_INIT;
-  if (__gthread_once (&once, eh_threads_initialize) == -1)
+  /* Make sure that get_eh_context does not point to us anymore.
+     Some systems have dummy thread routines in their libc that
+     return a success (Solaris 2.6 for example). */
+  if (__gthread_once (&once, eh_threads_initialize) != 0
+      || get_eh_context == &eh_context_initialize)
     {
       /* Use static version of EH context. */
       get_eh_context = &eh_context_static;
@@ -3116,10 +3166,17 @@ eh_context_initialize ()
 static struct eh_context *
 eh_context_static ()
 {
-  static struct eh_context *eh;
-  if (! eh)
-    eh = new_eh_context ();
-  return eh;
+  static struct eh_context eh;
+  static int initialized;
+  static void *top_elt[2];
+
+  if (! initialized)
+    {
+      initialized = 1;
+      memset (&eh, 0, sizeof eh);
+      eh.dynamic_handler_chain = top_elt;
+    }
+  return &eh;
 }
 
 #if __GTHREADS
@@ -3169,6 +3226,8 @@ __get_dynamic_handler_chain ()
    dynamic handler chain, and use longjmp to transfer back to the associated
    handler.  */
 
+extern void __sjthrow (void) __attribute__ ((__noreturn__));
+
 void
 __sjthrow ()
 {
@@ -3221,7 +3280,7 @@ __sjthrow ()
   /* We must call terminate if we try and rethrow an exception, when
      there is no exception currently active and when there are no
      handlers left.  */
-  if (! eh->info || (*dhc) == top_elt)
+  if (! eh->info || (*dhc)[0] == 0)
     __terminate ();
     
   /* Find the jmpbuf associated with the top element of the dynamic
@@ -3245,12 +3304,13 @@ __sjthrow ()
    then throw.  This is used to skip the first handler, and transfer
    control to the next handler in the dynamic handler stack.  */
 
+extern void __sjpopnthrow (void) __attribute__ ((__noreturn__));
+
 void
 __sjpopnthrow ()
 {
   struct eh_context *eh = (*get_eh_context) ();
   void ***dhc = &eh->dynamic_handler_chain;
-  void *jmpbuf;
   void (*func)(void *, int);
   void *arg;
   void ***cleanup;
@@ -3302,6 +3362,26 @@ __sjpopnthrow ()
 \f
 /* Support code for all exception region-based exception handling.  */
 
+int
+__eh_rtime_match (void *rtime)
+{
+  void *info;
+  __eh_matcher matcher;
+  void *ret;
+
+  info = *(__get_eh_info ());
+  matcher = ((__eh_info *)info)->match_function;
+  if (! matcher)
+    {
+#ifndef inhibit_libc
+      fprintf (stderr, "Internal Compiler Bug: No runtime type matcher.");
+#endif
+      return 0;
+    }
+  ret = (*matcher) (info, rtime, (void *)0);
+  return (ret != NULL);
+}
+
 /* This value identifies the place from which an exception is being
    thrown.  */
 
@@ -3311,11 +3391,24 @@ EH_TABLE_LOOKUP
 
 #else
 
-typedef struct exception_table {
-  void *start;
-  void *end;
-  void *exception_handler;
-} exception_table;
+#ifdef DWARF2_UNWIND_INFO
+
+
+/* Return the table version of an exception descriptor */
+
+short 
+__get_eh_table_version (exception_descriptor *table) 
+{
+  return table->lang.version;
+}
+
+/* Return the originating table language of an exception descriptor */
+
+short 
+__get_eh_table_language (exception_descriptor *table)
+{
+  return table->lang.language;
+}
 
 /* This routine takes a PC and a pointer to the exception region TABLE for
    its translation unit, and returns the address of the exception handler
@@ -3326,7 +3419,7 @@ typedef struct exception_table {
    an inner block.  */
 
 static void *
-find_exception_handler (void *pc, exception_table *table)
+old_find_exception_handler (void *pc, old_exception_table *table)
 {
   if (table)
     {
@@ -3334,27 +3427,106 @@ find_exception_handler (void *pc, exception_table *table)
       int best = -1;
 
       /* We can't do a binary search because the table isn't guaranteed
-        to be sorted from function to function.  */
-      for (pos = 0; table[pos].exception_handler != (void *) -1; ++pos)
-       {
-         if (table[pos].start <= pc && table[pos].end > pc)
-           {
-             /* This can apply.  Make sure it is at least as small as
-                the previous best.  */
-             if (best == -1 || (table[pos].end <= table[best].end
-                                && table[pos].start >= table[best].start))
-               best = pos;
-           }
-         /* But it is sorted by starting PC within a function.  */
-         else if (best >= 0 && table[pos].start > pc)
-           break;
-       }
+         to be sorted from function to function.  */
+      for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
+        {
+          if (table[pos].start_region <= pc && table[pos].end_region > pc)
+            {
+              /* This can apply.  Make sure it is at least as small as
+                 the previous best.  */
+              if (best == -1 || (table[pos].end_region <= table[best].end_region
+                        && table[pos].start_region >= table[best].start_region))
+                best = pos;
+            }
+          /* But it is sorted by starting PC within a function.  */
+          else if (best >= 0 && table[pos].start_region > pc)
+            break;
+        }
       if (best != -1)
-       return table[best].exception_handler;
+        return table[best].exception_handler;
     }
 
   return (void *) 0;
 }
+
+/* find_exception_handler finds the correct handler, if there is one, to
+   handle an exception.
+   returns a pointer to the handler which controlled should be transferred
+   to, or NULL if there is nothing left.
+   Parameters:
+   PC - pc where the exception originates. If this is a rethrow, 
+        then this starts out as a pointer to the exception table
+       entry we wish to rethrow out of.
+   TABLE - exception table for the current module.
+   EH_INFO - eh info pointer for this exception.
+   RETHROW - 1 if this is a rethrow. (see incoming value of PC).
+   CLEANUP - returned flag indicating whether this is a cleanup handler.
+*/
+static void *
+find_exception_handler (void *pc, exception_descriptor *table, 
+                        __eh_info *eh_info, int rethrow, int *cleanup)
+{
+
+  void *retval = NULL;
+  *cleanup = 1;
+  if (table)
+    {
+      int pos = 0;
+      /* The new model assumed the table is sorted inner-most out so the
+         first region we find which matches is the correct one */
+
+      exception_table *tab = &(table->table[0]);
+
+      /* Subtract 1 from the PC to avoid hitting the next region */
+      if (rethrow) 
+        {
+          /* pc is actually the region table entry to rethrow out of */
+          pos = ((exception_table *) pc) - tab;
+          pc = ((exception_table *) pc)->end_region - 1;
+
+          /* The label is always on the LAST handler entry for a region, 
+             so we know the next entry is a different region, even if the
+             addresses are the same. Make sure its not end of table tho. */
+          if (tab[pos].start_region != (void *) -1)
+            pos++;
+        }
+      else
+        pc--;
+      
+      /* We can't do a binary search because the table is in inner-most
+         to outermost address ranges within functions */
+      for ( ; tab[pos].start_region != (void *) -1; pos++)
+        { 
+          if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
+            {
+              if (tab[pos].match_info)
+                {
+                  __eh_matcher matcher = eh_info->match_function;
+                  /* match info but no matcher is NOT a match */
+                  if (matcher) 
+                    {
+                      void *ret = (*matcher)((void *) eh_info, 
+                                             tab[pos].match_info, table);
+                      if (ret) 
+                        {
+                          if (retval == NULL)
+                            retval = tab[pos].exception_handler;
+                          *cleanup = 0;
+                          break;
+                        }
+                    }
+                }
+              else
+                {
+                  if (retval == NULL)
+                    retval = tab[pos].exception_handler;
+                }
+            }
+        }
+    }
+  return retval;
+}
+#endif /* DWARF2_UNWIND_INFO */
 #endif /* EH_TABLE_LOOKUP */
 \f
 #ifdef DWARF2_UNWIND_INFO
@@ -3369,31 +3541,71 @@ find_exception_handler (void *pc, exception_table *table)
 
 typedef int ptr_type __attribute__ ((mode (pointer)));
 
-/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+#ifdef INCOMING_REGNO
+/* Is the saved value for register REG in frame UDATA stored in a register
+   window in the previous frame?  */
+
+/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT.  This allows us
+   to use the macro here.  One wonders, though, that perhaps TARGET_FLAT
+   compiled functions won't work with the frame-unwind stuff here.  
+   Perhaps the entireity of in_reg_window should be conditional on having
+   seen a DW_CFA_GNU_window_save?  */
+#define target_flags 0
+
+static int
+in_reg_window (int reg, frame_state *udata)
+{
+  if (udata->saved[reg] == REG_SAVED_REG)
+    return INCOMING_REGNO (reg) == reg;
+  if (udata->saved[reg] != REG_SAVED_OFFSET)
+    return 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+  return udata->reg_or_offset[reg] > 0;
+#else
+  return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#else
+static inline int in_reg_window (int reg, frame_state *udata) { return 0; }
+#endif /* INCOMING_REGNO */
+
+/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
    frame called by UDATA or 0.  */
 
-static void*
-get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+static word_type *
+get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
 {
+  while (udata->saved[reg] == REG_SAVED_REG)
+    {
+      reg = udata->reg_or_offset[reg];
+      if (in_reg_window (reg, udata))
+       {
+          udata = sub_udata;
+         sub_udata = NULL;
+       }
+    }
   if (udata->saved[reg] == REG_SAVED_OFFSET)
-    return (void *)(ptr_type)
-      *(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
-  else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
-    return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
+    return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
   else
     abort ();
 }
 
+/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+   frame called by UDATA or 0.  */
+
+static inline void *
+get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+{
+  return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
+}
+
 /* Overwrite the saved value for register REG in frame UDATA with VAL.  */
 
-static void
+static inline void
 put_reg (unsigned reg, void *val, frame_state *udata)
 {
-  if (udata->saved[reg] == REG_SAVED_OFFSET)
-    *(word_type *)(udata->cfa + udata->reg_or_offset[reg])
-      = (word_type)(ptr_type) val;
-  else
-    abort ();
+  *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
 }
 
 /* Copy the saved value for register REG from frame UDATA to frame
@@ -3403,17 +3615,13 @@ put_reg (unsigned reg, void *val, frame_state *udata)
 static void
 copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
 {
-  if (udata->saved[reg] == REG_SAVED_OFFSET
-      && target_udata->saved[reg] == REG_SAVED_OFFSET)
-    memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
-           udata->cfa + udata->reg_or_offset[reg],
-           __builtin_dwarf_reg_size (reg));
-  else
-    abort ();
+  word_type *preg = get_reg_addr (reg, udata, NULL);
+  word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
+
+  memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));
 }
 
-/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
-   frame called by UDATA or 0.  */
+/* Retrieve the return address for frame UDATA.  */
 
 static inline void *
 get_return_addr (frame_state *udata, frame_state *sub_udata)
@@ -3453,75 +3661,55 @@ next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
   return caller_udata;
 }
 
-#ifdef INCOMING_REGNO
-/* Is the saved value for register REG in frame UDATA stored in a register
-   window in the previous frame?  */
-
-static int
-in_reg_window (int reg, frame_state *udata)
+/* Hook to call before __terminate if only cleanup handlers remain. */
+void 
+__unwinding_cleanup ()
 {
-  if (udata->saved[reg] != REG_SAVED_OFFSET)
-    return 0;
-
-#ifdef STACK_GROWS_DOWNWARD
-  return udata->reg_or_offset[reg] > 0;
-#else
-  return udata->reg_or_offset[reg] < 0;
-#endif
 }
-#endif /* INCOMING_REGNO */
 
-/* We first search for an exception handler, and if we don't find
-   it, we call __terminate on the current stack frame so that we may
-   use the debugger to walk the stack and understand why no handler
-   was found.
+/* throw_helper performs some of the common grunt work for a throw. This
+   routine is called by throw and rethrows. This is pretty much split 
+   out from the old __throw routine. An addition has been added which allows
+   for a dummy call to a routine __unwinding_cleanup() when there are nothing
+   but cleanups remaining. This allows a debugger to examine the state
+   at which the throw was executed, before any cleanups, rather than
+   at the terminate point after the stack has been unwound.
 
-   If we find one, then we unwind the frames down to the one that
-   has the handler and transfer control into the handler.  */
+   EH is the current eh_context structure.
+   PC is the address of the call to __throw.
+   MY_UDATA is the unwind information for __throw.
+   OFFSET_P is where we return the SP adjustment offset.  */
 
-void
-__throw ()
-{
-  struct eh_context *eh = (*get_eh_context) ();
-  void *saved_pc, *pc, *handler, *retaddr;
-  frame_state ustruct, ustruct2;
-  frame_state *udata = &ustruct;
-  frame_state *sub_udata = &ustruct2;
-  frame_state my_ustruct, *my_udata = &my_ustruct;
+static void *
+throw_helper (eh, pc, my_udata, offset_p)
+     struct eh_context *eh;
+     void *pc;
+     frame_state *my_udata;
+     long *offset_p;
+{
+  frame_state ustruct2, *udata = &ustruct2;
+  frame_state ustruct;
+  frame_state *sub_udata = &ustruct;
+  void *saved_pc = pc;
+  void *handler;
+  void *handler_p;
+  void *pc_p;
+  frame_state saved_ustruct;
+  int new_eh_model;
+  int cleanup = 0;
+  int only_cleanup = 0;
+  int rethrow = 0;
+  int saved_state = 0;
   long args_size;
+  __eh_info *eh_info = (__eh_info *)eh->info;
 
-  /* This is required for C++ semantics.  We must call terminate if we
-     try and rethrow an exception, when there is no exception currently
-     active.  */
-  if (! eh->info)
-    __terminate ();
-    
-  /* Start at our stack frame.  */
-label:
-  udata = __frame_state_for (&&label, udata);
-  if (! udata)
-    __terminate ();
-
-  /* We need to get the value from the CFA register.  At this point in
-     compiling __throw we don't know whether or not we will use the frame
-     pointer register for the CFA, so we check our unwind info.  */
-  if (udata->cfa_reg == __builtin_dwarf_fp_regnum ())
-    udata->cfa = __builtin_fp ();
-  else
-    udata->cfa = __builtin_sp ();
-  udata->cfa += udata->cfa_offset;
-
-  memcpy (my_udata, udata, sizeof (*udata));
+  /* Do we find a handler based on a re-throw PC? */
+  if (eh->table_index != (void *) 0)
+    rethrow = 1;
 
-  /* Do any necessary initialization to access arbitrary stack frames.
-     On the SPARC, this means flushing the register windows.  */
-  __builtin_unwind_init ();
+  memcpy (udata, my_udata, sizeof (*udata));
 
-  /* Now reset pc to the right throw point.  */
-  pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
-  saved_pc = pc;
-
-  handler = 0;
+  handler = (void *) 0;
   for (;;)
     { 
       frame_state *p = udata;
@@ -3532,13 +3720,47 @@ label:
       if (! udata)
        break;
 
-      handler = find_exception_handler (pc, udata->eh_ptr);
+      if (udata->eh_ptr == NULL)
+        new_eh_model = 0;
+      else
+        new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
+                                          runtime_id_field == NEW_EH_RUNTIME);
 
-      /* If we found one, we can stop searching.  */
+      if (rethrow) 
+        {
+          rethrow = 0;
+          handler = find_exception_handler (eh->table_index, udata->eh_ptr, 
+                                          eh_info, 1, &cleanup);
+          eh->table_index = (void *)0;
+        }
+      else
+        if (new_eh_model)
+          handler = find_exception_handler (pc, udata->eh_ptr, eh_info, 
+                                            0, &cleanup);
+        else
+          handler = old_find_exception_handler (pc, udata->eh_ptr);
+
+      /* If we found one, we can stop searching, if its not a cleanup. 
+         for cleanups, we save the state, and keep looking. This allows
+         us to call a debug hook if there are nothing but cleanups left. */
       if (handler)
        {
-         args_size = udata->args_size;
-         break;
+         if (cleanup)
+           {
+             if (!saved_state)
+               {
+                 saved_ustruct = *udata;
+                 handler_p = handler;
+                 pc_p = pc;
+                 saved_state = 1;
+                 only_cleanup = 1;
+               }
+           }
+         else
+           {
+             only_cleanup = 0;
+             break;
+           }
        }
 
       /* Otherwise, we continue searching.  We subtract 1 from PC to avoid
@@ -3546,10 +3768,23 @@ label:
       pc = get_return_addr (udata, sub_udata) - 1;
     }
 
+  if (saved_state) 
+    {
+      udata = &saved_ustruct;
+      handler = handler_p;
+      pc = pc_p;
+      if (only_cleanup)
+        __unwinding_cleanup ();
+    }
+
   /* If we haven't found a handler by now, this is an unhandled
      exception.  */
-  if (! handler)
-    __terminate ();
+  if (! handler) 
+    __terminate();
+
+  eh->handler_label = handler;
+
+  args_size = udata->args_size;
 
   if (pc == saved_pc)
     /* We found a handler in the throw context, no need to unwind.  */
@@ -3557,7 +3792,6 @@ label:
   else
     {
       int i;
-      void *val;
 
       /* Unwind all the frames between this one and the handler by copying
         their saved register values into our register save slots.  */
@@ -3578,7 +3812,6 @@ label:
          for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
            if (i != udata->retaddr_column && udata->saved[i])
              {
-#ifdef INCOMING_REGNO
                /* If you modify the saved value of the return address
                   register on the SPARC, you modify the return address for
                   your caller's frame.  Don't do that here, as it will
@@ -3587,14 +3820,12 @@ label:
                    && udata->saved[udata->retaddr_column] == REG_SAVED_REG
                    && udata->reg_or_offset[udata->retaddr_column] == i)
                  continue;
-#endif
                copy_reg (i, udata, my_udata);
              }
 
          pc = get_return_addr (udata, sub_udata) - 1;
        }
 
-#ifdef INCOMING_REGNO
       /* But we do need to update the saved return address register from
         the last frame we unwind, or the handler frame will have the wrong
         return address.  */
@@ -3604,29 +3835,123 @@ label:
          if (in_reg_window (i, udata))
            copy_reg (i, udata, my_udata);
        }
-#endif
     }
   /* udata now refers to the frame called by the handler frame.  */
 
-  /* Emit the stub to adjust sp and jump to the handler.  */
-  retaddr = __builtin_eh_stub ();
-
-  /* And then set our return address to point to the stub.  */
-  if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
-    put_return_addr (retaddr, my_udata);
-  else
-    __builtin_set_return_addr_reg (retaddr);
-
-  /* Set up the registers we use to communicate with the stub.
-     We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack.  */
-  __builtin_set_eh_regs (handler,
+  /* We adjust SP by the difference between __throw's CFA and the CFA for
+     the frame called by the handler frame, because those CFAs correspond
+     to the SP values at the two call sites.  We need to further adjust by
+     the args_size of the handler frame itself to get the handler frame's
+     SP from before the args were pushed for that call.  */
 #ifdef STACK_GROWS_DOWNWARD
-                        udata->cfa - my_udata->cfa
+  *offset_p = udata->cfa - my_udata->cfa + args_size;
 #else
-                        my_udata->cfa - udata->cfa
+  *offset_p = my_udata->cfa - udata->cfa - args_size;
 #endif
-                        + args_size
-                        );
+                      
+  return handler;
+}
+
+
+/* We first search for an exception handler, and if we don't find
+   it, we call __terminate on the current stack frame so that we may
+   use the debugger to walk the stack and understand why no handler
+   was found.
+
+   If we find one, then we unwind the frames down to the one that
+   has the handler and transfer control into the handler.  */
+
+/*extern void __throw(void) __attribute__ ((__noreturn__));*/
+
+void
+__throw ()
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void *pc, *handler;
+  long offset;
+
+  /* XXX maybe make my_ustruct static so we don't have to look it up for
+     each throw.  */
+  frame_state my_ustruct, *my_udata = &my_ustruct;
+
+  /* This is required for C++ semantics.  We must call terminate if we
+     try and rethrow an exception, when there is no exception currently
+     active.  */
+  if (! eh->info)
+    __terminate ();
+    
+  /* Start at our stack frame.  */
+label:
+  my_udata = __frame_state_for (&&label, my_udata);
+  if (! my_udata)
+    __terminate ();
+
+  /* We need to get the value from the CFA register. */
+  my_udata->cfa = __builtin_dwarf_cfa ();
+
+  /* Do any necessary initialization to access arbitrary stack frames.
+     On the SPARC, this means flushing the register windows.  */
+  __builtin_unwind_init ();
+
+  /* Now reset pc to the right throw point.  */
+  pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+  handler = throw_helper (eh, pc, my_udata, &offset);
+
+  /* Now go!  */
+
+  __builtin_eh_return ((void *)eh, offset, handler);
+
+  /* Epilogue:  restore the handler frame's register values and return
+     to the stub.  */
+}
+
+/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
+
+void
+__rethrow (index)
+     void *index;
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void *pc, *handler;
+  long offset;
+
+  /* XXX maybe make my_ustruct static so we don't have to look it up for
+     each throw.  */
+  frame_state my_ustruct, *my_udata = &my_ustruct;
+
+  /* This is required for C++ semantics.  We must call terminate if we
+     try and rethrow an exception, when there is no exception currently
+     active.  */
+  if (! eh->info)
+    __terminate ();
+
+  /* This is the table index we want to rethrow from. The value of
+     the END_REGION label is used for the PC of the throw, and the
+     search begins with the next table entry. */
+  eh->table_index = index;
+    
+  /* Start at our stack frame.  */
+label:
+  my_udata = __frame_state_for (&&label, my_udata);
+  if (! my_udata)
+    __terminate ();
+
+  /* We need to get the value from the CFA register. */
+  my_udata->cfa = __builtin_dwarf_cfa ();
+
+  /* Do any necessary initialization to access arbitrary stack frames.
+     On the SPARC, this means flushing the register windows.  */
+  __builtin_unwind_init ();
+
+  /* Now reset pc to the right throw point.  */
+  pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+  handler = throw_helper (eh, pc, my_udata, &offset);
+
+  /* Now go!  */
+
+  __builtin_eh_return ((void *)eh, offset, handler);
 
   /* Epilogue:  restore the handler frame's register values and return
      to the stub.  */
@@ -3656,6 +3981,6 @@ __pure_virtual ()
 #ifndef inhibit_libc
   write (2, MESSAGE, sizeof (MESSAGE) - 1);
 #endif
-  _exit (-1);
+  __terminate ();
 }
 #endif