OSDN Git Service

Shared library support.
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index f600297..44b4de5 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 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -18,9 +18,10 @@ 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.  */
 
-/* As a special exception, if you link this library with files
-   compiled with GCC to produce an executable, this does not cause
-   the resulting executable to be covered by the GNU General Public License.
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
    This exception does not however invalidate any other reasons why
    the executable file might be covered by the GNU General Public License.  */
 
@@ -31,7 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tconfig.h"
 #include "machmode.h"
 #ifndef L_trampoline
-#include "gstddef.h"
+#include <stddef.h>
 #endif
 
 /* Don't use `fancy_abort' here even if config.h says to use it.  */
@@ -39,6 +40,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #undef abort
 #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
@@ -55,13 +64,23 @@ 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 0
+#if LONG_DOUBLE_TYPE_SIZE == 96
 typedef                float XFtype    __attribute__ ((mode (XF)));
 #endif
 #if LONG_DOUBLE_TYPE_SIZE == 128
 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
+
 /* 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*
    the type names defined above.  The following macro definitions insure
@@ -79,9 +98,9 @@ typedef               float TFtype    __attribute__ ((mode (TF)));
 #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;};
@@ -105,6 +124,12 @@ typedef union
 
 extern DItype __fixunssfdi (SFtype a);
 extern DItype __fixunsdfdi (DFtype a);
+#if LONG_DOUBLE_TYPE_SIZE == 96
+extern DItype __fixunsxfdi (XFtype a);
+#endif
+#if LONG_DOUBLE_TYPE_SIZE == 128
+extern DItype __fixunstfdi (TFtype a);
+#endif
 \f
 #if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
 #if defined (L_divdi3) || defined (L_moddi3)
@@ -630,6 +655,7 @@ __udivmoddi4 (n, d, rp)
 
 #ifdef L_divdi3
 UDItype __udivmoddi4 ();
+
 DItype
 __divdi3 (u, v)
      DItype u, v;
@@ -689,7 +715,7 @@ UDItype
 __umoddi3 (u, v)
      UDItype u, v;
 {
-  DItype w;
+  UDItype w;
 
   (void) __udivmoddi4 (u, v, &w);
 
@@ -708,7 +734,7 @@ __udivdi3 (n, d)
 #endif
 \f
 #ifdef L_cmpdi2
-SItype
+word_type
 __cmpdi2 (a, b)
      DItype a, b;
 {
@@ -729,7 +755,7 @@ __cmpdi2 (a, b)
 #endif
 
 #ifdef L_ucmpdi2
-SItype
+word_type
 __ucmpdi2 (a, b)
      DItype a, b;
 {
@@ -793,6 +819,50 @@ __fixtfdi (a)
 }
 #endif
 
+#if defined(L_fixunsxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+
+DItype
+__fixunsxfdi (a)
+     XFtype a;
+{
+  XFtype b;
+  UDItype v;
+
+  if (a < 0)
+    return 0;
+
+  /* Compute high word of result, as a flonum.  */
+  b = (a / HIGH_WORD_COEFF);
+  /* Convert that to fixed (but not to DItype!),
+     and shift it into the high word.  */
+  v = (USItype) b;
+  v <<= WORD_SIZE;
+  /* Remove high part from the XFtype, leaving the low part as flonum.  */
+  a -= (XFtype)v;
+  /* Convert that to fixed (but not to DItype!) and add it in.
+     Sometimes A comes out negative.  This is significant, since
+     A has more bits than a long int does.  */
+  if (a < 0)
+    v -= (USItype) (- a);
+  else
+    v += (USItype) a;
+  return v;
+}
+#endif
+
+#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+DItype
+__fixxfdi (a)
+     XFtype a;
+{
+  if (a < 0)
+    return - __fixunsxfdi (-a);
+  return __fixunsxfdi (a);
+}
+#endif
+
 #ifdef L_fixunsdfdi
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
@@ -883,6 +953,30 @@ __fixsfdi (SFtype a)
 }
 #endif
 
+#if defined(L_floatdixf) && (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)
+
+XFtype
+__floatdixf (u)
+     DItype u;
+{
+  XFtype d;
+  SItype negate = 0;
+
+  if (u < 0)
+    u = -u, negate = 1;
+
+  d = (USItype) (u >> WORD_SIZE);
+  d *= HIGH_HALFWORD_COEFF;
+  d *= HIGH_HALFWORD_COEFF;
+  d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+
+  return (negate ? -d : d);
+}
+#endif
+
 #if defined(L_floatditf) && (LONG_DOUBLE_TYPE_SIZE == 128)
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
@@ -935,23 +1029,74 @@ __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)
+#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+#define DF_SIZE 53
+#define SF_SIZE 24
+#else
+#if TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#else
+#if TARGET_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#else
+#define DF_SIZE 0
+#define SF_SIZE 0
+#endif
+#endif
+#endif
+
 
 SFtype
 __floatdisf (u)
      DItype u;
 {
-  SFtype f;
+  /* Do the calculation in DFmode
+     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,
+     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;
   f += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -f : f);
+  return (SFtype) (negate ? -f : f);
+}
+#endif
+
+#if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
+#include "glimits.h"
+
+USItype
+__fixunsxfsi (a)
+     XFtype a;
+{
+  if (a >= - (DFtype) LONG_MIN)
+    return (SItype) (a + LONG_MIN) - LONG_MIN;
+  return (SItype) a;
 }
 #endif
 
@@ -1087,7 +1232,74 @@ asm ("___builtin_saveregs:");
        asm ("  bri     %r1");          /* delayed return */
        asm ("  st.l    %r28,12(%r16)"); /* pointer to overflow args */
 
-#else /* not __SVR4__ */
+#else /* not __svr4__ */
+#if defined(__PARAGON__)
+       /*
+        *      we'll use SVR4-ish varargs but need SVR3.2 assembler syntax,
+        *      and we stand a better chance of hooking into libraries
+        *      compiled by PGI.  [andyp@ssd.intel.com]
+        */
+       asm ("  .text");
+       asm ("  .align  4");
+       asm (".globl    __builtin_saveregs");
+asm ("__builtin_saveregs:");
+       asm (".globl    ___builtin_saveregs");
+asm ("___builtin_saveregs:");
+
+        asm (" andnot  0x0f,sp,sp");   /* round down to 16-byte boundary */
+       asm ("  adds    -96,sp,sp");    /* allocate stack space for reg save
+                                          area and also for a new va_list
+                                          structure */
+       /* Save all argument registers in the arg reg save area.  The
+          arg reg save area must have the following layout (according
+          to the svr4 ABI):
+
+               struct {
+                 union  {
+                   float freg[8];
+                   double dreg[4];
+                 } float_regs;
+                 long  ireg[12];
+               };
+       */
+
+       asm ("  fst.q   f8,  0(sp)");
+       asm ("  fst.q   f12,16(sp)"); 
+       asm ("  st.l    r16,32(sp)");
+       asm ("  st.l    r17,36(sp)"); 
+       asm ("  st.l    r18,40(sp)");
+       asm ("  st.l    r19,44(sp)");
+       asm ("  st.l    r20,48(sp)");
+       asm ("  st.l    r21,52(sp)");
+       asm ("  st.l    r22,56(sp)");
+       asm ("  st.l    r23,60(sp)");
+       asm ("  st.l    r24,64(sp)");
+       asm ("  st.l    r25,68(sp)");
+       asm ("  st.l    r26,72(sp)");
+       asm ("  st.l    r27,76(sp)");
+
+       asm ("  adds    80,sp,r16");  /* compute the address of the new
+                                          va_list structure.  Put in into
+                                          r16 so that it will be returned
+                                          to the caller.  */
+
+       /* Initialize all fields of the new va_list structure.  This
+          structure looks like:
+
+               typedef struct {
+                   unsigned long       ireg_used;
+                   unsigned long       freg_used;
+                   long                *reg_base;
+                   long                *mem_ptr;
+               } va_list;
+       */
+
+       asm ("  st.l    r0, 0(r16)"); /* nfixed */
+       asm ("  st.l    r0, 4(r16)"); /* nfloating */
+       asm ("  st.l    sp, 8(r16)"); /* __va_ctl points to __va_struct.  */
+       asm ("  bri     r1");           /* delayed return */
+       asm ("   st.l   r28,12(r16)"); /* pointer to overflow args */
+#else /* not __PARAGON__ */
        asm ("  .text");
        asm ("  .align  4");
 
@@ -1125,7 +1337,8 @@ asm ("___builtin_saveregs:");
        asm ("  mov     r30,sp");
                                /* recover stack and pass address to start 
                                   of data.  */
-#endif /* not __SVR4__ */
+#endif /* not __PARAGON__ */
+#endif /* not __svr4__ */
 #else /* not __i860__ */
 #ifdef __sparc__
        asm (".global __builtin_saveregs");
@@ -1160,17 +1373,20 @@ asm ("___builtin_saveregs:");
   asm ("       j       $31");
   asm ("       .end __builtin_saveregs");
 #else /* not __mips__, etc. */
+
+void *
 __builtin_saveregs ()
 {
   abort ();
 }
+
 #endif /* not __mips__ */
 #endif /* not __sparc__ */
 #endif /* not __i860__ */
 #endif
 \f
 #ifdef L_eprintf
-#ifndef inhibit_eprintf
+#ifndef inhibit_libc
 
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
 #include <stdio.h>
@@ -1191,44 +1407,214 @@ __eprintf (string, expression, line, filename)
 #endif
 
 #ifdef L_bb
-/* Avoid warning from ranlib about empty object file.  */
-void
-__bb_avoid_warning ()
-{}
 
-#if defined (__sun__) && defined (__mc68000__)
+/* Structure emitted by -a  */
 struct bb
 {
-  int initialized;
-  char *filename;
-  int *counts;
-  int ncounts;
-  int zero_word;
-  int *addresses;
+  long zero_word;
+  const char *filename;
+  long *counts;
+  long ncounts;
+  struct bb *next;
+  const unsigned long *addresses;
+
+  /* Older GCC's did not emit these fields.  */
+  long nwords;
+  const char **functions;
+  const long *line_nums;
+  const char **filenames;
 };
 
-extern int ___tcov_init;
+#ifdef BLOCK_PROFILER_CODE
+BLOCK_PROFILER_CODE
+#else
+#ifndef inhibit_libc
+
+/* Simple minded basic block profiling output dumper for
+   systems that don't provde tcov support.  At present,
+   it requires atexit and stdio.  */
 
-__bb_init_func (blocks)
-       struct bb *blocks;
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
+char *ctime ();
+
+#ifdef HAVE_ATEXIT
+extern void atexit (void (*) (void));
+#define ON_EXIT(FUNC,ARG) atexit ((FUNC))
+#else
+#ifdef sun
+extern void on_exit (void*, void*);
+#define ON_EXIT(FUNC,ARG) on_exit ((FUNC), (ARG))
+#endif
+#endif
+
+static struct bb *bb_head = (struct bb *)0;
+
+/* Return the number of digits needed to print a value */
+/* __inline__ */ static int num_digits (long value, int base)
 {
-  if (! ___tcov_init)
-    ___tcov_init_func ();
+  int minus = (value < 0 && base != 16);
+  unsigned long v = (minus) ? -value : value;
+  int ret = minus;
+
+  do
+    {
+      v /= base;
+      ret++;
+    }
+  while (v);
 
-  ___bb_link (blocks->filename, blocks->counts, blocks->ncounts);
+  return ret;
 }
 
+void
+__bb_exit_func (void)
+{
+  FILE *file = fopen ("bb.out", "a");
+  long time_value;
+
+  if (!file)
+    perror ("bb.out");
+
+  else
+    {
+      struct bb *ptr;
+
+      /* This is somewhat type incorrect, but it avoids worrying about
+        exactly where time.h is included from.  It should be ok unless
+        a void * differs from other pointer formats, or if sizeof(long)
+        is < sizeof (time_t).  It would be nice if we could assume the
+        use of rationale standards here.  */
+
+      time((void *) &time_value);
+      fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
+
+      /* We check the length field explicitly in order to allow compatibility
+        with older GCC's which did not provide it.  */
+
+      for (ptr = bb_head; ptr != (struct bb *)0; ptr = ptr->next)
+       {
+         int i;
+         int func_p    = (ptr->nwords >= sizeof (struct bb) && ptr->nwords <= 1000);
+         int line_p    = (func_p && ptr->line_nums);
+         int file_p    = (func_p && ptr->filenames);
+         long ncounts  = ptr->ncounts;
+         long cnt_max  = 0;
+         long line_max = 0;
+         long addr_max = 0;
+         int file_len  = 0;
+         int func_len  = 0;
+         int blk_len   = num_digits (ncounts, 10);
+         int cnt_len;
+         int line_len;
+         int addr_len;
+
+         fprintf (file, "File %s, %ld basic blocks \n\n",
+                  ptr->filename, ncounts);
+
+         /* Get max values for each field.  */
+         for (i = 0; i < ncounts; i++)
+           {
+             const char *p;
+             int len;
+
+             if (cnt_max < ptr->counts[i])
+               cnt_max = ptr->counts[i];
+
+             if (addr_max < ptr->addresses[i])
+               addr_max = ptr->addresses[i];
+
+             if (line_p && line_max < ptr->line_nums[i])
+               line_max = ptr->line_nums[i];
+
+             if (func_p)
+               {
+                 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
+                 len = strlen (p);
+                 if (func_len < len)
+                   func_len = len;
+               }
+
+             if (file_p)
+               {
+                 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
+                 len = strlen (p);
+                 if (file_len < len)
+                   file_len = len;
+               }
+           }
+
+         addr_len = num_digits (addr_max, 16);
+         cnt_len  = num_digits (cnt_max, 10);
+         line_len = num_digits (line_max, 10);
+
+         /* Now print out the basic block information.  */
+         for (i = 0; i < ncounts; i++)
+           {
+             fprintf (file,
+                      "    Block #%*d: executed %*ld time(s) address= 0x%.*lx",
+                      blk_len, i+1,
+                      cnt_len, ptr->counts[i],
+                      addr_len, ptr->addresses[i]);
+
+             if (func_p)
+               fprintf (file, " function= %-*s", func_len,
+                        (ptr->functions[i]) ? ptr->functions[i] : "<none>");
+
+             if (line_p)
+               fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
+
+             if (file_p)
+               fprintf (file, " file= %s",
+                        (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
+
+             fprintf (file, "\n");
+           }
+
+         fprintf (file, "\n");
+         fflush (file);
+       }
+
+      fprintf (file, "\n\n");
+      fclose (file);
+    }
+}
+
+void
+__bb_init_func (struct bb *blocks)
+{
+  /* User is supposed to check whether the first word is non-0,
+     but just in case.... */
+
+  if (blocks->zero_word)
+    return;
+
+#ifdef ON_EXIT
+  /* Initialize destructor.  */
+  if (!bb_head)
+    ON_EXIT (__bb_exit_func, 0);
 #endif
-#endif
+
+  /* Set up linked list.  */
+  blocks->zero_word = 1;
+  blocks->next = bb_head;
+  bb_head = blocks;
+}
+
+#endif /* not inhibit_libc */
+#endif /* not BLOCK_PROFILER_CODE */
+#endif /* L_bb */
 \f
-/* frills for C++ */
+/* Default free-store management functions for C++, per sections 12.5 and
+   17.3.3 of the Working Paper. */
 
 #ifdef L_op_new
-typedef void (*vfp)(void);
+/* operator new (size_t), described in 17.3.3.5.  This function is used by
+   C++ programs to allocate a block of memory to hold a single object. */
 
+typedef void (*vfp)(void);
 extern vfp __new_handler;
 
-/* void * operator new (size_t sz) */
 void *
 __builtin_new (size_t sz)
 {
@@ -1238,14 +1624,35 @@ __builtin_new (size_t sz)
   if (sz == 0)
     sz = 1;
   p = (void *) malloc (sz);
-  if (p == 0)
-    (*__new_handler) ();
+  while (p == 0)
+    {
+      (*__new_handler) ();
+      p = (void *) malloc (sz);
+    }
+  
   return p;
 }
 #endif /* L_op_new */
 
+#ifdef L_op_vnew
+/* void * operator new [] (size_t), described in 17.3.3.6.  This function
+   is used by C++ programs to allocate a block of memory for an array.  */
+
+extern void * __builtin_new (size_t);
+
+void *
+__builtin_vec_new (size_t sz)
+{
+  return __builtin_new (sz);
+}
+#endif /* L_op_vnew */
+
 #ifdef L_new_handler
+/* set_new_handler (fvoid_t *) and the default new handler, described in
+   17.3.3.2 and 17.3.3.5.  These functions define the result of a failure
+   to allocate the amount of memory requested from operator new or new []. */
 
+#ifndef inhibit_libc
 /* This gets us __GNU_LIBRARY__.  */
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
 #include <stdio.h>
@@ -1255,37 +1662,28 @@ __builtin_new (size_t sz)
      by using the "internal" name (for use within the library)  */
 #define write(fd, buf, n)      __write((fd), (buf), (n))
 #endif
+#endif /* inhibit_libc */
 
 typedef void (*vfp)(void);
+void __default_new_handler (void);
 
-extern void *__builtin_new (size_t);
-static void default_new_handler (void);
-
-vfp __new_handler = default_new_handler;
+vfp __new_handler = __default_new_handler;
 
 vfp
-__set_new_handler (handler)
-     vfp handler;
+set_new_handler (vfp handler)
 {
   vfp prev_handler;
 
   prev_handler = __new_handler;
-  if (handler == 0) handler = default_new_handler;
+  if (handler == 0) handler = __default_new_handler;
   __new_handler = handler;
   return prev_handler;
 }
 
-vfp
-set_new_handler (handler)
-     vfp handler;
-{
-  return __set_new_handler (handler);
-}
-
 #define MESSAGE "Virtual memory exceeded in `new'\n"
 
-static void
-default_new_handler ()
+void
+__default_new_handler ()
 {
   /* 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
@@ -1298,7 +1696,10 @@ default_new_handler ()
 #endif
 
 #ifdef L_op_delete
-/* void operator delete (void *ptr) */
+/* operator delete (void *), described in 17.3.3.3.  This function is used
+   by C++ programs to return to the free store a block of memory allocated
+   as a single object. */
+
 void
 __builtin_delete (void *ptr)
 {
@@ -1306,6 +1707,22 @@ __builtin_delete (void *ptr)
     free (ptr);
 }
 #endif
+
+#ifdef L_op_vdel
+/* operator delete [] (void *), described in 17.3.3.4.  This function is
+   used by C++ programs to return to the free store a block of memory
+   allocated as an array. */
+
+extern void __builtin_delete (void *);
+
+void
+__builtin_vec_delete (void *ptr)
+{
+  __builtin_delete (ptr);
+}
+#endif
+
+/* End of C++ free-store management functions */
 \f
 #ifdef L_shtab
 unsigned int __shtab[] = {
@@ -1329,6 +1746,9 @@ void
 __clear_cache (beg, end)
      char *beg, *end;
 {
+#ifdef CLEAR_INSN_CACHE 
+  CLEAR_INSN_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;
@@ -1427,6 +1847,7 @@ __clear_cache (beg, end)
 #endif /* just one plane */
 #endif /* Cache is large */
 #endif /* Cache exists */
+#endif /* CLEAR_INSN_CACHE */
 }
 
 #endif /* L_clear_cache */
@@ -1439,6 +1860,43 @@ __clear_cache (beg, end)
 TRANSFER_FROM_TRAMPOLINE 
 #endif
 
+#if defined (NeXT) && defined (__MACH__)
+
+/* Make stack executable so we can call trampolines on stack.
+   This is called from INITIALIZE_TRAMPOLINE in next.h.  */
+#ifdef NeXTStep21
+ #include <mach.h>
+#else
+ #include <mach/mach.h>
+#endif
+
+void
+__enable_execute_stack (addr)
+     char *addr;
+{
+  kern_return_t r;
+  char *eaddr = addr + TRAMPOLINE_SIZE;
+  vm_address_t a = (vm_address_t) addr;
+
+  /* turn on execute access on stack */
+  r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
+  if (r != KERN_SUCCESS)
+    {
+      mach_error("vm_protect VM_PROT_ALL", r);
+      exit(1);
+    }
+
+  /* We inline the i-cache invalidation for speed */
+
+#ifdef CLEAR_INSN_CACHE
+  CLEAR_INSN_CACHE (addr, eaddr);
+#else
+  __clear_cache ((int) addr, (int) eaddr);
+#endif
+} 
+
+#endif /* defined (NeXT) && defined (__MACH__) */
+
 #ifdef __convex__
 
 /* Make stack executable so we can call trampolines on stack.
@@ -1467,6 +1925,38 @@ __enable_execute_stack ()
 }
 #endif /* __convex__ */
 
+#ifdef __DOLPHIN__
+
+/* Modified from the convex -code above. */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <sys/m88kbcs.h>
+
+void
+__enable_execute_stack ()
+{
+  int save_errno;
+  static unsigned long lowest = USRSTACK;
+  unsigned long current = (unsigned long) &save_errno & -NBPC;
+  
+  /* Ignore errno being set. memctl sets errno to EINVAL whenever the
+     address is seen as 'negative'. That is the case with the stack.   */
+
+  save_errno=errno;
+  if (lowest > current)
+    {
+      unsigned len=lowest-current;
+      memctl(current,len,MCT_TEXT);
+      lowest = current;
+    }
+  else
+    memctl(current,NBPC,MCT_TEXT);
+  errno=save_errno;
+}
+
+#endif /* __DOLPHIN__ */
+
 #ifdef __pyr__
 
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
@@ -1497,7 +1987,16 @@ __enable_execute_stack ()
 #ifdef L__main
 
 #include "gbl-ctors.h"
+/* 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. */
+#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
@@ -1506,23 +2005,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.  */
@@ -1556,7 +2044,7 @@ __do_global_ctors ()
    to run __do_global_ctors, so we need not do anything here.  */
 
 void
-__main ()
+SYMBOL__MAIN ()
 {
   /* Support recursive calls to `main': run initializers just once.  */
   static int initialized = 0;
@@ -1605,7 +2093,7 @@ func_ptr __DTOR_LIST__[2];
 
 extern void __do_global_dtors ();
 extern void _cleanup ();
-extern volatile void _exit ();
+extern void _exit () __attribute__ ((noreturn));
 
 void 
 exit (status)
@@ -1626,37 +2114,161 @@ 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 = 0;
+static void *except_pc = (void *)0;
+static struct exception_table_node *exception_table_list = 0;
+
+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 tighest 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
 
-#ifdef L_dtor_list
-#include "gbl-ctors.h"
-func_ptr __DTOR_LIST__[2];
+  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;
+}
+
+int
+__throw_type_match (const char *catch_type, const char *throw_type)
+{
+#if 0
+ printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
+       catch_type, throw_type);
+#endif
+ return strcmp (catch_type, throw_type);
+}
+
+void
+__register_exceptions (exception_table *table)
+{
+  struct exception_table_node *node = (struct exception_table_node*)
+      malloc (sizeof (struct exception_table_node));
+  exception_table *range = table + 1;
+  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;
+}
+#endif /* L_eh */
+\f
+#ifdef L_pure
+#define MESSAGE "pure virtual method called\n"
+void
+__pure_virtual ()
+{
+  write (2, MESSAGE, sizeof (MESSAGE) - 1);
+  _exit (-1);
+}
 #endif