#include "tconfig.h"
#include "tsystem.h"
#ifdef abort
#undef abort
#endif
#ifdef LIBCC_KEXT
#define abort() panic()
extern void panic (void);
#endif
#include "libgcc2.h"
#ifdef DECLARE_LIBRARY_RENAMES
DECLARE_LIBRARY_RENAMES
#endif
#if defined (L_negdi2)
DWtype
__negdi2 (DWtype u)
{
DWunion w;
DWunion uu;
uu.ll = u;
w.s.low = -uu.s.low;
w.s.high = -uu.s.high - ((UWtype) w.s.low > 0);
return w.ll;
}
#endif
#ifdef L_addvsi3
Wtype
__addvsi3 (Wtype a, Wtype b)
{
Wtype w;
w = a + b;
if (b >= 0 ? w < a : w > a)
abort ();
return w;
}
#endif
#ifdef L_addvdi3
DWtype
__addvdi3 (DWtype a, DWtype b)
{
DWtype w;
w = a + b;
if (b >= 0 ? w < a : w > a)
abort ();
return w;
}
#endif
#ifdef L_subvsi3
Wtype
__subvsi3 (Wtype a, Wtype b)
{
#ifdef L_addvsi3
return __addvsi3 (a, (-b));
#else
DWtype w;
w = a - b;
if (b >= 0 ? w > a : w < a)
abort ();
return w;
#endif
}
#endif
#ifdef L_subvdi3
DWtype
__subvdi3 (DWtype a, DWtype b)
{
#ifdef L_addvdi3
return (a, (-b));
#else
DWtype w;
w = a - b;
if (b >= 0 ? w > a : w < a)
abort ();
return w;
#endif
}
#endif
#ifdef L_mulvsi3
Wtype
__mulvsi3 (Wtype a, Wtype b)
{
DWtype w;
w = a * b;
if (((a >= 0) == (b >= 0)) ? w < 0 : w > 0)
abort ();
return w;
}
#endif
#ifdef L_negvsi2
Wtype
__negvsi2 (Wtype a)
{
Wtype w;
w = -a;
if (a >= 0 ? w > 0 : w < 0)
abort ();
return w;
}
#endif
#ifdef L_negvdi2
DWtype
__negvdi2 (DWtype a)
{
DWtype w;
w = -a;
if (a >= 0 ? w > 0 : w < 0)
abort ();
return w;
}
#endif
#ifdef L_absvsi2
Wtype
__absvsi2 (Wtype a)
{
Wtype w = a;
if (a < 0)
#ifdef L_negvsi2
w = __negvsi2 (a);
#else
w = -a;
if (w < 0)
abort ();
#endif
return w;
}
#endif
#ifdef L_absvdi2
DWtype
__absvdi2 (DWtype a)
{
DWtype w = a;
if (a < 0)
#ifdef L_negvsi2
w = __negvsi2 (a);
#else
w = -a;
if (w < 0)
abort ();
#endif
return w;
}
#endif
#ifdef L_mulvdi3
DWtype
__mulvdi3 (DWtype u, DWtype v)
{
DWtype w;
w = u * v;
if (((u >= 0) == (v >= 0)) ? w < 0 : w > 0)
abort ();
return w;
}
#endif
#ifdef L_lshrdi3
DWtype
__lshrdi3 (DWtype u, word_type b)
{
DWunion w;
word_type bm;
DWunion uu;
if (b == 0)
return u;
uu.ll = u;
bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
if (bm <= 0)
{
w.s.high = 0;
w.s.low = (UWtype) uu.s.high >> -bm;
}
else
{
UWtype carries = (UWtype) uu.s.high << bm;
w.s.high = (UWtype) uu.s.high >> b;
w.s.low = ((UWtype) uu.s.low >> b) | carries;
}
return w.ll;
}
#endif
#ifdef L_ashldi3
DWtype
__ashldi3 (DWtype u, word_type b)
{
DWunion w;
word_type bm;
DWunion uu;
if (b == 0)
return u;
uu.ll = u;
bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
if (bm <= 0)
{
w.s.low = 0;
w.s.high = (UWtype) uu.s.low << -bm;
}
else
{
UWtype carries = (UWtype) uu.s.low >> bm;
w.s.low = (UWtype) uu.s.low << b;
w.s.high = ((UWtype) uu.s.high << b) | carries;
}
return w.ll;
}
#endif
#ifdef L_ashrdi3
DWtype
__ashrdi3 (DWtype u, word_type b)
{
DWunion w;
word_type bm;
DWunion uu;
if (b == 0)
return u;
uu.ll = u;
bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
if (bm <= 0)
{
w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
w.s.low = uu.s.high >> -bm;
}
else
{
UWtype carries = (UWtype) uu.s.high << bm;
w.s.high = uu.s.high >> b;
w.s.low = ((UWtype) uu.s.low >> b) | carries;
}
return w.ll;
}
#endif
#ifdef L_ffsdi2
DWtype
__ffsdi2 (DWtype u)
{
DWunion uu;
UWtype word, count, add;
uu.ll = u;
if (uu.s.low != 0)
word = uu.s.low, add = 0;
else if (uu.s.high != 0)
word = uu.s.high, add = BITS_PER_UNIT * sizeof (Wtype);
else
return 0;
count_trailing_zeros (count, word);
return count + add + 1;
}
#endif
#ifdef L_muldi3
DWtype
__muldi3 (DWtype u, DWtype v)
{
DWunion w;
DWunion uu, vv;
uu.ll = u,
vv.ll = v;
w.ll = __umulsidi3 (uu.s.low, vv.s.low);
w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
+ (UWtype) uu.s.high * (UWtype) vv.s.low);
return w.ll;
}
#endif
#if (defined (L_udivdi3) || defined (L_divdi3) || \
defined (L_umoddi3) || defined (L_moddi3))
#if defined (sdiv_qrnnd)
#define L_udiv_w_sdiv
#endif
#endif
#ifdef L_udiv_w_sdiv
#if defined (sdiv_qrnnd)
#if (defined (L_udivdi3) || defined (L_divdi3) || \
defined (L_umoddi3) || defined (L_moddi3))
static inline __attribute__ ((__always_inline__))
#endif
UWtype
__udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
{
UWtype q, r;
UWtype c0, c1, b1;
if ((Wtype) d >= 0)
{
if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1)))
{
sdiv_qrnnd (q, r, a1, a0, d);
}
else
{
sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1));
sdiv_qrnnd (q, r, c1, c0, d);
q += (UWtype) 1 << (W_TYPE_SIZE - 1);
}
}
else
{
b1 = d >> 1;
c1 = a1 >> 1;
c0 = (a1 << (W_TYPE_SIZE - 1)) + (a0 >> 1);
if (a1 < b1)
{
sdiv_qrnnd (q, r, c1, c0, b1);
r = 2*r + (a0 & 1);
if ((d & 1) != 0)
{
if (r >= q)
r = r - q;
else if (q - r <= d)
{
r = r - q + d;
q--;
}
else
{
r = r - q + 2*d;
q -= 2;
}
}
}
else if (c1 < b1)
{
c1 = (b1 - 1) - c1;
c0 = ~c0;
sdiv_qrnnd (q, r, c1, c0, b1);
q = ~q;
r = (b1 - 1) - r;
r = 2*r + (a0 & 1);
if ((d & 1) != 0)
{
if (r >= q)
r = r - q;
else if (q - r <= d)
{
r = r - q + d;
q--;
}
else
{
r = r - q + 2*d;
q -= 2;
}
}
}
else
{
if (a0 >= -d)
{
q = -1;
r = a0 + d;
}
else
{
q = -2;
r = a0 + 2*d;
}
}
}
*rp = r;
return q;
}
#else
UWtype
__udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
UWtype a1 __attribute__ ((__unused__)),
UWtype a0 __attribute__ ((__unused__)),
UWtype d __attribute__ ((__unused__)))
{
return 0;
}
#endif
#endif
#if (defined (L_udivdi3) || defined (L_divdi3) || \
defined (L_umoddi3) || defined (L_moddi3))
#define L_udivmoddi4
#endif
#ifdef L_clz
const UQItype __clz_tab[] =
{
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
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,
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,
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,
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,
};
#endif
#ifdef L_udivmoddi4
#if (defined (L_udivdi3) || defined (L_divdi3) || \
defined (L_umoddi3) || defined (L_moddi3))
static inline __attribute__ ((__always_inline__))
#endif
UDWtype
__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
{
DWunion ww;
DWunion nn, dd;
DWunion rr;
UWtype d0, d1, n0, n1, n2;
UWtype q0, q1;
UWtype b, bm;
nn.ll = n;
dd.ll = d;
d0 = dd.s.low;
d1 = dd.s.high;
n0 = nn.s.low;
n1 = nn.s.high;
#if !UDIV_NEEDS_NORMALIZATION
if (d1 == 0)
{
if (d0 > n1)
{
udiv_qrnnd (q0, n0, n1, n0, d0);
q1 = 0;
}
else
{
if (d0 == 0)
d0 = 1 / d0;
udiv_qrnnd (q1, n1, 0, n1, d0);
udiv_qrnnd (q0, n0, n1, n0, d0);
}
if (rp != 0)
{
rr.s.low = n0;
rr.s.high = 0;
*rp = rr.ll;
}
}
#else
if (d1 == 0)
{
if (d0 > n1)
{
count_leading_zeros (bm, d0);
if (bm != 0)
{
d0 = d0 << bm;
n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
n0 = n0 << bm;
}
udiv_qrnnd (q0, n0, n1, n0, d0);
q1 = 0;
}
else
{
if (d0 == 0)
d0 = 1 / d0;
count_leading_zeros (bm, d0);
if (bm == 0)
{
n1 -= d0;
q1 = 1;
}
else
{
b = W_TYPE_SIZE - bm;
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
udiv_qrnnd (q1, n1, n2, n1, d0);
}
udiv_qrnnd (q0, n0, n1, n0, d0);
}
if (rp != 0)
{
rr.s.low = n0 >> bm;
rr.s.high = 0;
*rp = rr.ll;
}
}
#endif
else
{
if (d1 > n1)
{
q0 = 0;
q1 = 0;
if (rp != 0)
{
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
}
else
{
count_leading_zeros (bm, d1);
if (bm == 0)
{
if (n1 > d1 || n0 >= d0)
{
q0 = 1;
sub_ddmmss (n1, n0, n1, n0, d1, d0);
}
else
q0 = 0;
q1 = 0;
if (rp != 0)
{
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
}
else
{
UWtype m1, m0;
b = W_TYPE_SIZE - bm;
d1 = (d1 << bm) | (d0 >> b);
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
udiv_qrnnd (q0, n1, n2, n1, d1);
umul_ppmm (m1, m0, q0, d0);
if (m1 > n1 || (m1 == n1 && m0 > n0))
{
q0--;
sub_ddmmss (m1, m0, m1, m0, d1, d0);
}
q1 = 0;
if (rp != 0)
{
sub_ddmmss (n1, n0, n1, n0, m1, m0);
rr.s.low = (n1 << b) | (n0 >> bm);
rr.s.high = n1 >> bm;
*rp = rr.ll;
}
}
}
}
ww.s.low = q0;
ww.s.high = q1;
return ww.ll;
}
#endif
#ifdef L_divdi3
DWtype
__divdi3 (DWtype u, DWtype v)
{
word_type c = 0;
DWunion uu, vv;
DWtype w;
uu.ll = u;
vv.ll = v;
if (uu.s.high < 0)
c = ~c,
uu.ll = -uu.ll;
if (vv.s.high < 0)
c = ~c,
vv.ll = -vv.ll;
w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
if (c)
w = -w;
return w;
}
#endif
#ifdef L_moddi3
DWtype
__moddi3 (DWtype u, DWtype v)
{
word_type c = 0;
DWunion uu, vv;
DWtype w;
uu.ll = u;
vv.ll = v;
if (uu.s.high < 0)
c = ~c,
uu.ll = -uu.ll;
if (vv.s.high < 0)
vv.ll = -vv.ll;
(void) __udivmoddi4 (uu.ll, vv.ll, &w);
if (c)
w = -w;
return w;
}
#endif
#ifdef L_umoddi3
UDWtype
__umoddi3 (UDWtype u, UDWtype v)
{
UDWtype w;
(void) __udivmoddi4 (u, v, &w);
return w;
}
#endif
#ifdef L_udivdi3
UDWtype
__udivdi3 (UDWtype n, UDWtype d)
{
return __udivmoddi4 (n, d, (UDWtype *) 0);
}
#endif
#ifdef L_cmpdi2
word_type
__cmpdi2 (DWtype a, DWtype b)
{
DWunion au, bu;
au.ll = a, bu.ll = b;
if (au.s.high < bu.s.high)
return 0;
else if (au.s.high > bu.s.high)
return 2;
if ((UWtype) au.s.low < (UWtype) bu.s.low)
return 0;
else if ((UWtype) au.s.low > (UWtype) bu.s.low)
return 2;
return 1;
}
#endif
#ifdef L_ucmpdi2
word_type
__ucmpdi2 (DWtype a, DWtype b)
{
DWunion au, bu;
au.ll = a, bu.ll = b;
if ((UWtype) au.s.high < (UWtype) bu.s.high)
return 0;
else if ((UWtype) au.s.high > (UWtype) bu.s.high)
return 2;
if ((UWtype) au.s.low < (UWtype) bu.s.low)
return 0;
else if ((UWtype) au.s.low > (UWtype) bu.s.low)
return 2;
return 1;
}
#endif
#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
__fixunstfDI (TFtype a)
{
TFtype b;
UDWtype v;
if (a < 0)
return 0;
b = (a / HIGH_WORD_COEFF);
v = (UWtype) b;
v <<= WORD_SIZE;
a -= (TFtype)v;
if (a < 0)
v -= (UWtype) (- a);
else
v += (UWtype) a;
return v;
}
#endif
#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
DWtype
__fixtfdi (TFtype a)
{
if (a < 0)
return - __fixunstfDI (-a);
return __fixunstfDI (a);
}
#endif
#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
__fixunsxfDI (XFtype a)
{
XFtype b;
UDWtype v;
if (a < 0)
return 0;
b = (a / HIGH_WORD_COEFF);
v = (UWtype) b;
v <<= WORD_SIZE;
a -= (XFtype)v;
if (a < 0)
v -= (UWtype) (- a);
else
v += (UWtype) a;
return v;
}
#endif
#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
DWtype
__fixxfdi (XFtype a)
{
if (a < 0)
return - __fixunsxfDI (-a);
return __fixunsxfDI (a);
}
#endif
#ifdef L_fixunsdfdi
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
__fixunsdfDI (DFtype a)
{
DFtype b;
UDWtype v;
if (a < 0)
return 0;
b = (a / HIGH_WORD_COEFF);
v = (UWtype) b;
v <<= WORD_SIZE;
a -= (DFtype)v;
if (a < 0)
v -= (UWtype) (- a);
else
v += (UWtype) a;
return v;
}
#endif
#ifdef L_fixdfdi
DWtype
__fixdfdi (DFtype a)
{
if (a < 0)
return - __fixunsdfDI (-a);
return __fixunsdfDI (a);
}
#endif
#ifdef L_fixunssfdi
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
__fixunssfDI (SFtype original_a)
{
DFtype a = original_a;
DFtype b;
UDWtype v;
if (a < 0)
return 0;
b = (a / HIGH_WORD_COEFF);
v = (UWtype) b;
v <<= WORD_SIZE;
a -= (DFtype) v;
if (a < 0)
v -= (UWtype) (- a);
else
v += (UWtype) a;
return v;
}
#endif
#ifdef L_fixsfdi
DWtype
__fixsfdi (SFtype a)
{
if (a < 0)
return - __fixunssfDI (-a);
return __fixunssfDI (a);
}
#endif
#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
XFtype
__floatdixf (DWtype u)
{
XFtype d;
d = (Wtype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
return d;
}
#endif
#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
TFtype
__floatditf (DWtype u)
{
TFtype d;
d = (Wtype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
return d;
}
#endif
#ifdef L_floatdidf
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DFtype
__floatdidf (DWtype u)
{
DFtype d;
d = (Wtype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
return d;
}
#endif
#ifdef L_floatdisf
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
#define DF_SIZE DBL_MANT_DIG
#define SF_SIZE FLT_MANT_DIG
SFtype
__floatdisf (DWtype u)
{
DFtype f;
if (DF_SIZE < DI_SIZE
&& DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
{
#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
if (! (- ((DWtype) 1 << DF_SIZE) < u
&& u < ((DWtype) 1 << DF_SIZE)))
{
if ((UDWtype) u & (REP_BIT - 1))
{
u &= ~ (REP_BIT - 1);
u |= REP_BIT;
}
}
}
f = (Wtype) (u >> WORD_SIZE);
f *= HIGH_HALFWORD_COEFF;
f *= HIGH_HALFWORD_COEFF;
f += (UWtype) (u & (HIGH_WORD_COEFF - 1));
return (SFtype) f;
}
#endif
#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
#undef char
#undef short
#undef int
#undef long
#undef unsigned
#undef float
#undef double
#undef MIN
#undef MAX
#include <limits.h>
UWtype
__fixunsxfSI (XFtype a)
{
if (a >= - (DFtype) Wtype_MIN)
return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
return (Wtype) a;
}
#endif
#ifdef L_fixunsdfsi
#undef char
#undef short
#undef int
#undef long
#undef unsigned
#undef float
#undef double
#undef MIN
#undef MAX
#include <limits.h>
UWtype
__fixunsdfSI (DFtype a)
{
if (a >= - (DFtype) Wtype_MIN)
return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
return (Wtype) a;
}
#endif
#ifdef L_fixunssfsi
#undef char
#undef short
#undef int
#undef long
#undef unsigned
#undef float
#undef double
#undef MIN
#undef MAX
#include <limits.h>
UWtype
__fixunssfSI (SFtype a)
{
if (a >= - (SFtype) Wtype_MIN)
return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
return (Wtype) a;
}
#endif
#define SItype bogus_type
#define USItype bogus_type
#define DItype bogus_type
#define UDItype bogus_type
#define SFtype bogus_type
#define DFtype bogus_type
#undef Wtype
#undef UWtype
#undef HWtype
#undef UHWtype
#undef DWtype
#undef UDWtype
#undef char
#undef short
#undef int
#undef long
#undef unsigned
#undef float
#undef double
#ifdef L__gcc_bcmp
int
__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size)
{
while (size > 0)
{
unsigned char c1 = *s1++, c2 = *s2++;
if (c1 != c2)
return c1 - c2;
size--;
}
return 0;
}
#endif
#ifdef L_eprintf
#if !defined (inhibit_libc) || defined (PHAT)
#undef NULL
#include <stdio.h>
void
__eprintf (const char *string, const char *expression,
unsigned int line, const char *filename)
{
fprintf (stderr, string, expression, line, filename);
fflush (stderr);
abort ();
}
#endif
#endif
#ifdef L_bb
struct bb_function_info {
long checksum;
int arc_count;
const char *name;
};
struct bb
{
long zero_word;
const char *filename;
gcov_type *counts;
long ncounts;
struct bb *next;
long sizeof_bb;
struct bb_function_info *function_infos;
};
#ifndef inhibit_libc
#undef NULL
#include <stdio.h>
#include "gcov-io.h"
#include <string.h>
#ifdef TARGET_HAS_F_SETLKW
#include <fcntl.h>
#include <errno.h>
#endif
static struct bb *bb_head;
void
__bb_exit_func (void)
{
struct bb *ptr;
int i;
gcov_type program_sum = 0;
gcov_type program_max = 0;
long program_arcs = 0;
gcov_type merged_sum = 0;
gcov_type merged_max = 0;
long merged_arcs = 0;
#if defined (TARGET_HAS_F_SETLKW)
struct flock s_flock;
s_flock.l_type = F_WRLCK;
s_flock.l_whence = SEEK_SET;
s_flock.l_start = 0;
s_flock.l_len = 0;
s_flock.l_pid = getpid ();
#endif
for (ptr = bb_head; ptr; ptr = ptr->next)
{
for (i = 0; i < ptr->ncounts; i++)
{
program_sum += ptr->counts[i];
if (ptr->counts[i] > program_max)
program_max = ptr->counts[i];
}
program_arcs += ptr->ncounts;
}
for (ptr = bb_head; ptr; ptr = ptr->next)
{
FILE *da_file;
gcov_type object_max = 0;
gcov_type object_sum = 0;
long object_functions = 0;
int merging = 0;
int error = 0;
struct bb_function_info *fn_info;
gcov_type *count_ptr;
da_file = fopen (ptr->filename, "r+b");
if (da_file)
merging = 1;
else
{
da_file = fopen (ptr->filename, "ab");
if (!da_file)
da_file = fopen (ptr->filename, "a");
}
if (!da_file)
{
fprintf (stderr, "arc profiling: Can't open output file %s.\n",
ptr->filename);
ptr->filename = 0;
continue;
}
#if defined (TARGET_HAS_F_SETLKW)
while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
&& errno == EINTR)
continue;
#endif
for (fn_info = ptr->function_infos; fn_info->arc_count != -1; fn_info++)
object_functions++;
if (merging)
{
long tmp_long;
gcov_type tmp_gcov;
if (
(__read_long (&tmp_long, da_file, 4) || tmp_long != -123l)
|| (__read_long (&tmp_long, da_file, 4)
|| tmp_long != object_functions)
|| (__read_long (&tmp_long, da_file, 4)
|| fseek (da_file, tmp_long, SEEK_CUR)))
{
read_error:;
fprintf (stderr, "arc profiling: Error merging output file %s.\n",
ptr->filename);
clearerr (da_file);
}
else
{
count_ptr = ptr->counts;
for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
fn_info++)
{
if (
(__read_long (&tmp_long, da_file, 4)
|| tmp_long != -1)
|| (__read_long (&tmp_long, da_file, 4)
|| tmp_long != (long) strlen (fn_info->name))
|| fseek (da_file, ((tmp_long + 1) + 3) & ~3, SEEK_CUR)
|| (__read_long (&tmp_long, da_file, 4)
|| tmp_long != -1))
goto read_error;
if (
(__read_long (&tmp_long, da_file, 4)
|| tmp_long != fn_info->checksum)
|| (__read_long (&tmp_long, da_file, 4)
|| tmp_long != fn_info->arc_count))
goto read_error;
for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
if (__read_gcov_type (&tmp_gcov, da_file, 8))
goto read_error;
else
*count_ptr += tmp_gcov;
}
}
fseek (da_file, 0, SEEK_SET);
}
for (i = 0; i < ptr->ncounts; i++)
{
object_sum += ptr->counts[i];
if (ptr->counts[i] > object_max)
object_max = ptr->counts[i];
}
merged_sum += object_sum;
if (merged_max < object_max)
merged_max = object_max;
merged_arcs += ptr->ncounts;
if (
__write_long (-123, da_file, 4)
|| __write_long (object_functions, da_file, 4)
|| __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4)
|| __write_long (merging ? ptr->ncounts : program_arcs, da_file, 4)
|| __write_gcov_type (merging ? object_sum : program_sum, da_file, 8)
|| __write_gcov_type (merging ? object_max : program_max, da_file, 8)
|| __write_long (ptr->ncounts, da_file, 4)
|| __write_gcov_type (object_sum, da_file, 8)
|| __write_gcov_type (object_max, da_file, 8))
{
write_error:;
fprintf (stderr, "arc profiling: Error writing output file %s.\n",
ptr->filename);
error = 1;
}
else
{
count_ptr = ptr->counts;
for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
fn_info++)
{
if (__write_gcov_string (fn_info->name,
strlen (fn_info->name), da_file, -1)
|| __write_long (fn_info->checksum, da_file, 4)
|| __write_long (fn_info->arc_count, da_file, 4))
goto write_error;
for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
if (__write_gcov_type (*count_ptr, da_file, 8))
goto write_error;
}
}
if (fclose (da_file))
{
fprintf (stderr, "arc profiling: Error closing output file %s.\n",
ptr->filename);
error = 1;
}
if (error || !merging)
ptr->filename = 0;
}
for (ptr = bb_head; ptr; ptr = ptr->next)
if (ptr->filename)
{
FILE *da_file;
da_file = fopen (ptr->filename, "r+b");
if (!da_file)
{
fprintf (stderr, "arc profiling: Cannot reopen %s.\n",
ptr->filename);
continue;
}
#if defined (TARGET_HAS_F_SETLKW)
while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
&& errno == EINTR)
continue;
#endif
if (fseek (da_file, 4 * 3, SEEK_SET)
|| __write_long (merged_arcs, da_file, 4)
|| __write_gcov_type (merged_sum, da_file, 8)
|| __write_gcov_type (merged_max, da_file, 8))
fprintf (stderr, "arc profiling: Error updating program header %s.\n",
ptr->filename);
if (fclose (da_file))
fprintf (stderr, "arc profiling: Error reclosing %s\n",
ptr->filename);
}
}
void
__bb_init_func (struct bb *blocks)
{
if (blocks->zero_word)
return;
if (!bb_head)
atexit (__bb_exit_func);
blocks->zero_word = 1;
blocks->next = bb_head;
bb_head = blocks;
}
void
__bb_fork_func (void)
{
struct bb *ptr;
__bb_exit_func ();
for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
{
long i;
for (i = ptr->ncounts - 1; i >= 0; i--)
ptr->counts[i] = 0;
}
}
#endif
#endif
#ifdef L_nf
struct nf_function_info {
long checksum;
int arc_count;
int call_count;
const char *name;
};
struct nf
{
long zero_word;
const char *filename;
gcov_type *arccounts;
long narccounts;
gcov_type *callcounts;
long ncallcounts;
long *arcindices;
long narcindices;
long *callindices;
long ncallindices;
struct nf *next;
long sizeof_nf;
struct nf_function_info *function_infos;
};
#ifndef inhibit_libc
#undef NULL
#include <stdio.h>
#include "gcov-io.h"
#include <string.h>
#ifdef TARGET_HAS_F_SETLKW
#include <fcntl.h>
#include <errno.h>
#endif
static struct nf *nf_head;
void
__nf_exit_func (void)
{
struct nf *ptr;
int i;
gcov_type program_arcctsum = 0;
gcov_type program_maxarcct = 0;
long program_narccts = 0;
gcov_type program_callctsum = 0;
gcov_type program_maxcallct = 0;
long program_ncallcts = 0;
gcov_type merged_arcctsum = 0;
gcov_type merged_maxarcct = 0;
long merged_arccts = 0;
gcov_type merged_callctsum = 0;
gcov_type merged_maxcallct = 0;
long merged_callcts = 0;
#if defined (TARGET_HAS_F_SETLKW)
struct flock s_flock;
s_flock.l_type = F_WRLCK;
s_flock.l_whence = SEEK_SET;
s_flock.l_start = 0;
s_flock.l_len = 0;
s_flock.l_pid = getpid ();
#endif
for (ptr = nf_head; ptr; ptr = ptr->next)
{
for (i = 0; i < ptr->narccounts; i++)
{
program_arcctsum += ptr->arccounts[i];
if (ptr->arccounts[i] > program_maxarcct)
program_maxarcct = ptr->arccounts[i];
}
program_narccts += ptr->narccounts;
for (i = 0; i < ptr->ncallcounts; i++)
{
program_callctsum += ptr->callcounts[i];
if (ptr->callcounts[i] > program_maxcallct)
program_maxcallct = ptr->callcounts[i];
}
program_ncallcts += ptr->ncallcounts;
}
for (ptr = nf_head; ptr; ptr = ptr->next)
{
FILE *db_file;
gcov_type object_maxarcct = 0;
gcov_type object_arcctsum = 0;
long object_functions = 0;
gcov_type object_maxcallct = 0;
gcov_type object_callctsum = 0;
int merging = 0;
int error = 0;
struct nf_function_info *fn_info;
gcov_type *arccount_ptr;
gcov_type *callcount_ptr;
long *arcindex_ptr;
long *callindex_ptr;
db_file = fopen (ptr->filename, "r+b");
if (db_file)
merging = 1;
else
{
db_file = fopen (ptr->filename, "ab");
if (!db_file)
db_file = fopen (ptr->filename, "a");
}
if (!db_file)
{
fprintf (stderr, "arc profiling: Can't open output file %s.\n",
ptr->filename);
ptr->filename = 0;
continue;
}
#if defined (TARGET_HAS_F_SETLKW)
while (fcntl (fileno (db_file), F_SETLKW, &s_flock)
&& errno == EINTR)
continue;
#endif
for (fn_info = ptr->function_infos; fn_info->arc_count != -1; fn_info++)
object_functions++;
if (merging)
{
long tmp_long;
gcov_type tmp_gcov;
if (
(__read_long (&tmp_long, db_file, 4) || tmp_long != -457l)
|| (__read_long (&tmp_long, db_file, 4)
|| tmp_long != object_functions)
|| (__read_long (&tmp_long, db_file, 4)
|| tmp_long != ptr->narccounts)
|| (__read_long (&tmp_long, db_file, 4)
|| tmp_long != ptr->ncallcounts)
|| (__read_long (&tmp_long, db_file, 4)
|| tmp_long != ptr->narcindices)
|| (__read_long (&tmp_long, db_file, 4)
|| tmp_long != ptr->ncallindices)
|| (__read_long (&tmp_long, db_file, 4)
|| fseek (db_file, tmp_long, SEEK_CUR)))
{
read_error:;
fprintf (stderr, "arc profiling: Error merging output file %s.\n",
ptr->filename);
clearerr (db_file);
}
else
{
arccount_ptr = ptr->arccounts;
callcount_ptr = ptr->callcounts;
for (i = ptr->narccounts; i >0; i--, arccount_ptr++)
if (__read_gcov_type (&tmp_gcov, db_file, 8))
goto read_error;
else
*arccount_ptr += tmp_gcov;
for (i = ptr->ncallcounts; i > 0; i--, callcount_ptr++)
if (__read_gcov_type (&tmp_gcov, db_file, 8))
goto read_error;
else
*callcount_ptr += tmp_gcov;
arcindex_ptr = ptr->arcindices;
callindex_ptr = ptr->callindices;
for (i = ptr->narcindices; i > 0; i--, arcindex_ptr++)
if (__read_long (&tmp_long, db_file, 4)
|| tmp_long != *arcindex_ptr)
goto read_error;
for (i = ptr->ncallindices; i > 0; i--, callindex_ptr++)
if (__read_long (&tmp_long, db_file, 4)
|| tmp_long != *callindex_ptr)
goto read_error;
}
fseek (db_file, 0, SEEK_SET);
}
for (i = 0; i < ptr->narccounts; i++)
{
object_arcctsum += ptr->arccounts[i];
if (ptr->arccounts[i] > object_maxarcct)
object_maxarcct = ptr->arccounts[i];
}
for (i = 0; i < ptr->ncallcounts; i++)
{
object_callctsum += ptr->callcounts[i];
if (ptr->callcounts[i] > object_maxcallct)
object_maxcallct = ptr->callcounts[i];
}
merged_arcctsum += object_arcctsum;
merged_callctsum += object_callctsum;
if (merged_maxarcct < object_maxarcct)
merged_maxarcct = object_maxarcct;
if (merged_maxcallct < object_maxcallct)
merged_maxcallct = object_maxcallct;
merged_arccts += ptr->narccounts;
merged_callcts += ptr->ncallcounts;
if (
__write_long (-457, db_file, 4)
|| __write_long (object_functions, db_file, 4)
|| __write_long (ptr->narccounts, db_file, 4)
|| __write_long (ptr->ncallcounts, db_file, 4)
|| __write_long (ptr->narcindices, db_file, 4)
|| __write_long (ptr->ncallindices, db_file, 4)
|| __write_long ((4 + 4 + 8 + 8 + 8 + 8)
+ (4 + 4 + 8 + 8 + 8 + 8), db_file, 4)
|| __write_long (merging ? ptr->narccounts : program_narccts,
db_file, 4)
|| __write_long (merging ? ptr->ncallcounts : program_ncallcts,
db_file, 4)
|| __write_gcov_type (merging ? object_arcctsum : program_arcctsum,
db_file, 8)
|| __write_gcov_type (merging ? object_callctsum
: program_callctsum, db_file, 8)
|| __write_gcov_type (merging ? object_maxarcct : program_maxarcct,
db_file, 8)
|| __write_gcov_type (merging ? object_maxcallct
: program_maxcallct, db_file, 8)
|| __write_long (ptr->narccounts, db_file, 4)
|| __write_long (ptr->ncallcounts, db_file, 4)
|| __write_gcov_type (object_arcctsum, db_file, 8)
|| __write_gcov_type (object_callctsum, db_file, 8)
|| __write_gcov_type (object_maxarcct, db_file, 8)
|| __write_gcov_type (object_maxcallct, db_file, 8))
{
write_error:;
fprintf (stderr, "arc profiling: Error writing output file %s.\n",
ptr->filename);
error = 1;
}
else
{
arccount_ptr = ptr->arccounts;
callcount_ptr = ptr->callcounts;
for (i = ptr->narccounts; i > 0; i--, arccount_ptr++)
if (__write_gcov_type (*arccount_ptr, db_file, 8))
goto write_error;
for (i = ptr->ncallcounts; i > 0; i--, callcount_ptr++)
if (__write_gcov_type (*callcount_ptr, db_file, 8))
goto write_error;
arcindex_ptr = ptr->arcindices;
callindex_ptr = ptr->callindices;
for (i = ptr->narcindices; i > 0; i--, arcindex_ptr++)
if (__write_long (*arcindex_ptr, db_file, 4))
goto write_error;
for (i = ptr->ncallindices; i > 0; i--, callindex_ptr++)
if (__write_long (*callindex_ptr, db_file, 4))
goto write_error;
}
if (fclose (db_file))
{
fprintf (stderr, "arc profiling: Error closing output file %s.\n",
ptr->filename);
error = 1;
}
if (error || !merging)
ptr->filename = 0;
}
for (ptr = nf_head; ptr; ptr = ptr->next)
if (ptr->filename)
{
FILE *db_file;
db_file = fopen (ptr->filename, "r+b");
if (!db_file)
{
fprintf (stderr, "arc profiling: Cannot reopen %s.\n",
ptr->filename);
continue;
}
#if defined (TARGET_HAS_F_SETLKW)
while (fcntl (fileno (db_file), F_SETLKW, &s_flock)
&& errno == EINTR)
continue;
#endif
if (fseek (db_file, 4 * 7, SEEK_SET)
|| __write_long (merged_arccts, db_file, 4)
|| __write_long (merged_callcts, db_file, 4)
|| __write_gcov_type (merged_arcctsum, db_file, 8)
|| __write_gcov_type (merged_callctsum, db_file, 8)
|| __write_gcov_type (merged_maxarcct, db_file, 8)
|| __write_gcov_type (merged_maxcallct, db_file, 8))
fprintf (stderr, "arc profiling: Error updating program header %s.\n",
ptr->filename);
if (fclose (db_file))
fprintf (stderr, "arc profiling: Error reclosing %s\n",
ptr->filename);
}
}
void
__nf_init_func (struct nf *blocks)
{
if (blocks->zero_word)
return;
if (!nf_head)
atexit (__nf_exit_func);
blocks->zero_word = 1;
blocks->next = nf_head;
nf_head = blocks;
}
void
__nf_fork_func (void)
{
struct nf *ptr;
__nf_exit_func ();
for (ptr = nf_head; ptr != (struct nf *) 0; ptr = ptr->next)
{
long i;
for (i = ptr->narccounts - 1; i >= 0; i--)
ptr->arccounts[i] = 0;
for (i = ptr->ncallcounts - 1; i >= 0; i--)
ptr->callcounts[i] = 0;
}
}
#endif
#endif
#ifdef L_clear_cache
#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
void
__clear_cache (char *beg __attribute__((__unused__)),
char *end __attribute__((__unused__)))
{
#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;
int offset;
void *start_addr
void *end_addr;
typedef (*function_ptr) (void);
#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
if (! initialized)
{
int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
& -INSN_CACHE_LINE_WIDTH);
int end_ptr = ptr + INSN_CACHE_SIZE;
while (ptr < end_ptr)
{
*(INSTRUCTION_TYPE *)ptr
= JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
ptr += INSN_CACHE_LINE_WIDTH;
}
*(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
initialized = 1;
}
(((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
& -INSN_CACHE_LINE_WIDTH))
());
#else
if (! initialized)
{
int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
& -INSN_CACHE_LINE_WIDTH);
while (ptr < (int) array + sizeof array)
{
*(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
ptr += INSN_CACHE_LINE_WIDTH;
}
initialized = 1;
}
offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
& -INSN_CACHE_PLANE_SIZE)
+ offset);
#if 0
if (end < beg + INSN_CACHE_PLANE_SIZE)
#endif
offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
& -INSN_CACHE_LINE_WIDTH)
& (INSN_CACHE_PLANE_SIZE - 1));
#if INSN_CACHE_DEPTH > 1
end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
if (end_addr <= start_addr)
end_addr += INSN_CACHE_PLANE_SIZE;
for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
{
int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE;
int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE;
while (addr != stop)
{
((function_ptr) addr) ();
addr += INSN_CACHE_LINE_WIDTH;
}
}
#else
do
{
((function_ptr) start_addr) ();
start_addr += INSN_CACHE_LINE_WIDTH;
}
while ((start_addr % INSN_CACHE_SIZE) != offset);
#endif
#endif
#endif
#endif
}
#endif
#ifdef L_trampoline
#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
long
getpagesize (void)
{
#ifdef _ALPHA_
return 8192;
#else
return 4096;
#endif
}
#ifdef __i386__
extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
#endif
int
mprotect (char *addr, int len, int prot)
{
int np, op;
if (prot == 7)
np = 0x40;
else if (prot == 5)
np = 0x20;
else if (prot == 4)
np = 0x10;
else if (prot == 3)
np = 0x04;
else if (prot == 1)
np = 0x02;
else if (prot == 0)
np = 0x01;
if (VirtualProtect (addr, len, np, &op))
return 0;
else
return -1;
}
#endif
#ifdef TRANSFER_FROM_TRAMPOLINE
TRANSFER_FROM_TRAMPOLINE
#endif
#ifdef __sysV68__
#include <sys/signal.h>
#include <errno.h>
#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
void
__clear_insn_cache (void)
{
#ifdef MCT_TEXT
int save_errno;
save_errno = errno;
memctl(0, 4096, MCT_TEXT);
errno = save_errno;
#endif
}
#endif
#endif
#ifndef __CYGWIN__
#ifdef L__main
#include "gbl-ctors.h"
#ifndef NAME__MAIN
#define NAME__MAIN "__main"
#define SYMBOL__MAIN __main
#endif
#ifdef INIT_SECTION_ASM_OP
#undef HAS_INIT_SECTION
#define HAS_INIT_SECTION
#endif
#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
#ifdef EH_FRAME_SECTION_NAME
#include "unwind-dw2-fde.h"
extern unsigned char __EH_FRAME_BEGIN__[];
#endif
void
__do_global_dtors (void)
{
#ifdef DO_GLOBAL_DTORS_BODY
DO_GLOBAL_DTORS_BODY;
#else
static func_ptr *p = __DTOR_LIST__ + 1;
while (*p)
{
p++;
(*(p-1)) ();
}
#endif
#if defined (EH_FRAME_SECTION_NAME) && !defined (HAS_INIT_SECTION)
{
static int completed = 0;
if (! completed)
{
completed = 1;
__deregister_frame_info (__EH_FRAME_BEGIN__);
}
}
#endif
}
#endif
#ifndef HAS_INIT_SECTION
void
__do_global_ctors (void)
{
#ifdef EH_FRAME_SECTION_NAME
{
static struct object object;
__register_frame_info (__EH_FRAME_BEGIN__, &object);
}
#endif
DO_GLOBAL_CTORS_BODY;
atexit (__do_global_dtors);
}
#endif
#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
void
SYMBOL__MAIN ()
{
static int initialized;
if (! initialized)
{
initialized = 1;
__do_global_ctors ();
}
}
#endif
#endif
#endif
#ifdef L_ctors
#include "gbl-ctors.h"
#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
#if defined (TARGET_ASM_CONSTRUCTOR) || defined (USE_COLLECT2)
func_ptr __CTOR_LIST__[2] = {0, 0};
func_ptr __DTOR_LIST__[2] = {0, 0};
#else
func_ptr __CTOR_LIST__[2];
func_ptr __DTOR_LIST__[2];
#endif
#endif
#endif
#ifdef L_exit
#include "gbl-ctors.h"
#ifdef NEED_ATEXIT
#ifndef ON_EXIT
# 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)
{
if (++last_atexit_chain_slot == atexit_chain_length)
{
atexit_chain_length += 32;
if (atexit_chain)
atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
* sizeof (func_ptr));
else
atexit_chain = (func_ptr *) malloc (atexit_chain_length
* sizeof (func_ptr));
if (! atexit_chain)
{
atexit_chain_length = 0;
last_atexit_chain_slot = -1;
errno = ENOMEM;
return (-1);
}
}
atexit_chain[last_atexit_chain_slot] = func;
return (0);
}
extern void _cleanup (void);
extern void _exit (int) __attribute__ ((__noreturn__));
void
exit (int status)
{
if (atexit_chain)
{
for ( ; last_atexit_chain_slot-- >= 0; )
{
(*atexit_chain[last_atexit_chain_slot + 1]) ();
atexit_chain[last_atexit_chain_slot + 1] = 0;
}
free (atexit_chain);
atexit_chain = 0;
}
#ifdef EXIT_BODY
EXIT_BODY;
#else
_cleanup ();
#endif
_exit (status);
}
#else
int
atexit (func_ptr func)
{
return ON_EXIT (func);
}
#endif
#endif
#endif