OSDN Git Service

(__udiv_w_sdiv): If we don't have sdiv_qrnnd, define dummy variant of
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index a37e66f..3d9637c 100644 (file)
@@ -1,6 +1,6 @@
 /* More subroutines needed by GCC output code on some machines.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* As a special exception, if you link this library with other files,
    some of which are compiled with GCC, to produce an executable,
@@ -31,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "tconfig.h"
 #include "machmode.h"
+#include "defaults.h" 
 #ifndef L_trampoline
 #include <stddef.h>
 #endif
@@ -40,6 +42,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #undef abort
 #endif
 
+#if (SUPPORTS_WEAK == 1) && defined (ASM_OUTPUT_DEF)
+#define WEAK_ALIAS
+#endif
+
+/* Permit the tm.h file to select the endianness to use just for this
+   file.  This is used when the endianness is determined when the
+   compiler is run.  */
+
+#ifndef LIBGCC2_WORDS_BIG_ENDIAN
+#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
+#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
@@ -49,29 +63,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    because the sizes for those types can be configured to be anything.
    Instead we use the following special type names.  */
 
-typedef unsigned int UQItype   __attribute__ ((mode ("QI")));
-typedef         int SItype     __attribute__ ((mode ("SI")));
-typedef unsigned int USItype   __attribute__ ((mode ("SI")));
-typedef                 int DItype     __attribute__ ((mode ("DI")));
-typedef unsigned int UDItype   __attribute__ ((mode ("DI")));
-typedef        float SFtype    __attribute__ ((mode ("SF")));
-typedef                float DFtype    __attribute__ ((mode ("DF")));
+typedef unsigned int UQItype   __attribute__ ((mode (QI)));
+typedef         int SItype     __attribute__ ((mode (SI)));
+typedef unsigned int USItype   __attribute__ ((mode (SI)));
+typedef                 int DItype     __attribute__ ((mode (DI)));
+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
-typedef                float XFtype    __attribute__ ((mode ("XF")));
+typedef                float XFtype    __attribute__ ((mode (XF)));
 #endif
 #if LONG_DOUBLE_TYPE_SIZE == 128
-typedef                float TFtype    __attribute__ ((mode ("TF")));
+typedef                float TFtype    __attribute__ ((mode (TF)));
 #endif
 
-#if BITS_PER_WORD==16
-typedef int word_type __attribute__ ((mode ("HI")));
-#endif
-#if BITS_PER_WORD==32
-typedef int word_type __attribute__ ((mode ("SI")));
-#endif
-#if BITS_PER_WORD==64
-typedef int word_type __attribute__ ((mode ("DI")));
-#endif
+typedef int word_type __attribute__ ((mode (__word__)));
 
 /* Make sure that we don't accidentally use any normal C language built-in
    type names in the first part of this file.  Instead we want to use *only*
@@ -90,9 +98,9 @@ typedef int word_type __attribute__ ((mode ("DI")));
 #define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 
 /* DIstructs are pairs of SItype values in the order determined by
-   WORDS_BIG_ENDIAN.  */
+   LIBGCC2_WORDS_BIG_ENDIAN.  */
 
-#if WORDS_BIG_ENDIAN
+#if LIBGCC2_WORDS_BIG_ENDIAN
   struct DIstruct {SItype high, low;};
 #else
   struct DIstruct {SItype low, high;};
@@ -108,7 +116,9 @@ typedef union
   DItype ll;
 } DIunion;
 
-#if defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)
+#if (defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)\
+     || defined (L_divdi3) || defined (L_udivdi3) \
+     || defined (L_moddi3) || defined (L_umoddi3))
 
 #include "longlong.h"
 
@@ -143,46 +153,14 @@ __negdi2 (u)
 }
 #endif
 \f
-#ifdef L_lshldi3
-DItype
-__lshldi3 (u, b)
-     DItype u;
-     SItype b;
-{
-  DIunion w;
-  SItype bm;
-  DIunion uu;
-
-  if (b == 0)
-    return u;
-
-  uu.ll = u;
-
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
-  if (bm <= 0)
-    {
-      w.s.low = 0;
-      w.s.high = (USItype)uu.s.low << -bm;
-    }
-  else
-    {
-      USItype carries = (USItype)uu.s.low >> bm;
-      w.s.low = (USItype)uu.s.low << b;
-      w.s.high = ((USItype)uu.s.high << b) | carries;
-    }
-
-  return w.ll;
-}
-#endif
-
 #ifdef L_lshrdi3
 DItype
 __lshrdi3 (u, b)
      DItype u;
-     SItype b;
+     word_type b;
 {
   DIunion w;
-  SItype bm;
+  word_type bm;
   DIunion uu;
 
   if (b == 0)
@@ -211,10 +189,10 @@ __lshrdi3 (u, b)
 DItype
 __ashldi3 (u, b)
      DItype u;
-     SItype b;
+     word_type b;
 {
   DIunion w;
-  SItype bm;
+  word_type bm;
   DIunion uu;
 
   if (b == 0)
@@ -243,10 +221,10 @@ __ashldi3 (u, b)
 DItype
 __ashrdi3 (u, b)
      DItype u;
-     SItype b;
+     word_type b;
 {
   DIunion w;
-  SItype bm;
+  word_type bm;
   DIunion uu;
 
   if (b == 0)
@@ -313,6 +291,7 @@ __muldi3 (u, v)
 #endif
 \f
 #ifdef L_udiv_w_sdiv
+#if defined (sdiv_qrnnd)
 USItype
 __udiv_w_sdiv (rp, a1, a0, d)
      USItype *rp, a1, a0, d;
@@ -410,8 +389,20 @@ __udiv_w_sdiv (rp, a1, a0, d)
   *rp = r;
   return q;
 }
+#else
+/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
+USItype
+__udiv_w_sdiv (rp, a1, a0, d)
+     USItype *rp, a1, a0, d;
+{}
+#endif
 #endif
 \f
+#if (defined (L_udivdi3) || defined (L_divdi3) || \
+     defined (L_umoddi3) || defined (L_moddi3))
+#define L_udivmoddi4
+#endif
+
 #ifdef L_udivmoddi4
 static const UQItype __clz_tab[] =
 {
@@ -425,6 +416,10 @@ static const UQItype __clz_tab[] =
   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
 };
 
+#if (defined (L_udivdi3) || defined (L_divdi3) || \
+     defined (L_umoddi3) || defined (L_moddi3))
+static inline
+#endif
 UDItype
 __udivmoddi4 (n, d, rp)
      UDItype n, d;
@@ -652,7 +647,7 @@ DItype
 __divdi3 (u, v)
      DItype u, v;
 {
-  SItype c = 0;
+  word_type c = 0;
   DIunion uu, vv;
   DItype w;
 
@@ -680,7 +675,7 @@ DItype
 __moddi3 (u, v)
      DItype u, v;
 {
-  SItype c = 0;
+  word_type c = 0;
   DIunion uu, vv;
   DItype w;
 
@@ -707,7 +702,7 @@ UDItype
 __umoddi3 (u, v)
      UDItype u, v;
 {
-  DItype w;
+  UDItype w;
 
   (void) __udivmoddi4 (u, v, &w);
 
@@ -1021,6 +1016,35 @@ __floatdidf (u)
 #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)
+#define DI_SIZE (sizeof (DItype) * BITS_PER_UNIT)
+
+/* Define codes for all the float formats that we know of.  Note
+   that this is copied from real.h.  */
+   
+#define UNKNOWN_FLOAT_FORMAT 0
+#define IEEE_FLOAT_FORMAT 1
+#define VAX_FLOAT_FORMAT 2
+#define IBM_FLOAT_FORMAT 3
+
+/* Default to IEEE float if not specified.  Nearly all machines use it.  */
+#ifndef HOST_FLOAT_FORMAT
+#define        HOST_FLOAT_FORMAT       IEEE_FLOAT_FORMAT
+#endif
+
+#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+#define DF_SIZE 53
+#define SF_SIZE 24
+#endif
+
+#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#endif
+
+#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#endif
 
 SFtype
 __floatdisf (u)
@@ -1035,6 +1059,22 @@ __floatdisf (u)
   if (u < 0)
     u = -u, negate = 1;
 
+  /* Protect against double-rounding error.
+     Represent any low-order bits, that might be truncated in DFmode,
+     by a bit that won't be lost.  The bit can go in anywhere below the
+     rounding position of the SFmode.  A fixed mask and bit position
+     handles all usual configurations.  It doesn't handle the case
+     of 128-bit DImode, however.  */
+  if (DF_SIZE < DI_SIZE
+      && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
+    {
+#define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
+      if (u >= ((UDItype) 1 << DF_SIZE))
+       {
+         if ((USItype) u & (REP_BIT - 1))
+           u |= REP_BIT;
+       }
+    }
   f = (USItype) (u >> WORD_SIZE);
   f *= HIGH_HALFWORD_COEFF;
   f *= HIGH_HALFWORD_COEFF;
@@ -1045,7 +1085,15 @@ __floatdisf (u)
 #endif
 
 #if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
-#include "glimits.h"
+/* Reenable the normal types, in case limits.h needs them.  */
+#undef char
+#undef short
+#undef int
+#undef long
+#undef unsigned
+#undef float
+#undef double
+#include <limits.h>
 
 USItype
 __fixunsxfsi (a)
@@ -1058,7 +1106,15 @@ __fixunsxfsi (a)
 #endif
 
 #ifdef L_fixunsdfsi
-#include "glimits.h"
+/* Reenable the normal types, in case limits.h needs them.  */
+#undef char
+#undef short
+#undef int
+#undef long
+#undef unsigned
+#undef float
+#undef double
+#include <limits.h>
 
 USItype
 __fixunsdfsi (a)
@@ -1071,7 +1127,15 @@ __fixunsdfsi (a)
 #endif
 
 #ifdef L_fixunssfsi
-#include "glimits.h"
+/* Reenable the normal types, in case limits.h needs them.  */
+#undef char
+#undef short
+#undef int
+#undef long
+#undef unsigned
+#undef float
+#undef double
+#include <limits.h>
 
 USItype
 __fixunssfsi (SFtype a)
@@ -1102,7 +1166,7 @@ __fixunssfsi (SFtype a)
 #ifdef L__gcc_bcmp
 
 /* Like bcmp except the sign is meaningful.
-   Reult is negative if S1 is less than S2,
+   Result is negative if S1 is less than S2,
    positive if S1 is greater, 0 if S1 and S2 are equal.  */
 
 int
@@ -1388,14 +1452,19 @@ BLOCK_PROFILER_CODE
 #ifndef inhibit_libc
 
 /* Simple minded basic block profiling output dumper for
-   systems that don't provde tcov support.  At present,
+   systems that don't provide tcov support.  At present,
    it requires atexit and stdio.  */
 
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
 #include <stdio.h>
+char *ctime ();
 
 #ifdef HAVE_ATEXIT
+#ifdef WINNT
+extern int atexit (void (*) (void));
+#else
 extern void atexit (void (*) (void));
+#endif
 #define ON_EXIT(FUNC,ARG) atexit ((FUNC))
 #else
 #ifdef sun
@@ -1404,7 +1473,7 @@ extern void on_exit (void*, void*);
 #endif
 #endif
 
-static struct bb *bb_head = (struct bb *)0;
+static struct bb *bb_head;
 
 /* Return the number of digits needed to print a value */
 /* __inline__ */ static int num_digits (long value, int base)
@@ -1570,11 +1639,20 @@ __bb_init_func (struct bb *blocks)
 
 typedef void (*vfp)(void);
 extern vfp __new_handler;
+extern void __default_new_handler (void);
 
+#ifdef WEAK_ALIAS
+void * __builtin_new (size_t sz)
+     __attribute__ ((weak, alias ("___builtin_new")));
+void *
+___builtin_new (size_t sz)
+#else
 void *
 __builtin_new (size_t sz)
+#endif
 {
   void *p;
+  vfp handler = (__new_handler) ? __new_handler : __default_new_handler;
 
   /* malloc (0) is unpredictable; avoid it.  */
   if (sz == 0)
@@ -1582,7 +1660,7 @@ __builtin_new (size_t sz)
   p = (void *) malloc (sz);
   while (p == 0)
     {
-      (*__new_handler) ();
+      (*handler) ();
       p = (void *) malloc (sz);
     }
   
@@ -1596,8 +1674,15 @@ __builtin_new (size_t sz)
 
 extern void * __builtin_new (size_t);
 
+#ifdef WEAK_ALIAS
+void * __builtin_vec_new (size_t sz)
+     __attribute__ ((weak, alias ("___builtin_vec_new")));
+void *
+___builtin_vec_new (size_t sz)
+#else
 void *
 __builtin_vec_new (size_t sz)
+#endif
 {
   return __builtin_new (sz);
 }
@@ -1623,7 +1708,7 @@ __builtin_vec_new (size_t sz)
 typedef void (*vfp)(void);
 void __default_new_handler (void);
 
-vfp __new_handler = __default_new_handler;
+vfp __new_handler = (vfp)0;
 
 vfp
 set_new_handler (vfp handler)
@@ -1641,10 +1726,12 @@ set_new_handler (vfp handler)
 void
 __default_new_handler ()
 {
+#ifndef inhibit_libc
   /* don't use fprintf (stderr, ...) because it may need to call malloc.  */
   /* This should really print the name of the program, but that is hard to
      do.  We need a standard, clean way to get at the name.  */
   write (2, MESSAGE, sizeof (MESSAGE));
+#endif
   /* don't call exit () because that may call global destructors which
      may cause a loop.  */
   _exit (-1);
@@ -1656,8 +1743,15 @@ __default_new_handler ()
    by C++ programs to return to the free store a block of memory allocated
    as a single object. */
 
+#ifdef WEAK_ALIAS
+void __builtin_delete (void *ptr)
+     __attribute__ ((weak, alias ("___builtin_delete")));
+void
+___builtin_delete (void *ptr)
+#else
 void
 __builtin_delete (void *ptr)
+#endif
 {
   if (ptr)
     free (ptr);
@@ -1671,8 +1765,15 @@ __builtin_delete (void *ptr)
 
 extern void __builtin_delete (void *);
 
+#ifdef WEAK_ALIAS
+void __builtin_vec_delete (void *ptr)
+     __attribute__ ((weak, alias ("___builtin_vec_delete")));
+void
+___builtin_vec_delete (void *ptr)
+#else
 void
 __builtin_vec_delete (void *ptr)
+#endif
 {
   __builtin_delete (ptr);
 }
@@ -1707,7 +1808,7 @@ __clear_cache (beg, end)
 #else
 #ifdef INSN_CACHE_SIZE
   static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
-  static int initialized = 0;
+  static int initialized;
   int offset;
   void *start_addr
   void *end_addr;
@@ -1946,12 +2047,13 @@ __enable_execute_stack ()
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
    give the same symbol without quotes for an alternative entry point.  You
-   must define both, or niether. */
+   must define both, or neither. */
 #ifndef NAME__MAIN
 #define NAME__MAIN "__main"
 #define SYMBOL__MAIN __main
 #endif
 
+#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
 /* Run all the global destructors on exit from the program.  */
 
 void
@@ -1960,23 +2062,12 @@ __do_global_dtors ()
 #ifdef DO_GLOBAL_DTORS_BODY
   DO_GLOBAL_DTORS_BODY;
 #else
-  unsigned nptrs = (unsigned HOST_WIDE_INT) __DTOR_LIST__[0];
-  unsigned i;
-
-  /* Some systems place the number of pointers
-     in the first word of the table.
-     On other systems, that word is -1.
-     In all cases, the table is null-terminated.  */
-
-  /* If the length is not recorded, count up to the null.  */
-  if (nptrs == -1)
-    for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++);
-
-  /* GNU LD format.  */
-  for (i = nptrs; i >= 1; i--)
-    __DTOR_LIST__[i] ();
+  func_ptr *p;
+  for (p = __DTOR_LIST__ + 1; *p; )
+    (*p++) ();
 #endif
 }
+#endif
 
 #ifndef INIT_SECTION_ASM_OP
 /* Run all the global constructors on entry to the program.  */
@@ -2013,7 +2104,7 @@ void
 SYMBOL__MAIN ()
 {
   /* Support recursive calls to `main': run initializers just once.  */
-  static int initialized = 0;
+  static int initialized;
   if (! initialized)
     {
       initialized = 1;
@@ -2065,7 +2156,9 @@ void
 exit (status)
      int status;
 {
+#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
   __do_global_dtors ();
+#endif
 #ifdef EXIT_BODY
   EXIT_BODY;
 #else
@@ -2080,37 +2173,245 @@ int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
 
 #endif /* L_exit */
 \f
-/* In a.out systems, we need to have these dummy constructor and destructor
-   lists in the library.
-
-   When using `collect', the first link will resolve __CTOR_LIST__
-   and __DTOR_LIST__ to these symbols.  We will then run "nm" on the
-   result, build the correct __CTOR_LIST__ and __DTOR_LIST__, and relink.
-   Since we don't do the second link if no constructors existed, these
-   dummies must be fully functional empty lists.
-
-   When using `gnu ld', these symbols will be used if there are no
-   constructors.  If there are constructors, the N_SETV symbol defined
-   by the linker from the N_SETT's in input files will define __CTOR_LIST__
-   and __DTOR_LIST__ rather than its being allocated as common storage
-   by the definitions below.
-
-   When using a linker that supports constructor and destructor segments,
-   these definitions will not be used, since crtbegin.o and crtend.o
-   (from crtstuff.c) will have already defined __CTOR_LIST__ and
-    __DTOR_LIST__.  The crt*.o files are passed directly to the linker
-   on its command line, by gcc.  */
-
-/* The list needs two elements:  one is ignored (the old count); the
-   second is the terminating zero.  Since both values are zero, this
-   declaration is not initialized, and it becomes `common'.  */
-
-#ifdef L_ctor_list
-#include "gbl-ctors.h"
-func_ptr __CTOR_LIST__[2];
+#ifdef L_eh
+typedef struct {
+  void *start;
+  void *end;
+  void *exception_handler;
+} exception_table;
+
+struct exception_table_node {
+  exception_table *table;
+  void *start;
+  void *end;
+  struct exception_table_node *next;
+};
+
+static int except_table_pos;
+static void *except_pc;
+static struct exception_table_node *exception_table_list;
+
+static exception_table *
+find_exception_table (pc)
+     void* pc;
+{
+  register struct exception_table_node *table = exception_table_list;
+  for ( ; table != 0; table = table->next)
+    {
+      if (table->start <= pc && table->end > pc)
+       return table->table;
+    }
+  return 0;
+}
+
+/* this routine takes a pc, and the address of the exception handler associated
+   with the closest exception table handler entry associated with that PC,
+   or 0 if there are no table entries the PC fits in.  The algorithm works
+   something like this:
+
+    while(current_entry exists) {
+        if(current_entry.start < pc )
+            current_entry = next_entry;
+        else {
+            if(prev_entry.start <= pc && prev_entry.end > pc) {
+                save pointer to prev_entry;
+                return prev_entry.exception_handler;
+             }
+            else return 0;
+         }
+     }
+    return 0;
+
+   Assuming a correctly sorted table (ascending order) this routine should
+   return the tightest match...
+
+   In the advent of a tie, we have to give the last entry, as it represents
+   an inner block.
+ */
+
+
+void *
+__find_first_exception_table_match(pc)
+void *pc;
+{
+  exception_table *table = find_exception_table (pc);
+  int pos = 0;
+  int best = 0;
+  if (table == 0)
+    return (void*)0;
+#if 0
+  printf("find_first_exception_table_match(): pc = %x!\n",pc);
+#endif
+
+  except_pc = pc;
+
+#if 0
+  /* We can't do this yet, as we don't know that the table is sorted.  */
+  do {
+    ++pos;
+    if (table[pos].start > except_pc)
+      /* found the first table[pos].start > except_pc, so the previous
+        entry better be the one we want! */
+      break;
+  } while(table[pos].exception_handler != (void*)-1);
+
+  --pos;
+  if (table[pos].start <= except_pc && table[pos].end > except_pc)
+    {
+      except_table_pos = pos;
+#if 0
+      printf("find_first_eh_table_match(): found match: %x\n",table[pos].exception_handler);
 #endif
+      return table[pos].exception_handler;
+    }
+#else
+  while (table[++pos].exception_handler != (void*)-1) {
+    if (table[pos].start <= except_pc && table[pos].end > except_pc)
+      {
+       /* This can apply.  Make sure it is better or as good as the previous
+          best.  */
+       /* The best one ends first. */
+       if (best == 0 || (table[pos].end <= table[best].end
+                         /* The best one starts last.  */
+                         && table[pos].start >= table[best].start))
+         best = pos;
+      }
+  }
+  if (best != 0)
+    return table[best].exception_handler;
+#endif
+
+#if 0
+  printf("find_first_eh_table_match(): else: returning NULL!\n");
+#endif
+  return (void*)0;
+}
 
-#ifdef L_dtor_list
-#include "gbl-ctors.h"
-func_ptr __DTOR_LIST__[2];
+void *
+__throw_type_match (void *catch_type, void *throw_type, void* obj)
+{
+#if 0
+ printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
+       catch_type, throw_type);
+#endif
+ if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
+   return obj;
+ return 0;
+}
+
+void
+__register_exceptions (exception_table *table)
+{
+  struct exception_table_node *node;
+  exception_table *range = table + 1;
+
+  if (range->start == (void*)-1)
+    return;
+
+  node = (struct exception_table_node*)
+    malloc (sizeof (struct exception_table_node));
+  node->table = table;
+
+  /* This look can be optimized away either if the table
+     is sorted, or if we pass in extra parameters. */
+  node->start = range->start;
+  node->end = range->end;
+  for (range++ ; range->start != (void*)(-1); range++)
+    {
+      if (range->start < node->start)
+       node->start = range->start;
+      if (range->end > node->end)
+       node->end = range->end;
+    }
+
+  node->next = exception_table_list;
+  exception_table_list = node;
+}
+
+#if #machine(i386)
+void
+__unwind_function(void *ptr)
+{
+  asm("movl 8(%esp),%ecx");
+  /* Undo current frame */
+  asm("movl %ebp,%esp");
+  asm("popl %ebp");
+  /* like ret, but stay here */
+  asm("addl $4,%esp");
+  
+  /* Now, undo previous frame. */
+  /* This is a test routine, as we have to dynamically probe to find out
+     what to pop for certain, this is just a guess. */
+  asm("leal -16(%ebp),%esp");
+  asm("pop %eax"); /* really for popl %ebx */
+  asm("pop %eax"); /* really for popl %esi */
+  asm("pop %eax"); /* really for popl %edi */
+  asm("movl %ebp,%esp");
+  asm("popl %ebp");
+
+  asm("movl %ecx,0(%esp)");
+  asm("ret");
+}
+#endif
+
+#if #machine(rs6000)
+__unwind_function(void *ptr)
+{
+  asm("mr 31,1");
+  asm("l 1,0(1)");
+  asm("l 31,-4(1)");
+  asm("# br");
+
+  asm("mr 31,1");
+  asm("l 1,0(1)");
+  /* use 31 as a scratch register to restore the link register. */
+  asm("l 31, 8(1);mtlr 31 # l lr,8(1)");
+  asm("l 31,-4(1)");
+  asm("# br");
+  asm("mtctr 3;bctr # b 3");
+}
+#endif /* rs6000 */
+
+#if #machine(powerpc)
+__unwind_function(void *ptr)
+{
+  asm("mr 31,1");
+  asm("lwz 1,0(1)");
+  asm("lwz 31,-4(1)");
+  asm("# br");
+
+  asm("mr 31,1");
+  asm("lwz 1,0(1)");
+  /* use 31 as a scratch register to restore the link register. */
+  asm("lwz 31, 8(1);mtlr 31 # l lr,8(1)");
+  asm("lwz 31,-4(1)");
+  asm("# br");
+  asm("mtctr 3;bctr # b 3");
+}
+#endif /* powerpc */
+#endif /* L_eh */
+\f
+#ifdef L_pure
+#ifndef inhibit_libc
+/* This gets us __GNU_LIBRARY__.  */
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
+
+#ifdef __GNU_LIBRARY__
+  /* Avoid forcing the library's meaning of `write' on the user program
+     by using the "internal" name (for use within the library)  */
+#define write(fd, buf, n)      __write((fd), (buf), (n))
+#endif
+#endif /* inhibit_libc */
+
+#define MESSAGE "pure virtual method called\n"
+
+void
+__pure_virtual ()
+{
+#ifndef inhibit_libc
+  write (2, MESSAGE, sizeof (MESSAGE) - 1);
+#endif
+  _exit (-1);
+}
 #endif