text:
#include <stdint.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>

#include "shgetc.h"
#include "floatscan.h"

#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024

#define LD_B1B_DIG 2
#define LD_B1B_MAX 9007199, 254740991
#define KMAX 128

#else /* LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 */

#define LD_B1B_DIG 3
#define LD_B1B_MAX 18, 446744073, 709551615
#define KMAX 2048

#endif

#define MASK (KMAX-1)

#define CONCAT2(x,y) x ## y
#define CONCAT(x,y) CONCAT2(x,y)

static long long scanexp(FILE *f, int pok)
{
	int c;
	int x;
	long long y;
	int neg = 0;

	c = shgetc(f);
	if (c=='+' || c=='-') {
		neg = (c=='-');
		c = shgetc(f);
		if (c-'0'>=10U && pok) shunget(f);
	}
	if (c-'0'>=10U) {
		shunget(f);
		return LLONG_MIN;
	}
	for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f))
		x = 10*x + c-'0';
	for (y=x; c-'0'<10U && y<LLONG_MAX/100; c = shgetc(f))
		y = 10*y + c-'0';
	for (; c-'0'<10U; c = shgetc(f));
	shunget(f);
	return neg ? -y : y;
}

static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int pok)
{
	uint32_t x[KMAX];
	static const uint32_t th[] = { LD_B1B_MAX };
	int i, j, k, a, z;
	long long lrp=0, dc=0;
	long long e10=0;
	int lnz = 0;
	int gotdig = 0, gotrad = 0;
	int rp;
	int e2;
	int emax = -emin-bits+3;
	int denormal = 0;
	long double y;
	long double frac=0;
	long double bias=0;
	static const int p10s[] = { 10, 100, 1000, 10000,
		100000, 1000000, 10000000, 100000000 };

	j=0;
	k=0;

	/* Don't let leading zeros consume buffer space */
	for (; c=='0'; c = shgetc(f)) gotdig=1;
	if (c=='.') {
		gotrad = 1;
		for (c = shgetc(f); c=='0'; c = shgetc(f)) gotdig=1, lrp--;
	}

	x[0] = 0;
	for (; c-'0'<10U || c=='.'; c = shgetc(f)) {
		if (c == '.') {
			if (gotrad) break;
			gotrad = 1;
			lrp = dc;
		} else if (k < KMAX-3) {
			dc++;
			if (c!='0') lnz = dc;
			if (j) x[k] = x[k]*10 + c-'0';
			else x[k] = c-'0';
			if (++j==9) {
				k++;
				j=0;
			}
			gotdig=1;
		} else {
			dc++;
			if (c!='0') x[KMAX-4] |= 1;
		}
	}
	if (!gotrad) lrp=dc;

	if (gotdig && (c|32)=='e') {
		e10 = scanexp(f, pok);
		if (e10 == LLONG_MIN) {
			if (pok) {
				shunget(f);
			} else {
				shlim(f, 0);
				return 0;
			}
			e10 = 0;
		}
		lrp += e10;
	} else if (c>=0) {
		shunget(f);
	}
	if (!gotdig) {
		errno = EINVAL;
		shlim(f, 0);
		return 0;
	}

	/* Handle zero specially to avoid nasty special cases later */
	if (!x[0]) return sign * 0.0;

	/* Optimize small integers (w/no exponent) and over/under-flow */
	if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0))
		return sign * (long double)x[0];
	if (lrp > -emin/2) {
		errno = ERANGE;
		return sign * LDBL_MAX * LDBL_MAX;
	}
	if (lrp < emin-2*LDBL_MANT_DIG) {
		errno = ERANGE;
		return sign * LDBL_MIN * LDBL_MIN;
	}

	/* Align incomplete final B1B digit */
	if (j) {
		for (; j<9; j++) x[k]*=10;
		k++;
		j=0;
	}

	a = 0;
	z = k;
	e2 = 0;
	rp = lrp;

	/* Optimize small to mid-size integers (even in exp. notation) */
	if (lnz<9 && lnz<=rp && rp < 18) {
		if (rp == 9) return sign * (long double)x[0];
		if (rp < 9) return sign * (long double)x[0] / p10s[8-rp];
		int bitlim = bits-3*(int)(rp-9);
		if (bitlim>30 || x[0]>>bitlim==0)
			return sign * (long double)x[0] * p10s[rp-10];
	}

	/* Align radix point to B1B digit boundary */
	if (rp % 9) {
		int rpm9 = rp>=0 ? rp%9 : rp%9+9;
		int p10 = p10s[8-rpm9];
		uint32_t carry = 0;
		for (k=a; k!=z; k++) {
			uint32_t tmp = x[k] % p10;
			x[k] = x[k]/p10 + carry;
			carry = 1000000000/p10 * tmp;
			if (k==a && !x[k]) {
				a = (a+1 & MASK);
				rp -= 9;
			}
		}
		if (carry) x[z++] = carry;
		rp += 9-rpm9;
	}

	/* Upscale until desired number of bits are left of radix point */
	while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a]<th[0])) {
		uint32_t carry = 0;
		e2 -= 29;
		for (k=(z-1 & MASK); ; k=(k-1 & MASK)) {
			uint64_t tmp = ((uint64_t)x[k] << 29) + carry;
			if (tmp > 1000000000) {
				carry = tmp / 1000000000;
				x[k] = tmp % 1000000000;
			} else {
				carry = 0;
				x[k] = tmp;
			}
			if (k==(z-1 & MASK) && k!=a && !x[k]) z = k;
			if (k==a) break;
		}
		if (carry) {
			rp += 9;
			a = (a-1 & MASK);
			if (a == z) {
				z = (z-1 & MASK);
				x[z-1 & MASK] |= x[z];
			}
			x[a] = carry;
		}
	}

	/* Downscale until exactly number of bits are left of radix point */
	for (;;) {
		uint32_t carry = 0;
		int sh = 1;
		for (i=0; i<LD_B1B_DIG; i++) {
			k = (a+i & MASK);
			if (k == z || x[k] < th[i]) {
				i=LD_B1B_DIG;
				break;
			}
			if (x[a+i & MASK] > th[i]) break;
		}
		if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break;
		/* FIXME: find a way to compute optimal sh */
		if (rp > 9+9*LD_B1B_DIG) sh = 9;
		e2 += sh;
		for (k=a; k!=z; k=(k+1 & MASK)) {
			uint32_t tmp = x[k] & (1<<sh)-1;
			x[k] = (x[k]>>sh) + carry;
			carry = (1000000000>>sh) * tmp;
			if (k==a && !x[k]) {
				a = (a+1 & MASK);
				i--;
				rp -= 9;
			}
		}
		if (carry) {
			if ((z+1 & MASK) != a) {
				x[z] = carry;
				z = (z+1 & MASK);
			} else x[z-1 & MASK] |= 1;
		}
	}

	/* Assemble desired bits into floating point variable */
	for (y=i=0; i<LD_B1B_DIG; i++) {
		if ((a+i & MASK)==z) x[(z=(z+1 & MASK))-1] = 0;
		y = 1000000000.0L * y + x[a+i & MASK];
	}

	y *= sign;

	/* Limit precision for denormal results */
	if (bits > LDBL_MANT_DIG+e2-emin) {
		bits = LDBL_MANT_DIG+e2-emin;
		if (bits<0) bits=0;
		denormal = 1;
	}

	/* Calculate bias term to force rounding, move out lower bits */
	if (bits < LDBL_MANT_DIG) {
		bias = copysignl(scalbn(1, 2*LDBL_MANT_DIG-bits-1), y);
		frac = fmodl(y, scalbn(1, LDBL_MANT_DIG-bits));
		y -= frac;
		y += bias;
	}

	/* Process tail of decimal input so it can affect rounding */
	if ((a+i & MASK) != z) {
		uint32_t t = x[a+i & MASK];
		if (t < 500000000 && (t || (a+i+1 & MASK) != z))
			frac += 0.25*sign;
		else if (t > 500000000)
			frac += 0.75*sign;
		else if (t == 500000000) {
			if ((a+i+1 & MASK) == z)
				frac += 0.5*sign;
			else
				frac += 0.75*sign;
		}
		if (LDBL_MANT_DIG-bits >= 2 && !fmodl(frac, 1))
			frac++;
	}

	y += frac;
	y -= bias;

	if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) {
		if (fabs(y) >= CONCAT(0x1p, LDBL_MANT_DIG)) {
			if (denormal && bits==LDBL_MANT_DIG+e2-emin)
				denormal = 0;
			y *= 0.5;
			e2++;
		}
		if (e2+LDBL_MANT_DIG>emax || (denormal && frac))
			errno = ERANGE;
	}

	return scalbnl(y, e2);
}

static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok)
{
	uint32_t x = 0;
	long double y = 0;
	long double scale = 1;
	long double bias = 0;
	int gottail = 0, gotrad = 0, gotdig = 0;
	long long rp = 0;
	long long dc = 0;
	long long e2 = 0;
	int d;
	int c;

	c = shgetc(f);

	/* Skip leading zeros */
	for (; c=='0'; c = shgetc(f)) gotdig = 1;

	if (c=='.') {
		gotrad = 1;
		c = shgetc(f);
		/* Count zeros after the radix point before significand */
		for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1;
	}

	for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) {
		if (c=='.') {
			if (gotrad) break;
			rp = dc;
			gotrad = 1;
		} else {
			gotdig = 1;
			if (c > '9') d = (c|32)+10-'a';
			else d = c-'0';
			if (dc<8) {
				x = x*16 + d;
			} else if (dc < LDBL_MANT_DIG/4+1) {
				y += d*(scale/=16);
			} else if (d && !gottail) {
				y += 0.5*scale;
				gottail = 1;
			}
			dc++;
		}
	}
	if (!gotdig) {
		shunget(f);
		if (pok) {
			shunget(f);
			if (gotrad) shunget(f);
		} else {
			shlim(f, 0);
		}
		return sign * 0.0;
	}
	if (!gotrad) rp = dc;
	while (dc<8) x *= 16, dc++;
	if ((c|32)=='p') {
		e2 = scanexp(f, pok);
		if (e2 == LLONG_MIN) {
			if (pok) {
				shunget(f);
			} else {
				shlim(f, 0);
				return 0;
			}
			e2 = 0;
		}
	} else {
		shunget(f);
	}
	e2 += 4*rp - 32;

	if (!x) return sign * 0.0;
	if (e2 > -emin) {
		errno = ERANGE;
		return sign * LDBL_MAX * LDBL_MAX;
	}
	if (e2 < emin-2*LDBL_MANT_DIG) {
		errno = ERANGE;
		return sign * LDBL_MIN * LDBL_MIN;
	}

	while (x < 0x80000000) {
		if (y>=0.5) {
			x += x + 1;
			y += y - 1;
		} else {
			x += x;
			y += y;
		}
		e2--;
	}

	if (bits > 32+e2-emin) {
		bits = 32+e2-emin;
		if (bits<0) bits=0;
	}

	if (bits < LDBL_MANT_DIG)
		bias = copysignl(scalbn(1, 32+LDBL_MANT_DIG-bits-1), sign);

	if (bits<32 && y && !(x&1)) x++, y=0;

	y = bias + sign*(long double)x + sign*y;
	y -= bias;

	if (!y) errno = ERANGE;

	return scalbnl(y, e2);
}

long double __floatscan(FILE *f, int prec, int pok)
{
	int sign = 1;
	size_t i;
	int bits;
	int emin;
	int c;

	switch (prec) {
	case 0:
		bits = FLT_MANT_DIG;
		emin = FLT_MIN_EXP-bits;
		break;
	case 1:
		bits = DBL_MANT_DIG;
		emin = DBL_MIN_EXP-bits;
		break;
	case 2:
		bits = LDBL_MANT_DIG;
		emin = LDBL_MIN_EXP-bits;
		break;
	default:
		return 0;
	}

	while (isspace((c=shgetc(f))));

	if (c=='+' || c=='-') {
		sign -= 2*(c=='-');
		c = shgetc(f);
	}

	for (i=0; i<8 && (c|32)=="infinity"[i]; i++)
		if (i<7) c = shgetc(f);
	if (i==3 || i==8 || (i>3 && pok)) {
		if (i!=8) {
			shunget(f);
			if (pok) for (; i>3; i--) shunget(f);
		}
		return sign * INFINITY;
	}
	if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++)
		if (i<2) c = shgetc(f);
	if (i==3) {
		if (shgetc(f) != '(') {
			shunget(f);
			return NAN;
		}
		for (i=1; ; i++) {
			c = shgetc(f);
			if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_')
				continue;
			if (c==')') return NAN;
			shunget(f);
			if (!pok) {
				errno = EINVAL;
				shlim(f, 0);
				return 0;
			}
			while (i--) shunget(f);
			return NAN;
		}
		return NAN;
	}

	if (i) {
		shunget(f);
		errno = EINVAL;
		shlim(f, 0);
		return 0;
	}

	if (c=='0') {
		c = shgetc(f);
		if ((c|32) == 'x')
			return hexfloat(f, bits, emin, sign, pok);
		shunget(f);
		c = '0';
	}

	return decfloat(f, c, bits, emin, sign, pok);
}


text:
#include "stdio_impl.h"

void __shlim(FILE *, off_t);
int __shgetc(FILE *);

#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->rend))
#define shlim(f, lim) __shlim((f), (lim))
#define shgetc(f) (((f)->rpos < (f)->shend) ? *(f)->rpos++ : __shgetc(f))
#define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0)

repo_language: C

mime_type: text/x-c


text:
#ifdef SHARED

#include "version.h"

static const char version[] = VERSION;

const char *__libc_get_version()
{
	return version;
}

#endif


text:
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include "shgetc.h"

/* Lookup table for digit values. -1==255>=36 -> invalid */
static const unsigned char table[] = { -1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};

unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim)
{
	const unsigned char *val = table+1;
	int c, neg=0;
	unsigned x;
	unsigned long long y;
	if (base > 36) {
		errno = EINVAL;
		return 0;
	}
	while (isspace((c=shgetc(f))));
	if (c=='+' || c=='-') {
		neg = -(c=='-');
		c = shgetc(f);
	}
	if ((base == 0 || base == 16) && c=='0') {
		c = shgetc(f);
		if ((c|32)=='x') {
			c = shgetc(f);
			if (val[c]>=16) {
				shunget(f);
				if (pok) shunget(f);
				else shlim(f, 0);
				return 0;
			}
			base = 16;
		} else if (base == 0) {
			base = 8;
		}
	} else {
		if (base == 0) base = 10;
		if (val[c] >= base) {
			shunget(f);
			shlim(f, 0);
			errno = EINVAL;
			return 0;
		}
	}
	if (base == 10) {
		for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
			x = x*10 + (c-'0');
		for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
			y = y*10 + (c-'0');
		if (c-'0'>=10U) goto done;
	} else if (!(base & base-1)) {
		int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7];
		for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f))
			x = x<<bs | val[c];
		for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f))
			y = y<<bs | val[c];
	} else {
		for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f))
			x = x*base + val[c];
		for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f))
			y = y*base + val[c];
	}
	if (val[c]<base) {
		for (; val[c]<base; c=shgetc(f));
		errno = ERANGE;
		y = lim;
		if (lim&1) neg = 0;
	}
done:
	shunget(f);
	if (y>=lim) {
		if (!(lim&1) && !neg) {
			errno = ERANGE;
			return lim-1;
		} else if (y>lim) {
			errno = ERANGE;
			return lim;
		}
	}
	return (y^neg)-neg;
}


text:
#ifndef FLOATSCAN_H
#define FLOATSCAN_H

#include <stdio.h>

long double __floatscan(FILE *, int, int);

#endif


text:
#ifndef LIBC_H
#define LIBC_H

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

struct __locale_map;

struct __locale_struct {
	int ctype_utf8;
	char *messages_name;
	struct __locale_map *cat[4];
};

struct __libc {
	int has_thread_pointer;
	int can_do_threads;
	int threaded;
	int secure;
	size_t *auxv;
	volatile int threads_minus_1;
	FILE *ofl_head;
	int ofl_lock[2];
	size_t tls_size;
	size_t page_size;
	volatile int uselocale_cnt;
	volatile int bytelocale_cnt_minus_1;
	struct __locale_struct global_locale;
};

extern size_t __hwcap;

#ifndef PAGE_SIZE
#define PAGE_SIZE libc.page_size
#endif

#if !defined(__PIC__) || (100*__GNUC__+__GNUC_MINOR__ >= 303 && !defined(__PCC__))

#ifdef __PIC__
#if __GNUC__ < 4
#define BROKEN_VISIBILITY 1
#endif
#define ATTR_LIBC_VISIBILITY __attribute__((visibility("hidden")))
#else
#define ATTR_LIBC_VISIBILITY
#endif

extern struct __libc __libc ATTR_LIBC_VISIBILITY;
#define libc __libc

#else

#define USE_LIBC_ACCESSOR
#define ATTR_LIBC_VISIBILITY
extern struct __libc *__libc_loc(void) __attribute__((const));
#define libc (*__libc_loc())

#endif

/* Designed to avoid any overhead in non-threaded processes */
void __lock(volatile int *) ATTR_LIBC_VISIBILITY;
void __unlock(volatile int *) ATTR_LIBC_VISIBILITY;
int __lockfile(FILE *) ATTR_LIBC_VISIBILITY;
void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY;
#define LOCK(x) __lock(x)
#define UNLOCK(x) __unlock(x)

void __synccall(void (*)(void *), void *);
int __setxid(int, int, int, int);

extern char **__environ;

#undef weak_alias
#define weak_alias(old, new) \
	extern __typeof(old) new __attribute__((weak, alias(#old)))

#undef LFS64_2
#define LFS64_2(x, y) weak_alias(x, y)

#undef LFS64
#define LFS64(x) LFS64_2(x, x##64)

#endif


text:
void __procfdname(char *buf, unsigned fd)
{
	unsigned i, j;
	for (i=0; (buf[i] = "/proc/self/fd/"[i]); i++);
	if (!fd) {
		buf[i] = '0';
		buf[i+1] = 0;
		return;
	}
	for (j=fd; j; j/=10, i++);
	buf[i] = 0;
	for (; fd; fd/=10) buf[--i] = '0' + fd%10;
}


text:
#include <elf.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include "libc.h"
#include "syscall.h"

#ifdef VDSO_USEFUL

#if ULONG_MAX == 0xffffffff
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Phdr Phdr;
typedef Elf32_Sym Sym;
typedef Elf32_Verdef Verdef;
typedef Elf32_Verdaux Verdaux;
#else
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Phdr Phdr;
typedef Elf64_Sym Sym;
typedef Elf64_Verdef Verdef;
typedef Elf64_Verdaux Verdaux;
#endif

static int checkver(Verdef *def, int vsym, const char *vername, char *strings)
{
	vsym &= 0x7fff;
	for (;;) {
		if (!(def->vd_flags & VER_FLG_BASE)
		  && (def->vd_ndx & 0x7fff) == vsym)
			break;
		if (def->vd_next == 0)
			return 0;
		def = (Verdef *)((char *)def + def->vd_next);
	}
	Verdaux *aux = (Verdaux *)((char *)def + def->vd_aux);
	return !strcmp(vername, strings + aux->vda_name);
}

#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)

void *__vdsosym(const char *vername, const char *name)
{
	size_t i;
	for (i=0; libc.auxv[i] != AT_SYSINFO_EHDR; i+=2)
		if (!libc.auxv[i]) return 0;
	Ehdr *eh = (void *)libc.auxv[i+1];
	Phdr *ph = (void *)((char *)eh + eh->e_phoff);
	size_t *dynv=0, base=-1;
	for (i=0; i<eh->e_phnum; i++, ph=(void *)((char *)ph+eh->e_phentsize)) {
		if (ph->p_type == PT_LOAD)
			base = (size_t)eh + ph->p_offset - ph->p_vaddr;
		else if (ph->p_type == PT_DYNAMIC)
			dynv = (void *)((char *)eh + ph->p_offset);
	}
	if (!dynv || base==(size_t)-1) return 0;

	char *strings = 0;
	Sym *syms = 0;
	uint32_t *hashtab = 0;
	uint16_t *versym = 0;
	Verdef *verdef = 0;

	for (i=0; dynv[i]; i+=2) {
		void *p = (void *)(base + dynv[i+1]);
		switch(dynv[i]) {
		case DT_STRTAB: strings = p; break;
		case DT_SYMTAB: syms = p; break;
		case DT_HASH: hashtab = p; break;
		case DT_VERSYM: versym = p; break;
		case DT_VERDEF: verdef = p; break;
		}
	}

	if (!strings || !syms || !hashtab) return 0;
	if (!verdef) versym = 0;

	for (i=0; i<hashtab[1]; i++) {
		if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue;
		if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue;
		if (!syms[i].st_shndx) continue;
		if (strcmp(name, strings+syms[i].st_name)) continue;
		if (versym && !checkver(verdef, versym[i], vername, strings))
			continue;
		return (void *)(base + syms[i].st_value);
	}

	return 0;
}

#endif


text:
#include <locale.h>
#include <stdlib.h>
#include "libc.h"
#include "pthread_impl.h"

#define LOCALE_NAME_MAX 15

struct __locale_map {
	const void *map;
	size_t map_size;
	char name[LOCALE_NAME_MAX+1];
	struct __locale_map *next;
};

int __setlocalecat(locale_t, int, const char *);
const char *__mo_lookup(const void *, size_t, const char *);
const char *__lctrans(const char *, const struct __locale_map *);
const char *__lctrans_cur(const char *);

#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)-2])
#define LCTRANS_CUR(msg) __lctrans_cur(msg)

#define CURRENT_LOCALE \
	(libc.uselocale_cnt ? __pthread_self()->locale : &libc.global_locale)

#define CURRENT_UTF8 \
	(libc.bytelocale_cnt_minus_1<0 || __pthread_self()->locale->ctype_utf8)

#undef MB_CUR_MAX
#define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1)


text:
#ifndef _PTHREAD_IMPL_H
#define _PTHREAD_IMPL_H

#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <limits.h>
#include "libc.h"
#include "syscall.h"
#include "atomic.h"
#include "futex.h"

#define pthread __pthread

struct pthread {
	struct pthread *self;
	void **dtv, *unused1, *unused2;
	uintptr_t sysinfo;
	uintptr_t canary;
	pid_t tid, pid;
	int tsd_used, errno_val;
	volatile int cancel, canceldisable, cancelasync;
	int detached;
	unsigned char *map_base;
	size_t map_size;
	void *stack;
	size_t stack_size;
	void *start_arg;
	void *(*start)(void *);
	void *result;
	struct __ptcb *cancelbuf;
	void **tsd;
	pthread_attr_t attr;
	volatile int dead;
	struct {
		volatile void *volatile head;
		long off;
		volatile void *volatile pending;
	} robust_list;
	int unblock_cancel;
	int timer_id;
	locale_t locale;
	int killlock[2];
	int exitlock[2];
	int startlock[2];
	unsigned long sigmask[_NSIG/8/sizeof(long)];
	void *stdio_locks;
};

struct __timer {
	int timerid;
	pthread_t thread;
};

#define __SU (sizeof(size_t)/sizeof(int))

#define _a_stacksize __u.__s[0]
#define _a_guardsize __u.__s[1]
#define _a_stackaddr __u.__s[2]
#define _a_detach __u.__i[3*__SU+0]
#define _a_sched __u.__i[3*__SU+1]
#define _a_policy __u.__i[3*__SU+2]
#define _a_prio __u.__i[3*__SU+3]
#define _m_type __u.__i[0]
#define _m_lock __u.__i[1]
#define _m_waiters __u.__i[2]
#define _m_prev __u.__p[3]
#define _m_next __u.__p[4]
#define _m_count __u.__i[5]
#define _c_shared __u.__p[0]
#define _c_seq __u.__i[2]
#define _c_waiters __u.__i[3]
#define _c_clock __u.__i[4]
#define _c_lock __u.__i[8]
#define _c_head __u.__p[1]
#define _c_tail __u.__p[5]
#define _rw_lock __u.__i[0]
#define _rw_waiters __u.__i[1]
#define _rw_shared __u.__i[2]
#define _b_lock __u.__i[0]
#define _b_waiters __u.__i[1]
#define _b_limit __u.__i[2]
#define _b_count __u.__i[3]
#define _b_waiters2 __u.__i[4]
#define _b_inst __u.__p[3]

#include "pthread_arch.h"

#define SIGTIMER 32
#define SIGCANCEL 33
#define SIGSYNCCALL 34

#define SIGALL_SET ((sigset_t *)(const unsigned long long [2]){ -1,-1 })
#define SIGPT_SET \
	((sigset_t *)(const unsigned long [_NSIG/8/sizeof(long)]){ \
	[sizeof(long)==4] = 3UL<<(32*(sizeof(long)>4)) })
#define SIGTIMER_SET \
	((sigset_t *)(const unsigned long [_NSIG/8/sizeof(long)]){ \
	 0x80000000 })

pthread_t __pthread_self_init(void);

int __clone(int (*)(void *), void *, int, void *, ...);
int __set_thread_area(void *);
int __libc_sigaction(int, const struct sigaction *, struct sigaction *);
int __libc_sigprocmask(int, const sigset_t *, sigset_t *);
void __lock(volatile int *);
void __unmapself(void *, size_t);

int __timedwait(volatile int *, int, clockid_t, const struct timespec *, void (*)(void *), void *, int);
void __wait(volatile int *, volatile int *, int, int);
static inline void __wake(volatile void *addr, int cnt, int priv)
{
	if (priv) priv = 128;
	if (cnt<0) cnt = INT_MAX;
	__syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS ||
	__syscall(SYS_futex, addr, FUTEX_WAKE, cnt);
}

void __acquire_ptc();
void __release_ptc();
void __inhibit_ptc();

void __block_all_sigs(void *);
void __block_app_sigs(void *);
void __restore_sigs(void *);

#define DEFAULT_STACK_SIZE 81920
#define DEFAULT_GUARD_SIZE PAGE_SIZE

#define __ATTRP_C11_THREAD ((void*)(uintptr_t)-1)

#endif


text:
#ifndef INTSCAN_H
#define INTSCAN_H

#include <stdio.h>

unsigned long long __intscan(FILE *, unsigned, int, unsigned long long);

#endif


text:
#ifndef _STDIO_IMPL_H
#define _STDIO_IMPL_H

#include <stdio.h>
#include "syscall.h"
#include "libc.h"

#define UNGET 8

#define FFINALLOCK(f) ((f)->lock>=0 ? __lockfile((f)) : 0)
#define FLOCK(f) int __need_unlock = ((f)->lock>=0 ? __lockfile((f)) : 0)
#define FUNLOCK(f) if (__need_unlock) __unlockfile((f)); else

#define F_PERM 1
#define F_NORD 4
#define F_NOWR 8
#define F_EOF 16
#define F_ERR 32
#define F_SVB 64
#define F_APP 128

struct _IO_FILE {
	unsigned flags;
	unsigned char *rpos, *rend;
	int (*close)(FILE *);
	unsigned char *wend, *wpos;
	unsigned char *mustbezero_1;
	unsigned char *wbase;
	size_t (*read)(FILE *, unsigned char *, size_t);
	size_t (*write)(FILE *, const unsigned char *, size_t);
	off_t (*seek)(FILE *, off_t, int);
	unsigned char *buf;
	size_t buf_size;
	FILE *prev, *next;
	int fd;
	int pipe_pid;
	long lockcount;
	short dummy3;
	signed char mode;
	signed char lbf;
	int lock;
	int waiters;
	void *cookie;
	off_t off;
	char *getln_buf;
	void *mustbezero_2;
	unsigned char *shend;
	off_t shlim, shcnt;
	FILE *prev_locked, *next_locked;
};

size_t __stdio_read(FILE *, unsigned char *, size_t);
size_t __stdio_write(FILE *, const unsigned char *, size_t);
size_t __stdout_write(FILE *, const unsigned char *, size_t);
off_t __stdio_seek(FILE *, off_t, int);
int __stdio_close(FILE *);

size_t __string_read(FILE *, unsigned char *, size_t);

int __toread(FILE *);
int __towrite(FILE *);

#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303)
__attribute__((visibility("protected")))
#endif
int __overflow(FILE *, int), __uflow(FILE *);

int __fseeko(FILE *, off_t, int);
int __fseeko_unlocked(FILE *, off_t, int);
off_t __ftello(FILE *);
off_t __ftello_unlocked(FILE *);
size_t __fwritex(const unsigned char *, size_t, FILE *);
int __putc_unlocked(int, FILE *);

FILE *__fdopen(int, const char *);
int __fmodeflags(const char *);

#define OFLLOCK() LOCK(libc.ofl_lock)
#define OFLUNLOCK() UNLOCK(libc.ofl_lock)

#define feof(f) ((f)->flags & F_EOF)
#define ferror(f) ((f)->flags & F_ERR)

#define getc_unlocked(f) \
	( ((f)->rpos < (f)->rend) ? *(f)->rpos++ : __uflow((f)) )

#define putc_unlocked(c, f) ( ((c)!=(f)->lbf && (f)->wpos<(f)->wend) \
	? *(f)->wpos++ = (c) : __overflow((f),(c)) )

/* Caller-allocated FILE * operations */
FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t);
int __fclose_ca(FILE *);

#endif


text:
/* This is the structure used for the rt_sigaction syscall on most archs,
 * but it can be overridden by a file with the same name in the top-level
 * arch dir for a given arch, if necessary. */
struct k_sigaction {
	void (*handler)(int);
	unsigned long flags;
	void (*restorer)(void);
	unsigned mask[2];
};


text:
#ifndef _INTERNAL_FUTEX_H
#define _INTERNAL_FUTEX_H

#define FUTEX_WAIT		0
#define FUTEX_WAKE		1
#define FUTEX_FD		2
#define FUTEX_REQUEUE		3
#define FUTEX_CMP_REQUEUE	4
#define FUTEX_WAKE_OP		5
#define FUTEX_LOCK_PI		6
#define FUTEX_UNLOCK_PI		7
#define FUTEX_TRYLOCK_PI	8
#define FUTEX_WAIT_BITSET	9

#define FUTEX_CLOCK_REALTIME 256

int __futex(volatile int *, int, int, void *);

#endif


text:
#ifndef _INTERNAL_SYSCALL_H
#define _INTERNAL_SYSCALL_H

#include <sys/syscall.h>
#include "syscall_arch.h"

#ifndef SYSCALL_RLIM_INFINITY
#define SYSCALL_RLIM_INFINITY (~0ULL)
#endif

#ifndef SYSCALL_MMAP2_UNIT
#define SYSCALL_MMAP2_UNIT 4096ULL
#endif

#ifndef __scc
#define __scc(X) ((long) (X))
typedef long syscall_arg_t;
#endif

#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303)
__attribute__((visibility("hidden")))
#endif
long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...),
	__syscall_cp(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t,
	             syscall_arg_t, syscall_arg_t, syscall_arg_t);

#define __syscall1(n,a) __syscall1(n,__scc(a))
#define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b))
#define __syscall3(n,a,b,c) __syscall3(n,__scc(a),__scc(b),__scc(c))
#define __syscall4(n,a,b,c,d) __syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d))
#define __syscall5(n,a,b,c,d,e) __syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e))
#define __syscall6(n,a,b,c,d,e,f) __syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f))
#define __syscall7(n,a,b,c,d,e,f,g) (__syscall)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g))

#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n
#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,)
#define __SYSCALL_CONCAT_X(a,b) a##b
#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b)
#define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)

#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__)
#define syscall(...) __syscall_ret(__syscall(__VA_ARGS__))

#define socketcall __socketcall
#define socketcall_cp __socketcall_cp

#define __syscall_cp0(n) (__syscall_cp)(n,0,0,0,0,0,0)
#define __syscall_cp1(n,a) (__syscall_cp)(n,__scc(a),0,0,0,0,0)
#define __syscall_cp2(n,a,b) (__syscall_cp)(n,__scc(a),__scc(b),0,0,0,0)
#define __syscall_cp3(n,a,b,c) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),0,0,0)
#define __syscall_cp4(n,a,b,c,d) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),0,0)
#define __syscall_cp5(n,a,b,c,d,e) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),0)
#define __syscall_cp6(n,a,b,c,d,e,f) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f))

#define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)
#define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__))

#ifdef SYS_socket
#define __socketcall(nm,a,b,c,d,e,f) syscall(SYS_##nm, a, b, c, d, e, f)
#define __socketcall_cp(nm,a,b,c,d,e,f) syscall_cp(SYS_##nm, a, b, c, d, e, f)
#else
#define __socketcall(nm,a,b,c,d,e,f) syscall(SYS_socketcall, __SC_##nm, \
    ((long [6]){ (long)a, (long)b, (long)c, (long)d, (long)e, (long)f }))
#define __socketcall_cp(nm,a,b,c,d,e,f) syscall_cp(SYS_socketcall, __SC_##nm, \
    ((long [6]){ (long)a, (long)b, (long)c, (long)d, (long)e, (long)f }))
#endif

/* fixup legacy 16-bit junk */

#ifdef SYS_getuid32
#undef SYS_lchown
#undef SYS_getuid
#undef SYS_getgid
#undef SYS_geteuid
#undef SYS_getegid
#undef SYS_setreuid
#undef SYS_setregid
#undef SYS_getgroups
#undef SYS_setgroups
#undef SYS_fchown
#undef SYS_setresuid
#undef SYS_getresuid
#undef SYS_setresgid
#undef SYS_getresgid
#undef SYS_chown
#undef SYS_setuid
#undef SYS_setgid
#undef SYS_setfsuid
#undef SYS_setfsgid
#define SYS_lchown SYS_lchown32
#define SYS_getuid SYS_getuid32
#define SYS_getgid SYS_getgid32
#define SYS_geteuid SYS_geteuid32
#define SYS_getegid SYS_getegid32
#define SYS_setreuid SYS_setreuid32
#define SYS_setregid SYS_setregid32
#define SYS_getgroups SYS_getgroups32
#define SYS_setgroups SYS_setgroups32
#define SYS_fchown SYS_fchown32
#define SYS_setresuid SYS_setresuid32
#define SYS_getresuid SYS_getresuid32
#define SYS_setresgid SYS_setresgid32
#define SYS_getresgid SYS_getresgid32
#define SYS_chown SYS_chown32
#define SYS_setuid SYS_setuid32
#define SYS_setgid SYS_setgid32
#define SYS_setfsuid SYS_setfsuid32
#define SYS_setfsgid SYS_setfsgid32
#endif

/* fixup legacy 32-bit-vs-lfs64 junk */

#ifdef SYS_fcntl64
#undef SYS_fcntl
#define SYS_fcntl SYS_fcntl64
#endif

#ifdef SYS_getdents64
#undef SYS_getdents
#define SYS_getdents SYS_getdents64
#endif

#ifdef SYS_ftruncate64
#undef SYS_ftruncate
#undef SYS_truncate
#define SYS_ftruncate SYS_ftruncate64
#define SYS_truncate SYS_truncate64
#endif

#ifdef SYS_stat64
#undef SYS_stat
#define SYS_stat SYS_stat64
#endif

#ifdef SYS_fstat64
#undef SYS_fstat
#define SYS_fstat SYS_fstat64
#endif

#ifdef SYS_lstat64
#undef SYS_lstat
#define SYS_lstat SYS_lstat64
#endif

#ifdef SYS_statfs64
#undef SYS_statfs
#define SYS_statfs SYS_statfs64
#endif

#ifdef SYS_fstatfs64
#undef SYS_fstatfs
#define SYS_fstatfs SYS_fstatfs64
#endif

#if defined(SYS_newfstatat)
#undef SYS_fstatat
#define SYS_fstatat SYS_newfstatat
#elif defined(SYS_fstatat64)
#undef SYS_fstatat
#define SYS_fstatat SYS_fstatat64
#endif

#ifdef SYS_ugetrlimit
#undef SYS_getrlimit
#define SYS_getrlimit SYS_ugetrlimit
#endif

#ifdef SYS__newselect
#undef SYS_select
#define SYS_select SYS__newselect
#endif

#ifdef SYS_pread64
#undef SYS_pread
#undef SYS_pwrite
#define SYS_pread SYS_pread64
#define SYS_pwrite SYS_pwrite64
#endif

#ifdef SYS_fadvise64_64
#undef SYS_fadvise
#define SYS_fadvise SYS_fadvise64_64
#endif

#ifdef SYS_sendfile64
#undef SYS_sendfile
#define SYS_sendfile SYS_sendfile64
#endif

/* socketcall calls */

#define __SC_socket      1
#define __SC_bind        2
#define __SC_connect     3
#define __SC_listen      4
#define __SC_accept      5
#define __SC_getsockname 6
#define __SC_getpeername 7
#define __SC_socketpair  8
#define __SC_send        9
#define __SC_recv        10
#define __SC_sendto      11
#define __SC_recvfrom    12
#define __SC_shutdown    13
#define __SC_setsockopt  14
#define __SC_getsockopt  15
#define __SC_sendmsg     16
#define __SC_recvmsg     17
#define __SC_accept4     18
#define __SC_recvmmsg    19
#define __SC_sendmmsg    20

#ifdef SYS_open
#define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE)
#define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open_cp2(x,pn,fl) __syscall_cp2(SYS_open, pn, (fl)|O_LARGEFILE)
#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
#else
#define __sys_open2(x,pn,fl) __syscall3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
#define __sys_open3(x,pn,fl,mo) __syscall4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
#endif

#define __sys_open(...) __SYSCALL_DISP(__sys_open,,__VA_ARGS__)
#define sys_open(...) __syscall_ret(__sys_open(__VA_ARGS__))

#define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__)
#define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__))

#endif


text:
#include "libc.h"

#ifdef USE_LIBC_ACCESSOR
struct __libc *__libc_loc()
{
	static struct __libc __libc;
	return &__libc;
}
#else
struct __libc __libc;
#endif

#ifdef BROKEN_VISIBILITY
__asm__(".hidden __libc");
#endif

size_t __hwcap;
size_t __sysinfo;
char *__progname=0, *__progname_full=0;

weak_alias(__progname, program_invocation_short_name);
weak_alias(__progname_full, program_invocation_name);


text:
#include "shgetc.h"

void __shlim(FILE *f, off_t lim)
{
	f->shlim = lim;
	f->shcnt = f->rend - f->rpos;
	if (lim && f->shcnt > lim)
		f->shend = f->rpos + lim;
	else
		f->shend = f->rend;
}

int __shgetc(FILE *f)
{
	int c;
	if (f->shlim && f->shcnt >= f->shlim || (c=__uflow(f)) < 0) {
		f->shend = 0;
		return EOF;
	}
	if (f->shlim && f->rend - f->rpos > f->shlim - f->shcnt - 1)
		f->shend = f->rpos + (f->shlim - f->shcnt - 1);
	else
		f->shend = f->rend;
	if (f->rend) f->shcnt += f->rend - f->rpos + 1;
	if (f->rpos[-1] != c) f->rpos[-1] = c;
	return c;
}


text:
	.global __syscall
	.type   __syscall,@function
__syscall:
	mr      0, 3                  # Save the system call number
	mr      3, 4                  # Shift the arguments: arg1
	mr      4, 5                  # arg2
	mr      5, 6                  # arg3
	mr      6, 7                  # arg4
	mr      7, 8                  # arg5
	mr      8, 9                  # arg6
	sc
	bnslr+ # return if not summary overflow
	#else error:
	# return negated value.
	neg 3, 3
	blr
	.end    __syscall
	.size   __syscall, .-__syscall


text:
.global __syscall
.type   __syscall, @function
__syscall:
	! The kernel syscall entry point documents that the trap number indicates
	! the number of arguments being passed, but it then ignores that information.
	! Since we do not actually know how many arguments are being passed, we will
	! say there are six, since that is the maximum we support here.
	mov r4, r3
	mov r5, r4
	mov r6, r5
	mov r7, r6
	mov.l @r15, r7
	mov.l @(4,r15), r0
	mov.l @(8,r15), r1
	trapa #22
	or r0, r0
	or r0, r0
	or r0, r0
	or r0, r0
	or r0, r0
	rts
	 nop


text:
.global __syscall
.type   __syscall,@function
__syscall:
	addi    r12, r5, 0              # Save the system call number
	add     r5, r6, r0              # Shift the arguments, arg1
	add     r6, r7, r0              # arg2
	add     r7, r8, r0              # arg3
	add     r8, r9, r0              # arg4
	add     r9, r10, r0             # arg5
	lwi     r10, r1, 28             # Get arg6.
	brki    r14, 0x8                # syscall
	rtsd    r15, 8
	nop


text:
.set    noreorder

.global __syscall
.type   __syscall,@function
__syscall:
	move    $2, $4
	move    $4, $5
	move    $5, $6
	move    $6, $7
	lw      $7, 16($sp)
	lw      $8, 20($sp)
	lw      $9, 24($sp)
	lw      $10,28($sp)
	subu    $sp, $sp, 32
	sw      $8, 16($sp)
	sw      $9, 20($sp)
	sw      $10,24($sp)
	sw      $2 ,28($sp)
	lw      $2, 28($sp)
	syscall
	beq     $7, $0, 1f
	addu    $sp, $sp, 32
	subu    $2, $0, $2
1:	jr      $ra
	nop


text:
.hidden __sysinfo

# The calling convention for __vsyscall has the syscall number
# and 5 args arriving as:  eax, edx, ecx, edi, esi, 4(%esp).
# This ensures that the inline asm in the C code never has to touch
# ebx or ebp (which are unavailable in PIC and frame-pointer-using
# code, respectively), and optimizes for size/simplicity in the caller.

.global __vsyscall
.type __vsyscall,@function
__vsyscall:
	push %edi
	push %ebx
	mov %edx,%ebx
	mov %edi,%edx
	mov 12(%esp),%edi
	push %eax
	call 1f
2:	mov %ebx,%edx
	pop %ebx
	pop %ebx
	pop %edi
	ret

1:	mov (%esp),%eax
	add $[__sysinfo-2b],%eax
	mov (%eax),%eax
	test %eax,%eax
	jz 1f
	push %eax
	mov 8(%esp),%eax
	ret                     # tail call to kernel vsyscall entry
1:	mov 4(%esp),%eax
	int $128
	ret

# The __vsyscall6 entry point is used only for 6-argument syscalls.
# Instead of passing the 5th argument on the stack, a pointer to the
# 5th and 6th arguments is passed. This is ugly, but there are no
# register constraints the inline asm could use that would make it
# possible to pass two arguments on the stack.

.global __vsyscall6
.type __vsyscall6,@function
__vsyscall6:
	push %ebp
	push %eax
	mov 12(%esp), %ebp
	mov (%ebp), %eax
	mov 4(%ebp), %ebp
	push %eax
	mov 4(%esp),%eax
	call __vsyscall
	pop %ebp
	pop %ebp
	pop %ebp
	ret

.global __syscall
.type __syscall,@function
__syscall:
	lea 24(%esp),%eax
	push %esi
	push %edi
	push %eax
	mov 16(%esp),%eax
	mov 20(%esp),%edx
	mov 24(%esp),%ecx
	mov 28(%esp),%edi
	mov 32(%esp),%esi
	call __vsyscall6
	pop %edi
	pop %edi
	pop %esi
	ret


text:
.global __syscall
.type __syscall,@function
__syscall:
	movq %rdi,%rax
	movq %rsi,%rdi
	movq %rdx,%rsi
	movq %rcx,%rdx
	movq %r8,%r10
	movq %r9,%r8
	movq 8(%rsp),%r9
	syscall
	ret


text:
.global __syscall
.type __syscall,%function
__syscall:
	mov ip,sp
	stmfd sp!,{r4,r5,r6,r7}
	mov r7,r0
	mov r0,r1
	mov r1,r2
	mov r2,r3
	ldmfd ip,{r3,r4,r5,r6}
	svc 0
	ldmfd sp!,{r4,r5,r6,r7}
	tst lr,#1
	moveq pc,lr
	bx lr


text:
.global __syscall
.type   __syscall,@function
__syscall:
	l.ori	r11, r3, 0
	l.lwz	r3, 0(r1)
	l.lwz	r4, 4(r1)
	l.lwz	r5, 8(r1)
	l.lwz	r6, 12(r1)
	l.lwz	r7, 16(r1)
	l.lwz	r8, 20(r1)
	l.sys	1
	l.jr	r9
	 l.nop


text:
#if 0
.global __syscall
.type __syscall,@function
__syscall:
	movq %rdi,%rax
	movq %rsi,%rdi
	movq %rdx,%rsi
	movq %rcx,%rdx
	movq %r8,%r10
	movq %r9,%r8
	movq 8(%rsp),%r9
	syscall
	ret
#endif


text:
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

size_t confstr(int name, char *buf, size_t len)
{
	const char *s = "";
	if (!name) {
		s = "/bin:/usr/bin";
	} else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>31U) {
		errno = EINVAL;
		return 0;
	}
	// snprintf is overkill but avoid wasting code size to implement
	// this completely useless function and its truncation semantics
	return snprintf(buf, len, "%s", s) + 1;
}


text:
#include <unistd.h>

long pathconf(const char *path, int name)
{
	return fpathconf(-1, name);
}


text:
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <sys/resource.h>
#include <signal.h>
#include <sys/sysinfo.h>
#include "syscall.h"
#include "libc.h"

#define JT(x) (-256|(x))
#define VER JT(1)
#define JT_ARG_MAX JT(2)
#define JT_MQ_PRIO_MAX JT(3)
#define JT_PAGE_SIZE JT(4)
#define JT_SEM_VALUE_MAX JT(5)
#define JT_NPROCESSORS_CONF JT(6)
#define JT_NPROCESSORS_ONLN JT(7)
#define JT_PHYS_PAGES JT(8)
#define JT_AVPHYS_PAGES JT(9)
#define JT_ZERO JT(10)

#define RLIM(x) (-32768|(RLIMIT_ ## x))

long sysconf(int name)
{
	static const short values[] = {
		[_SC_ARG_MAX] = JT_ARG_MAX,
		[_SC_CHILD_MAX] = RLIM(NPROC),
		[_SC_CLK_TCK] = 100,
		[_SC_NGROUPS_MAX] = 32,
		[_SC_OPEN_MAX] = RLIM(NOFILE),
		[_SC_STREAM_MAX] = -1,
		[_SC_TZNAME_MAX] = TZNAME_MAX,
		[_SC_JOB_CONTROL] = 1,
		[_SC_SAVED_IDS] = 1,
		[_SC_REALTIME_SIGNALS] = 1,
		[_SC_PRIORITY_SCHEDULING] = -1,
		[_SC_TIMERS] = VER,
		[_SC_ASYNCHRONOUS_IO] = VER,
		[_SC_PRIORITIZED_IO] = -1,
		[_SC_SYNCHRONIZED_IO] = -1,
		[_SC_FSYNC] = VER,
		[_SC_MAPPED_FILES] = VER,
		[_SC_MEMLOCK] = VER,
		[_SC_MEMLOCK_RANGE] = VER,
		[_SC_MEMORY_PROTECTION] = VER,
		[_SC_MESSAGE_PASSING] = VER,
		[_SC_SEMAPHORES] = VER,
		[_SC_SHARED_MEMORY_OBJECTS] = VER,
		[_SC_AIO_LISTIO_MAX] = -1,
		[_SC_AIO_MAX] = -1,
		[_SC_AIO_PRIO_DELTA_MAX] = JT_ZERO, /* ?? */
		[_SC_DELAYTIMER_MAX] = _POSIX_DELAYTIMER_MAX,
		[_SC_MQ_OPEN_MAX] = -1,
		[_SC_MQ_PRIO_MAX] = JT_MQ_PRIO_MAX,
		[_SC_VERSION] = VER,
		[_SC_PAGE_SIZE] = JT_PAGE_SIZE,
		[_SC_RTSIG_MAX] = _NSIG - 1 - 31 - 3,
		[_SC_SEM_NSEMS_MAX] = SEM_NSEMS_MAX,
		[_SC_SEM_VALUE_MAX] = JT_SEM_VALUE_MAX,
		[_SC_SIGQUEUE_MAX] = -1,
		[_SC_TIMER_MAX] = -1,
		[_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX,
		[_SC_BC_DIM_MAX] = _POSIX2_BC_DIM_MAX,
		[_SC_BC_SCALE_MAX] = _POSIX2_BC_SCALE_MAX,
		[_SC_BC_STRING_MAX] = _POSIX2_BC_STRING_MAX,
		[_SC_COLL_WEIGHTS_MAX] = COLL_WEIGHTS_MAX,
		[_SC_EXPR_NEST_MAX] = -1,
		[_SC_LINE_MAX] = -1,
		[_SC_RE_DUP_MAX] = RE_DUP_MAX,
		[_SC_2_VERSION] = VER,
		[_SC_2_C_BIND] = VER,
		[_SC_2_C_DEV] = -1,
		[_SC_2_FORT_DEV] = -1,
		[_SC_2_FORT_RUN] = -1,
		[_SC_2_SW_DEV] = -1,
		[_SC_2_LOCALEDEF] = -1,
		[_SC_IOV_MAX] = IOV_MAX,
		[_SC_THREADS] = VER,
		[_SC_THREAD_SAFE_FUNCTIONS] = VER,
		[_SC_GETGR_R_SIZE_MAX] = -1,
		[_SC_GETPW_R_SIZE_MAX] = -1,
		[_SC_LOGIN_NAME_MAX] = 256,
		[_SC_TTY_NAME_MAX] = TTY_NAME_MAX,
		[_SC_THREAD_DESTRUCTOR_ITERATIONS] = PTHREAD_DESTRUCTOR_ITERATIONS,
		[_SC_THREAD_KEYS_MAX] = PTHREAD_KEYS_MAX,
		[_SC_THREAD_STACK_MIN] = PTHREAD_STACK_MIN,
		[_SC_THREAD_THREADS_MAX] = -1,
		[_SC_THREAD_ATTR_STACKADDR] = VER,
		[_SC_THREAD_ATTR_STACKSIZE] = VER,
		[_SC_THREAD_PRIORITY_SCHEDULING] = VER,
		[_SC_THREAD_PRIO_INHERIT] = -1,
		[_SC_THREAD_PRIO_PROTECT] = -1,
		[_SC_THREAD_PROCESS_SHARED] = VER,
		[_SC_NPROCESSORS_CONF] = JT_NPROCESSORS_CONF,
		[_SC_NPROCESSORS_ONLN] = JT_NPROCESSORS_ONLN,
		[_SC_PHYS_PAGES] = JT_PHYS_PAGES,
		[_SC_AVPHYS_PAGES] = JT_AVPHYS_PAGES,
		[_SC_ATEXIT_MAX] = -1,
		[_SC_PASS_MAX] = -1,
		[_SC_XOPEN_VERSION] = _XOPEN_VERSION,
		[_SC_XOPEN_XCU_VERSION] = _XOPEN_VERSION,
		[_SC_XOPEN_UNIX] = 1,
		[_SC_XOPEN_CRYPT] = -1,
		[_SC_XOPEN_ENH_I18N] = 1,
		[_SC_XOPEN_SHM] = 1,
		[_SC_2_CHAR_TERM] = -1,
		[_SC_2_UPE] = -1,
		[_SC_XOPEN_XPG2] = -1,
		[_SC_XOPEN_XPG3] = -1,
		[_SC_XOPEN_XPG4] = -1,
		[_SC_NZERO] = NZERO,
		[_SC_XBS5_ILP32_OFF32] = -1,
		[_SC_XBS5_ILP32_OFFBIG] = sizeof(long)==4 ? 1 : JT_ZERO,
		[_SC_XBS5_LP64_OFF64] = sizeof(long)==8 ? 1 : JT_ZERO,
		[_SC_XBS5_LPBIG_OFFBIG] = -1,
		[_SC_XOPEN_LEGACY] = -1,
		[_SC_XOPEN_REALTIME] = -1,
		[_SC_XOPEN_REALTIME_THREADS] = -1,
		[_SC_ADVISORY_INFO] = VER,
		[_SC_BARRIERS] = VER,
		[_SC_CLOCK_SELECTION] = VER,
		[_SC_CPUTIME] = VER,
		[_SC_THREAD_CPUTIME] = VER,
		[_SC_MONOTONIC_CLOCK] = VER,
		[_SC_READER_WRITER_LOCKS] = VER,
		[_SC_SPIN_LOCKS] = VER,
		[_SC_REGEXP] = 1,
		[_SC_SHELL] = 1,
		[_SC_SPAWN] = VER,
		[_SC_SPORADIC_SERVER] = -1,
		[_SC_THREAD_SPORADIC_SERVER] = -1,
		[_SC_TIMEOUTS] = VER,
		[_SC_TYPED_MEMORY_OBJECTS] = -1,
		[_SC_2_PBS] = -1,
		[_SC_2_PBS_ACCOUNTING] = -1,
		[_SC_2_PBS_LOCATE] = -1,
		[_SC_2_PBS_MESSAGE] = -1,
		[_SC_2_PBS_TRACK] = -1,
		[_SC_SYMLOOP_MAX] = SYMLOOP_MAX,
		[_SC_STREAMS] = JT_ZERO,
		[_SC_2_PBS_CHECKPOINT] = -1,
		[_SC_V6_ILP32_OFF32] = -1,
		[_SC_V6_ILP32_OFFBIG] = sizeof(long)==4 ? 1 : JT_ZERO,
		[_SC_V6_LP64_OFF64] = sizeof(long)==8 ? 1 : JT_ZERO,
		[_SC_V6_LPBIG_OFFBIG] = -1,
		[_SC_HOST_NAME_MAX] = HOST_NAME_MAX,
		[_SC_TRACE] = -1,
		[_SC_TRACE_EVENT_FILTER] = -1,
		[_SC_TRACE_INHERIT] = -1,
		[_SC_TRACE_LOG] = -1,

		[_SC_IPV6] = VER,
		[_SC_RAW_SOCKETS] = VER,
		[_SC_V7_ILP32_OFF32] = -1,
		[_SC_V7_ILP32_OFFBIG] = sizeof(long)==4 ? 1 : JT_ZERO,
		[_SC_V7_LP64_OFF64] = sizeof(long)==8 ? 1 : JT_ZERO,
		[_SC_V7_LPBIG_OFFBIG] = -1,
		[_SC_SS_REPL_MAX] = -1,
		[_SC_TRACE_EVENT_NAME_MAX] = -1,
		[_SC_TRACE_NAME_MAX] = -1,
		[_SC_TRACE_SYS_MAX] = -1,
		[_SC_TRACE_USER_EVENT_MAX] = -1,
		[_SC_XOPEN_STREAMS] = JT_ZERO,
		[_SC_THREAD_ROBUST_PRIO_INHERIT] = -1,
		[_SC_THREAD_ROBUST_PRIO_PROTECT] = -1,
	};

	if (name >= sizeof(values)/sizeof(values[0]) || !values[name]) {
		errno = EINVAL;
		return -1;
	} else if (values[name] >= -1) {
		return values[name];
	} else if (values[name] < -256) {
		struct rlimit lim;
		getrlimit(values[name]&16383, &lim);
		return lim.rlim_cur > LONG_MAX ? LONG_MAX : lim.rlim_cur;
	}

	switch ((unsigned char)values[name]) {
	case VER & 255:
		return _POSIX_VERSION;
	case JT_ARG_MAX & 255:
		return ARG_MAX;
	case JT_MQ_PRIO_MAX & 255:
		return MQ_PRIO_MAX;
	case JT_PAGE_SIZE & 255:
		return PAGE_SIZE;
	case JT_SEM_VALUE_MAX & 255:
		return SEM_VALUE_MAX;
	case JT_NPROCESSORS_CONF & 255:
	case JT_NPROCESSORS_ONLN & 255: ;
		unsigned char set[128] = {1};
		int i, cnt;
		__syscall(SYS_sched_getaffinity, 0, sizeof set, set);
		for (i=cnt=0; i<sizeof set; i++)
			for (; set[i]; set[i]&=set[i]-1, cnt++);
		return cnt;
	case JT_PHYS_PAGES & 255:
	case JT_AVPHYS_PAGES & 255: ;
		unsigned long long mem;
		int __lsysinfo(struct sysinfo *);
		struct sysinfo si;
		__lsysinfo(&si);
		if (!si.mem_unit) si.mem_unit = 1;
		if (name==_SC_PHYS_PAGES) mem = si.totalram;
		else mem = si.freeram + si.bufferram;
		mem *= si.mem_unit;
		mem /= PAGE_SIZE;
		return (mem > LONG_MAX) ? LONG_MAX : mem;
	case JT_ZERO & 255:
		return 0;
	}
	return values[name];
}


text:
#include <unistd.h>
#include <limits.h>
#include <errno.h>

long fpathconf(int fd, int name)
{
	static const short values[] = {
		[_PC_LINK_MAX] = _POSIX_LINK_MAX,
		[_PC_MAX_CANON] = _POSIX_MAX_CANON,
		[_PC_MAX_INPUT] = _POSIX_MAX_INPUT,
		[_PC_NAME_MAX] = NAME_MAX,
		[_PC_PATH_MAX] = PATH_MAX,
		[_PC_PIPE_BUF] = PIPE_BUF,
		[_PC_CHOWN_RESTRICTED] = 1,
		[_PC_NO_TRUNC] = 1,
		[_PC_VDISABLE] = 0,
		[_PC_SYNC_IO] = 1,
		[_PC_ASYNC_IO] = -1,
		[_PC_PRIO_IO] = -1,
		[_PC_SOCK_MAXBUF] = -1,
		[_PC_FILESIZEBITS] = FILESIZEBITS,
		[_PC_REC_INCR_XFER_SIZE] = 4096,
		[_PC_REC_MAX_XFER_SIZE] = 4096,
		[_PC_REC_MIN_XFER_SIZE] = 4096,
		[_PC_REC_XFER_ALIGN] = 4096,
		[_PC_ALLOC_SIZE_MIN] = 4096,
		[_PC_SYMLINK_MAX] = SYMLINK_MAX,
		[_PC_2_SYMLINKS] = 1
	};
	if (name >= sizeof(values)/sizeof(values[0])) {
		errno = EINVAL;
		return -1;
	}
	return values[name];
}


text:
In principle, this memory allocator is roughly equivalent to Doug
Lea's dlmalloc with fine-grained locking.

malloc:

Uses a freelist binned by chunk size, with a bitmap to optimize
searching for the smallest non-empty bin which can satisfy an
allocation. If no free chunks are available, it creates a new chunk of
the requested size and attempts to merge it with any existing free
chunk immediately below the newly created chunk.

Whether the chunk was obtained from a bin or newly created, it's
likely to be larger than the requested allocation. malloc always
finishes its work by passing the new chunk to realloc, which will
split it into two chunks and free the tail portion.


text:
#include <malloc.h>

void *(*const __realloc_dep)(void *, size_t) = realloc;

struct chunk {
	size_t psize, csize;
	struct chunk *next, *prev;
};

#define OVERHEAD (2*sizeof(size_t))
#define CHUNK_SIZE(c) ((c)->csize & -2)
#define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD)

size_t malloc_usable_size(void *p)
{
	return CHUNK_SIZE(MEM_TO_CHUNK(p)) - OVERHEAD;
}


text:
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <errno.h>
#include "libc.h"

uintptr_t __brk(uintptr_t);

#define ALIGN 16

void *__simple_malloc(size_t n)
{
	static uintptr_t cur, brk;
	uintptr_t base, new;
	static int lock[2];
	size_t align=1;

	if (!n) n++;
	if (n > SIZE_MAX/2) goto toobig;

	while (align<n && align<ALIGN)
		align += align;
	n = n + align - 1 & -align;

	LOCK(lock);
	if (!cur) cur = brk = __brk(0)+16;
	base = cur + align-1 & -align;
	if (n > SIZE_MAX - PAGE_SIZE - base) goto fail;
	if (base+n > brk) {
		new = base+n + PAGE_SIZE-1 & -PAGE_SIZE;
		if (__brk(new) != new) goto fail;
		brk = new;
	}
	cur = base+n;
	UNLOCK(lock);

	return (void *)base;

fail:
	UNLOCK(lock);
toobig:
	errno = ENOMEM;
	return 0;
}

weak_alias(__simple_malloc, malloc);


text:
#include <stdlib.h>
#include <errno.h>

void *__memalign(size_t, size_t);

int posix_memalign(void **res, size_t align, size_t len)
{
	if (align < sizeof(void *)) return EINVAL;
	void *mem = __memalign(align, len);
	if (!mem) return errno;
	*res = mem;
	return 0;
}


text:
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include "libc.h"

/* This function should work with most dlmalloc-like chunk bookkeeping
 * systems, but it's only guaranteed to work with the native implementation
 * used in this library. */

void *__memalign(size_t align, size_t len)
{
	unsigned char *mem, *new, *end;
	size_t header, footer;

	if ((align & -align) != align) {
		errno = EINVAL;
		return NULL;
	}

	if (len > SIZE_MAX - align) {
		errno = ENOMEM;
		return NULL;
	}

	if (align <= 4*sizeof(size_t)) {
		if (!(mem = malloc(len)))
			return NULL;
		return mem;
	}

	if (!(mem = malloc(len + align-1)))
		return NULL;

	new = (void *)((uintptr_t)mem + align-1 & -align);
	if (new == mem) return mem;

	header = ((size_t *)mem)[-1];

	if (!(header & 7)) {
		((size_t *)new)[-2] = ((size_t *)mem)[-2] + (new-mem);
		((size_t *)new)[-1] = ((size_t *)mem)[-1] - (new-mem);
		return new;
	}

	end = mem + (header & -8);
	footer = ((size_t *)end)[-2];

	((size_t *)mem)[-1] = header&7 | new-mem;
	((size_t *)new)[-2] = footer&7 | new-mem;
	((size_t *)new)[-1] = header&7 | end-new;
	((size_t *)end)[-2] = footer&7 | end-new;

	free(mem);
	return new;
}

weak_alias(__memalign, memalign);


text:
#include <stdlib.h>

void *__memalign(size_t, size_t);

void *aligned_alloc(size_t align, size_t len)
{
	return __memalign(align, len);
}


text:
#include <stdint.h>
#include "syscall.h"

uintptr_t __brk(uintptr_t newbrk)
{
	return __syscall(SYS_brk, newbrk);
}


text:
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#include <errno.h>
#include <sys/mman.h>
#include "libc.h"
#include "atomic.h"
#include "pthread_impl.h"

#if defined(__GNUC__) && defined(__PIC__)
#define inline inline __attribute__((always_inline))
#endif

uintptr_t __brk(uintptr_t);
void *__mmap(void *, size_t, int, int, int, off_t);
int __munmap(void *, size_t);
void *__mremap(void *, size_t, size_t, int, ...);
int __madvise(void *, size_t, int);

struct chunk {
	size_t psize, csize;
	struct chunk *next, *prev;
};

struct bin {
	int lock[2];
	struct chunk *head;
	struct chunk *tail;
};

static struct {
	uintptr_t brk;
	size_t *heap;
	uint64_t binmap;
	struct bin bins[64];
	int brk_lock[2];
	int free_lock[2];
	unsigned mmap_step;
} mal;

#define SIZE_ALIGN (4*sizeof(size_t))
#define SIZE_MASK (-SIZE_ALIGN)
#define OVERHEAD (2*sizeof(size_t))
#define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN)
#define DONTCARE 16
#define RECLAIM 163840

#define CHUNK_SIZE(c) ((c)->csize & -2)
#define CHUNK_PSIZE(c) ((c)->psize & -2)
#define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c)))
#define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c)))
#define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD)
#define CHUNK_TO_MEM(c) (void *)((char *)(c) + OVERHEAD)
#define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head))

#define C_INUSE  ((size_t)1)

#define IS_MMAPPED(c) !((c)->csize & (C_INUSE))

/* Synchronization tools */

static inline void lock(volatile int *lk)
{
	if (libc.threads_minus_1)
		while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1);
}

static inline void unlock(volatile int *lk)
{
	if (lk[0]) {
		a_store(lk, 0);
		if (lk[1]) __wake(lk, 1, 1);
	}
}

static inline void lock_bin(int i)
{
	lock(mal.bins[i].lock);
	if (!mal.bins[i].head)
		mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i);
}

static inline void unlock_bin(int i)
{
	unlock(mal.bins[i].lock);
}

static int first_set(uint64_t x)
{
#if 1
	return a_ctz_64(x);
#else
	static const char debruijn64[64] = {
		0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
		62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
		63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
		51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
	};
	static const char debruijn32[32] = {
		0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13,
		31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14
	};
	if (sizeof(long) < 8) {
		uint32_t y = x;
		if (!y) {
			y = x>>32;
			return 32 + debruijn32[(y&-y)*0x076be629 >> 27];
		}
		return debruijn32[(y&-y)*0x076be629 >> 27];
	}
	return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58];
#endif
}

static int bin_index(size_t x)
{
	x = x / SIZE_ALIGN - 1;
	if (x <= 32) return x;
	if (x > 0x1c00) return 63;
	return ((union { float v; uint32_t r; }){(int)x}.r>>21) - 496;
}

static int bin_index_up(size_t x)
{
	x = x / SIZE_ALIGN - 1;
	if (x <= 32) return x;
	return ((union { float v; uint32_t r; }){(int)x}.r+0x1fffff>>21) - 496;
}

#if 0
void __dump_heap(int x)
{
	struct chunk *c;
	int i;
	for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c))
		fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n",
			c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)),
			c->csize & 15,
			NEXT_CHUNK(c)->psize & 15);
	for (i=0; i<64; i++) {
		if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) {
			fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head);
			if (!(mal.binmap & 1ULL<<i))
				fprintf(stderr, "missing from binmap!\n");
		} else if (mal.binmap & 1ULL<<i)
			fprintf(stderr, "binmap wrongly contains %d!\n", i);
	}
}
#endif

static struct chunk *expand_heap(size_t n)
{
	struct chunk *w;
	uintptr_t new;

	lock(mal.brk_lock);

	if (n > SIZE_MAX - mal.brk - 2*PAGE_SIZE) goto fail;
	new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE;
	n = new - mal.brk;

	if (__brk(new) != new) {
		size_t min = (size_t)PAGE_SIZE << mal.mmap_step/2;
		n += -n & PAGE_SIZE-1;
		if (n < min) n = min;
		void *area = __mmap(0, n, PROT_READ|PROT_WRITE,
			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
		if (area == MAP_FAILED) goto fail;

		mal.mmap_step++;
		area = (char *)area + SIZE_ALIGN - OVERHEAD;
		w = area;
		n -= SIZE_ALIGN;
		w->psize = 0 | C_INUSE;
		w->csize = n | C_INUSE;
		w = NEXT_CHUNK(w);
		w->psize = n | C_INUSE;
		w->csize = 0 | C_INUSE;

		unlock(mal.brk_lock);

		return area;
	}

	w = MEM_TO_CHUNK(new);
	w->psize = n | C_INUSE;
	w->csize = 0 | C_INUSE;

	w = MEM_TO_CHUNK(mal.brk);
	w->csize = n | C_INUSE;
	mal.brk = new;

	unlock(mal.brk_lock);

	return w;
fail:
	unlock(mal.brk_lock);
	errno = ENOMEM;
	return 0;
}

static int init_malloc(size_t n)
{
	static int init, waiters;
	int state;
	struct chunk *c;

	if (init == 2) return 0;

	while ((state=a_swap(&init, 1)) == 1)
		__wait(&init, &waiters, 1, 1);
	if (state) {
		a_store(&init, 2);
		return 0;
	}

	mal.brk = __brk(0);
#ifdef SHARED
	mal.brk = mal.brk + PAGE_SIZE-1 & -PAGE_SIZE;
#endif
	mal.brk = mal.brk + 2*SIZE_ALIGN-1 & -SIZE_ALIGN;

	c = expand_heap(n);

	if (!c) {
		a_store(&init, 0);
		if (waiters) __wake(&init, 1, 1);
		return -1;
	}

	mal.heap = (void *)c;
	c->psize = 0 | C_INUSE;
	free(CHUNK_TO_MEM(c));

	a_store(&init, 2);
	if (waiters) __wake(&init, -1, 1);
	return 1;
}

static int adjust_size(size_t *n)
{
	/* Result of pointer difference must fit in ptrdiff_t. */
	if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) {
		if (*n) {
			errno = ENOMEM;
			return -1;
		} else {
			*n = SIZE_ALIGN;
			return 0;
		}
	}
	*n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
	return 0;
}

static void unbin(struct chunk *c, int i)
{
	if (c->prev == c->next)
		a_and_64(&mal.binmap, ~(1ULL<<i));
	c->prev->next = c->next;
	c->next->prev = c->prev;
	c->csize |= C_INUSE;
	NEXT_CHUNK(c)->psize |= C_INUSE;
}

static int alloc_fwd(struct chunk *c)
{
	int i;
	size_t k;
	while (!((k=c->csize) & C_INUSE)) {
		i = bin_index(k);
		lock_bin(i);
		if (c->csize == k) {
			unbin(c, i);
			unlock_bin(i);
			return 1;
		}
		unlock_bin(i);
	}
	return 0;
}

static int alloc_rev(struct chunk *c)
{
	int i;
	size_t k;
	while (!((k=c->psize) & C_INUSE)) {
		i = bin_index(k);
		lock_bin(i);
		if (c->psize == k) {
			unbin(PREV_CHUNK(c), i);
			unlock_bin(i);
			return 1;
		}
		unlock_bin(i);
	}
	return 0;
}

/* pretrim - trims a chunk _prior_ to removing it from its bin.
 * Must be called with i as the ideal bin for size n, j the bin
 * for the _free_ chunk self, and bin j locked. */
static int pretrim(struct chunk *self, size_t n, int i, int j)
{
	size_t n1;
	struct chunk *next, *split;

	/* We cannot pretrim if it would require re-binning. */
	if (j < 40) return 0;
	if (j < i+3) {
		if (j != 63) return 0;
		n1 = CHUNK_SIZE(self);
		if (n1-n <= MMAP_THRESHOLD) return 0;
	} else {
		n1 = CHUNK_SIZE(self);
	}
	if (bin_index(n1-n) != j) return 0;

	next = NEXT_CHUNK(self);
	split = (void *)((char *)self + n);

	split->prev = self->prev;
	split->next = self->next;
	split->prev->next = split;
	split->next->prev = split;
	split->psize = n | C_INUSE;
	split->csize = n1-n;
	next->psize = n1-n;
	self->csize = n | C_INUSE;
	return 1;
}

static void trim(struct chunk *self, size_t n)
{
	size_t n1 = CHUNK_SIZE(self);
	struct chunk *next, *split;

	if (n >= n1 - DONTCARE) return;

	next = NEXT_CHUNK(self);
	split = (void *)((char *)self + n);

	split->psize = n | C_INUSE;
	split->csize = n1-n | C_INUSE;
	next->psize = n1-n | C_INUSE;
	self->csize = n | C_INUSE;

	free(CHUNK_TO_MEM(split));
}

void *malloc(size_t n)
{
	struct chunk *c;
	int i, j;

	if (adjust_size(&n) < 0) return 0;

	if (n > MMAP_THRESHOLD) {
		size_t len = n + OVERHEAD + PAGE_SIZE - 1 & -PAGE_SIZE;
		char *base = __mmap(0, len, PROT_READ|PROT_WRITE,
			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
		if (base == (void *)-1) return 0;
		c = (void *)(base + SIZE_ALIGN - OVERHEAD);
		c->csize = len - (SIZE_ALIGN - OVERHEAD);
		c->psize = SIZE_ALIGN - OVERHEAD;
		return CHUNK_TO_MEM(c);
	}

	i = bin_index_up(n);
	for (;;) {
		uint64_t mask = mal.binmap & -(1ULL<<i);
		if (!mask) {
			if (init_malloc(n) > 0) continue;
			c = expand_heap(n);
			if (!c) return 0;
			if (alloc_rev(c)) {
				struct chunk *x = c;
				c = PREV_CHUNK(c);
				NEXT_CHUNK(x)->psize = c->csize =
					x->csize + CHUNK_SIZE(c);
			}
			break;
		}
		j = first_set(mask);
		lock_bin(j);
		c = mal.bins[j].head;
		if (c != BIN_TO_CHUNK(j) && j == bin_index(c->csize)) {
			if (!pretrim(c, n, i, j)) unbin(c, j);
			unlock_bin(j);
			break;
		}
		unlock_bin(j);
	}

	/* Now patch up in case we over-allocated */
	trim(c, n);

	return CHUNK_TO_MEM(c);
}

void *realloc(void *p, size_t n)
{
	struct chunk *self, *next;
	size_t n0, n1;
	void *new;

	if (!p) return malloc(n);

	if (adjust_size(&n) < 0) return 0;

	self = MEM_TO_CHUNK(p);
	n1 = n0 = CHUNK_SIZE(self);

	if (IS_MMAPPED(self)) {
		size_t extra = self->psize;
		char *base = (char *)self - extra;
		size_t oldlen = n0 + extra;
		size_t newlen = n + extra;
		/* Crash on realloc of freed chunk */
		if (extra & 1) a_crash();
		if (newlen < PAGE_SIZE && (new = malloc(n))) {
			memcpy(new, p, n-OVERHEAD);
			free(p);
			return new;
		}
		newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE;
		if (oldlen == newlen) return p;
		base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE);
		if (base == (void *)-1)
			return newlen < oldlen ? p : 0;
		self = (void *)(base + extra);
		self->csize = newlen - extra;
		return CHUNK_TO_MEM(self);
	}

	next = NEXT_CHUNK(self);

	/* Crash on corrupted footer (likely from buffer overflow) */
	if (next->psize != self->csize) a_crash();

	/* Merge adjacent chunks if we need more space. This is not
	 * a waste of time even if we fail to get enough space, because our
	 * subsequent call to free would otherwise have to do the merge. */
	if (n > n1 && alloc_fwd(next)) {
		n1 += CHUNK_SIZE(next);
		next = NEXT_CHUNK(next);
	}
	/* FIXME: find what's wrong here and reenable it..? */
	if (0 && n > n1 && alloc_rev(self)) {
		self = PREV_CHUNK(self);
		n1 += CHUNK_SIZE(self);
	}
	self->csize = n1 | C_INUSE;
	next->psize = n1 | C_INUSE;

	/* If we got enough space, split off the excess and return */
	if (n <= n1) {
		//memmove(CHUNK_TO_MEM(self), p, n0-OVERHEAD);
		trim(self, n);
		return CHUNK_TO_MEM(self);
	}

	/* As a last resort, allocate a new chunk and copy to it. */
	new = malloc(n-OVERHEAD);
	if (!new) return 0;
	memcpy(new, p, n0-OVERHEAD);
	free(CHUNK_TO_MEM(self));
	return new;
}

void free(void *p)
{
	struct chunk *self = MEM_TO_CHUNK(p);
	struct chunk *next;
	size_t final_size, new_size, size;
	int reclaim=0;
	int i;

	if (!p) return;

	if (IS_MMAPPED(self)) {
		size_t extra = self->psize;
		char *base = (char *)self - extra;
		size_t len = CHUNK_SIZE(self) + extra;
		/* Crash on double free */
		if (extra & 1) a_crash();
		__munmap(base, len);
		return;
	}

	final_size = new_size = CHUNK_SIZE(self);
	next = NEXT_CHUNK(self);

	/* Crash on corrupted footer (likely from buffer overflow) */
	if (next->psize != self->csize) a_crash();

	for (;;) {
		/* Replace middle of large chunks with fresh zero pages */
		if (reclaim && (self->psize & next->csize & C_INUSE)) {
			uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE;
			uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE;
#if 1
			__madvise((void *)a, b-a, MADV_DONTNEED);
#else
			__mmap((void *)a, b-a, PROT_READ|PROT_WRITE,
				MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
#endif
		}

		if (self->psize & next->csize & C_INUSE) {
			self->csize = final_size | C_INUSE;
			next->psize = final_size | C_INUSE;
			i = bin_index(final_size);
			lock_bin(i);
			lock(mal.free_lock);
			if (self->psize & next->csize & C_INUSE)
				break;
			unlock(mal.free_lock);
			unlock_bin(i);
		}

		if (alloc_rev(self)) {
			self = PREV_CHUNK(self);
			size = CHUNK_SIZE(self);
			final_size += size;
			if (new_size+size > RECLAIM && (new_size+size^size) > size)
				reclaim = 1;
		}

		if (alloc_fwd(next)) {
			size = CHUNK_SIZE(next);
			final_size += size;
			if (new_size+size > RECLAIM && (new_size+size^size) > size)
				reclaim = 1;
			next = NEXT_CHUNK(next);
		}
	}

	self->csize = final_size;
	next->psize = final_size;
	unlock(mal.free_lock);

	self->next = BIN_TO_CHUNK(i);
	self->prev = mal.bins[i].tail;
	self->next->prev = self;
	self->prev->next = self;

	if (!(mal.binmap & 1ULL<<i))
		a_or_64(&mal.binmap, 1ULL<<i);

	unlock_bin(i);
}


text:
#include <stdlib.h>
#include <errno.h>

void *calloc(size_t m, size_t n)
{
	void *p;
	size_t *z;
	if (n && m > (size_t)-1/n) {
		errno = ENOMEM;
		return 0;
	}
	n *= m;
	p = malloc(n);
	if (!p) return 0;
	/* Only do this for non-mmapped chunks */
	if (((size_t *)p)[-1] & 7) {
		/* Only write words that are not already zero */
		m = (n + sizeof *z - 1)/sizeof *z;
		for (z=p; m; m--, z++) if (*z) *z=0;
	}
	return p;
}


text:
#include <stdlib.h>
#include "libc.h"

static void dummy() { }
weak_alias(dummy, __funcs_on_quick_exit);

_Noreturn void quick_exit(int code)
{
	__funcs_on_quick_exit();
	_Exit(code);
}


text:
#include <stdlib.h>
#include <stdint.h>
#include "libc.h"

static void dummy()
{
}

/* atexit.c and __stdio_exit.c override these. the latter is linked
 * as a consequence of linking either __toread.c or __towrite.c. */
weak_alias(dummy, __funcs_on_exit);
weak_alias(dummy, __stdio_exit);

#ifndef SHARED
weak_alias(dummy, _fini);
extern void (*const __fini_array_start)() __attribute__((weak));
extern void (*const __fini_array_end)() __attribute__((weak));
#endif

_Noreturn void exit(int code)
{
	__funcs_on_exit();

#ifndef SHARED
	uintptr_t a = (uintptr_t)&__fini_array_end;
	for (; a>(uintptr_t)&__fini_array_start; a-=sizeof(void(*)()))
		(*(void (**)())(a-sizeof(void(*)())))();
	_fini();
#endif

	__stdio_exit();

	_Exit(code);
}


text:
#include <stdlib.h>
#include <signal.h>
#include "syscall.h"

_Noreturn void abort(void)
{
	raise(SIGABRT);
	raise(SIGKILL);
	for (;;);
}


text:
#include <stdlib.h>
#include "syscall.h"

_Noreturn void _Exit(int ec)
{
	__syscall(SYS_exit_group, ec);
	for (;;) __syscall(SYS_exit, ec);
}


text:
#include <stdlib.h>
#include <stdint.h>
#include "libc.h"

/* Ensure that at least 32 atexit handlers can be registered without malloc */
#define COUNT 32

static struct fl
{
	struct fl *next;
	void (*f[COUNT])(void *);
	void *a[COUNT];
} builtin, *head;

static int lock[2];

void __funcs_on_exit()
{
	int i;
	void (*func)(void *), *arg;
	LOCK(lock);
	for (; head; head=head->next) for (i=COUNT-1; i>=0; i--) {
		if (!head->f[i]) continue;
		func = head->f[i];
		arg = head->a[i];
		head->f[i] = 0;
		UNLOCK(lock);
		func(arg);
		LOCK(lock);
	}
}

void __cxa_finalize(void *dso)
{
}

int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
{
	int i;

	LOCK(lock);

	/* Defer initialization of head so it can be in BSS */
	if (!head) head = &builtin;

	/* If the current function list is full, add a new one */
	if (head->f[COUNT-1]) {
		struct fl *new_fl = calloc(sizeof(struct fl), 1);
		if (!new_fl) {
			UNLOCK(lock);
			return -1;
		}
		new_fl->next = head;
		head = new_fl;
	}

	/* Append function to the list. */
	for (i=0; i<COUNT && head->f[i]; i++);
	head->f[i] = func;
	head->a[i] = arg;

	UNLOCK(lock);
	return 0;
}

static void call(void *p)
{
	((void (*)(void))(uintptr_t)p)();
}

int atexit(void (*func)(void))
{
	return __cxa_atexit(call, (void *)(uintptr_t)func, 0);
}


text:
#include <stdlib.h>
#include "libc.h"

#define COUNT 32

static void (*funcs[COUNT])(void);
static int count;
static int lock[2];

void __funcs_on_quick_exit()
{
	void (*func)(void);
	LOCK(lock);
	while (count > 0) {
		func = funcs[--count];
		UNLOCK(lock);
		func();
		LOCK(lock);
	}
}

int at_quick_exit(void (*func)(void))
{
	if (count == 32) return -1;
	LOCK(lock);
	funcs[count++] = func;
	UNLOCK(lock);
	return 0;
}


text:
#include <stdio.h>
#include <stdlib.h>

void __assert_fail(const char *expr, const char *file, int line, const char *func)
{
	fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line);
	fflush(NULL);
	abort();
}


text:
#include <spawn.h>
#include <stdlib.h>
#include <errno.h>
#include "fdop.h"

int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, int srcfd, int fd)
{
	struct fdop *op = malloc(sizeof *op);
	if (!op) return ENOMEM;
	op->cmd = FDOP_DUP2;
	op->srcfd = srcfd;
	op->fd = fd;
	if ((op->next = fa->__actions)) op->next->prev = op;
	op->prev = 0;
	fa->__actions = op;
	return 0;
}


text:
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <spawn.h>
#include <errno.h>
#include "pthread_impl.h"
#include "libc.h"

extern char **__environ;

int system(const char *cmd)
{
	pid_t pid;
	sigset_t old, reset;
	struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
	int status = 0x7f00, ret;
	posix_spawnattr_t attr;

	pthread_testcancel();

	if (!cmd) return 1;

	sigaction(SIGINT, &sa, &oldint);
	sigaction(SIGQUIT, &sa, &oldquit);
	sigaddset(&sa.sa_mask, SIGCHLD);
	sigprocmask(SIG_BLOCK, &sa.sa_mask, &old);

	sigemptyset(&reset);
	if (oldint.sa_handler != SIG_IGN) sigaddset(&reset, SIGINT);
	if (oldquit.sa_handler != SIG_IGN) sigaddset(&reset, SIGQUIT);
	posix_spawnattr_init(&attr);
	posix_spawnattr_setsigmask(&attr, &old);
	posix_spawnattr_setsigdefault(&attr, &reset);
	posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);
	ret = posix_spawn(&pid, "/bin/sh", 0, &attr,
		(char *[]){"sh", "-c", (char *)cmd, 0}, __environ);
	posix_spawnattr_destroy(&attr);

	if (!ret) while (waitpid(pid, &status, 0)<0 && errno == EINTR);
	sigaction(SIGINT, &oldint, NULL);
	sigaction(SIGQUIT, &oldquit, NULL);
	sigprocmask(SIG_SETMASK, &old, NULL);

	if (ret) errno = ret;
	return status;
}


text:
#include <sys/wait.h>
#include "syscall.h"
#include "libc.h"

int waitid(idtype_t type, id_t id, siginfo_t *info, int options)
{
	return syscall_cp(SYS_waitid, type, id, info, options, 0);
}


text:
#include <spawn.h>
#include <unistd.h>

int __execvpe(const char *, char *const *, char *const *);

int __posix_spawnx(pid_t *restrict, const char *restrict,
	int (*)(const char *, char *const *, char *const *),
	const posix_spawn_file_actions_t *,
	const posix_spawnattr_t *restrict, char *const *restrict, char *const *restrict);

int posix_spawnp(pid_t *restrict res, const char *restrict file,
	const posix_spawn_file_actions_t *fa,
	const posix_spawnattr_t *restrict attr,
	char *const argv[restrict], char *const envp[restrict])
{
	return __posix_spawnx(res, file, __execvpe, fa, attr, argv, envp);
}


text:
#include <spawn.h>
#include <stdlib.h>
#include <errno.h>
#include "fdop.h"

int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, int fd)
{
	struct fdop *op = malloc(sizeof *op);
	if (!op) return ENOMEM;
	op->cmd = FDOP_CLOSE;
	op->fd = fd;
	if ((op->next = fa->__actions)) op->next->prev = op;
	op->prev = 0;
	fa->__actions = op;
	return 0;
}


text:
#define FDOP_CLOSE 1
#define FDOP_DUP2 2
#define FDOP_OPEN 3

struct fdop {
	struct fdop *next, *prev;
	int cmd, fd, srcfd, oflag;
	mode_t mode;
	char path[];
};


text:
#include <spawn.h>

int posix_spawnattr_setsigmask(posix_spawnattr_t *restrict attr, const sigset_t *restrict mask)
{
	attr->__mask = *mask;
	return 0;
}


text:
#include <spawn.h>

int posix_spawnattr_init(posix_spawnattr_t *attr)
{
	*attr = (posix_spawnattr_t){ 0 };
	return 0;
}


text:
#include <sys/wait.h>
#include "syscall.h"
#include "libc.h"

pid_t waitpid(pid_t pid, int *status, int options)
{
	return syscall_cp(SYS_wait4, pid, status, options, 0);
}


text:
#include <spawn.h>

int posix_spawnattr_getpgroup(const posix_spawnattr_t *restrict attr, pid_t *restrict pgrp)
{
	*pgrp = attr->__pgrp;
	return 0;
}


text:
#define _GNU_SOURCE
#include <spawn.h>
#include <sched.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "syscall.h"
#include "pthread_impl.h"
#include "fdop.h"
#include "libc.h"

struct args {
	int p[2];
	sigset_t oldmask;
	const char *path;
	int (*exec)(const char *, char *const *, char *const *);
	const posix_spawn_file_actions_t *fa;
	const posix_spawnattr_t *restrict attr;
	char *const *argv, *const *envp;
};

void __get_handler_set(sigset_t *);

static int __sys_dup2(int old, int new)
{
#ifdef SYS_dup2
	return __syscall(SYS_dup2, old, new);
#else
	if (old==new) {
		int r = __syscall(SYS_fcntl, old, F_GETFD);
		return r<0 ? r : old;
	} else {
		return __syscall(SYS_dup3, old, new, 0);
	}
#endif
}

static int child(void *args_vp)
{
	int i, ret;
	struct sigaction sa = {0};
	struct args *args = args_vp;
	int p = args->p[1];
	const posix_spawn_file_actions_t *fa = args->fa;
	const posix_spawnattr_t *restrict attr = args->attr;
	sigset_t hset;

	close(args->p[0]);

	/* All signal dispositions must be either SIG_DFL or SIG_IGN
	 * before signals are unblocked. Otherwise a signal handler
	 * from the parent might get run in the child while sharing
	 * memory, with unpredictable and dangerous results. To
	 * reduce overhead, sigaction has tracked for us which signals
	 * potentially have a signal handler. */
	__get_handler_set(&hset);
	for (i=1; i<_NSIG; i++) {
		if ((attr->__flags & POSIX_SPAWN_SETSIGDEF)
		     && sigismember(&attr->__def, i)) {
			sa.sa_handler = SIG_DFL;
		} else if (sigismember(&hset, i)) {
			if (i-32<3U) {
				sa.sa_handler = SIG_IGN;
			} else {
				__libc_sigaction(i, 0, &sa);
				if (sa.sa_handler==SIG_IGN) continue;
				sa.sa_handler = SIG_DFL;
			}
		} else {
			continue;
		}
		__libc_sigaction(i, &sa, 0);
	}

	if (attr->__flags & POSIX_SPAWN_SETPGROUP)
		if ((ret=__syscall(SYS_setpgid, 0, attr->__pgrp)))
			goto fail;

	/* Use syscalls directly because the library functions attempt
	 * to do a multi-threaded synchronized id-change, which would
	 * trash the parent's state. */
	if (attr->__flags & POSIX_SPAWN_RESETIDS)
		if ((ret=__syscall(SYS_setgid, __syscall(SYS_getgid))) ||
		    (ret=__syscall(SYS_setuid, __syscall(SYS_getuid))) )
			goto fail;

	if (fa && fa->__actions) {
		struct fdop *op;
		int fd;
		for (op = fa->__actions; op->next; op = op->next);
		for (; op; op = op->prev) {
			/* It's possible that a file operation would clobber
			 * the pipe fd used for synchronizing with the
			 * parent. To avoid that, we dup the pipe onto
			 * an unoccupied fd. */
			if (op->fd == p) {
				ret = __syscall(SYS_dup, p);
				if (ret < 0) goto fail;
				__syscall(SYS_close, p);
				p = ret;
			}
			switch(op->cmd) {
			case FDOP_CLOSE:
				if ((ret=__syscall(SYS_close, op->fd)))
					goto fail;
				break;
			case FDOP_DUP2:
				if ((ret=__sys_dup2(op->srcfd, op->fd))<0)
					goto fail;
				break;
			case FDOP_OPEN:
				fd = __sys_open(op->path, op->oflag, op->mode);
				if ((ret=fd) < 0) goto fail;
				if (fd != op->fd) {
					if ((ret=__sys_dup2(fd, op->fd))<0)
						goto fail;
					__syscall(SYS_close, fd);
				}
				break;
			}
		}
	}

	/* Close-on-exec flag may have been lost if we moved the pipe
	 * to a different fd. We don't use F_DUPFD_CLOEXEC above because
	 * it would fail on older kernels and atomicity is not needed --
	 * in this process there are no threads or signal handlers. */
	__syscall(SYS_fcntl, p, F_SETFD, FD_CLOEXEC);

	pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
		? &attr->__mask : &args->oldmask, 0);

	args->exec(args->path, args->argv, args->envp);
	ret = -errno;

fail:
	/* Since sizeof errno < PIPE_BUF, the write is atomic. */
	ret = -ret;
	if (ret) while (write(p, &ret, sizeof ret) < 0);
	_exit(127);
}

int __posix_spawnx(pid_t *restrict res, const char *restrict path,
	int (*exec)(const char *, char *const *, char *const *),
	const posix_spawn_file_actions_t *fa,
	const posix_spawnattr_t *restrict attr,
	char *const argv[restrict], char *const envp[restrict])
{
	pid_t pid;
	char stack[1024];
	int ec=0, cs;
	struct args args;

	if (pipe2(args.p, O_CLOEXEC))
		return errno;

	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);

	args.path = path;
	args.exec = exec;
	args.fa = fa;
	args.attr = attr ? attr : &(const posix_spawnattr_t){0};
	args.argv = argv;
	args.envp = envp;
	pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask);

	pid = __clone(child, stack+sizeof stack,
		CLONE_VM|CLONE_VFORK|SIGCHLD, &args);
	close(args.p[1]);

	if (pid > 0) {
		if (read(args.p[0], &ec, sizeof ec) != sizeof ec) ec = 0;
		else waitpid(pid, &(int){0}, 0);
	} else {
		ec = -pid;
	}

	close(args.p[0]);

	if (!ec && res) *res = pid;

	pthread_sigmask(SIG_SETMASK, &args.oldmask, 0);
	pthread_setcancelstate(cs, 0);

	return ec;
}

int posix_spawn(pid_t *restrict res, const char *restrict path,
	const posix_spawn_file_actions_t *fa,
	const posix_spawnattr_t *restrict attr,
	char *const argv[restrict], char *const envp[restrict])
{
	return __posix_spawnx(res, path, execve, fa, attr, argv, envp);
}


text:
#include <spawn.h>

int posix_spawnattr_getsigmask(const posix_spawnattr_t *restrict attr, sigset_t *restrict mask)
{
	*mask = attr->__mask;
	return 0;
}


text:
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include "libc.h"

extern char **__environ;

int __execvpe(const char *file, char *const argv[], char *const envp[])
{
	const char *p, *z, *path = getenv("PATH");
	size_t l, k;

	errno = ENOENT;
	if (!*file) return -1;

	if (strchr(file, '/'))
		return execve(file, argv, envp);

	if (!path) path = "/usr/local/bin:/bin:/usr/bin";
	k = strnlen(file, NAME_MAX+1);
	if (k > NAME_MAX) {
		errno = ENAMETOOLONG;
		return -1;
	}
	l = strnlen(path, PATH_MAX-1)+1;

	for(p=path; ; p=z) {
		char b[l+k+1];
		z = strchr(p, ':');
		if (!z) z = p+strlen(p);
		if (z-p >= l) {
			if (!*z++) break;
			continue;
		}
		memcpy(b, p, z-p);
		b[z-p] = '/';
		memcpy(b+(z-p)+(z>p), file, k+1);
		execve(b, argv, envp);
		if (errno != ENOENT) return -1;
		if (!*z++) break;
	}
	return -1;
}

int execvp(const char *file, char *const argv[])
{
	return __execvpe(file, argv, __environ);
}

weak_alias(__execvpe, execvpe);


text:
#include <unistd.h>
#include <stdarg.h>

int execlp(const char *file, const char *argv0, ...)
{
	int argc;
	va_list ap;
	va_start(ap, argv0);
	for (argc=1; va_arg(ap, const char *); argc++);
	va_end(ap);
	{
		int i;
		char *argv[argc+1];
		va_start(ap, argv0);
		argv[0] = (char *)argv0;
		for (i=1; i<argc; i++)
			argv[i] = va_arg(ap, char *);
		argv[i] = NULL;
		va_end(ap);
		return execvp(file, argv);
	}
}


text:
#include <spawn.h>
#include <sched.h>
#include <errno.h>

int posix_spawnattr_getschedparam(const posix_spawnattr_t *restrict attr,
	struct sched_param *restrict schedparam)
{
	return ENOSYS;
}

int posix_spawnattr_setschedparam(posix_spawnattr_t *restrict attr,
	const struct sched_param *restrict schedparam)
{
	return ENOSYS;
}

int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *restrict attr, int *restrict policy)
{
	return ENOSYS;
}

int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr, int policy)
{
	return ENOSYS;
}


text:
#include <spawn.h>

int posix_spawnattr_getflags(const posix_spawnattr_t *restrict attr, short *restrict flags)
{
	*flags = attr->__flags;
	return 0;
}


text:
#include <unistd.h>

extern char **__environ;

int execv(const char *path, char *const argv[])
{
	return execve(path, argv, __environ);
}


text:
#include <unistd.h>
#include <stdarg.h>

int execl(const char *path, const char *argv0, ...)
{
	int argc;
	va_list ap;
	va_start(ap, argv0);
	for (argc=1; va_arg(ap, const char *); argc++);
	va_end(ap);
	{
		int i;
		char *argv[argc+1];
		va_start(ap, argv0);
		argv[0] = (char *)argv0;
		for (i=1; i<argc; i++)
			argv[i] = va_arg(ap, char *);
		argv[i] = NULL;
		va_end(ap);
		return execv(path, argv);
	}
}


text:
#include <unistd.h>
#include "syscall.h"

int execve(const char *path, char *const argv[], char *const envp[])
{
	/* do we need to use environ if envp is null? */
	return syscall(SYS_execve, path, argv, envp);
}


text:
#include <spawn.h>

int posix_spawnattr_destroy(posix_spawnattr_t *attr)
{
	return 0;
}


text:
#include <unistd.h>
#include <errno.h>

void __procfdname(char *, unsigned);

int fexecve(int fd, char *const argv[], char *const envp[])
{
	char buf[15 + 3*sizeof(int)];
	__procfdname(buf, fd);
	execve(buf, argv, envp);
	if (errno == ENOENT) errno = EBADF;
	return -1;
}


text:
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include "syscall.h"
#include "libc.h"
#include "pthread_impl.h"

static void dummy(int x)
{
}

weak_alias(dummy, __fork_handler);

pid_t fork(void)
{
	pid_t ret;
	sigset_t set;
	__fork_handler(-1);
	__block_all_sigs(&set);
#ifdef SYS_fork
	ret = syscall(SYS_fork);
#else
	ret = syscall(SYS_clone, SIGCHLD, 0);
#endif
	if (libc.has_thread_pointer && !ret) {
		pthread_t self = __pthread_self();
		self->tid = __syscall(SYS_gettid);
		memset(&self->robust_list, 0, sizeof self->robust_list);
		libc.threads_minus_1 = 0;
	}
	__restore_sigs(&set);
	__fork_handler(!ret);
	return ret;
}


text:
#define _GNU_SOURCE
#include <unistd.h>
#include <signal.h>
#include "syscall.h"
#include "libc.h"

pid_t __vfork(void)
{
	/* vfork syscall cannot be made from C code */
#ifdef SYS_fork
	return syscall(SYS_fork);
#else
	return syscall(SYS_clone, SIGCHLD, 0);
#endif
}

weak_alias(__vfork, vfork);


text:
#include <unistd.h>
#include <stdarg.h>

int execle(const char *path, const char *argv0, ...)
{
	int argc;
	va_list ap;
	va_start(ap, argv0);
	for (argc=1; va_arg(ap, const char *); argc++);
	va_end(ap);
	{
		int i;
		char *argv[argc+1];
		char **envp;
		va_start(ap, argv0);
		argv[0] = (char *)argv0;
		for (i=1; i<=argc; i++)
			argv[i] = va_arg(ap, char *);
		envp = va_arg(ap, char **);
		va_end(ap);
		return execve(path, argv, envp);
	}
}


text:
#include <spawn.h>

int posix_spawnattr_getsigdefault(const posix_spawnattr_t *restrict attr, sigset_t *restrict def)
{
	*def = attr->__def;
	return 0;
}


text:
#include <spawn.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "fdop.h"

int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *restrict fa, int fd, const char *restrict path, int flags, mode_t mode)
{
	struct fdop *op = malloc(sizeof *op + strlen(path) + 1);
	if (!op) return ENOMEM;
	op->cmd = FDOP_OPEN;
	op->fd = fd;
	op->oflag = flags;
	op->mode = mode;
	strcpy(op->path, path);
	if ((op->next = fa->__actions)) op->next->prev = op;
	op->prev = 0;
	fa->__actions = op;
	return 0;
}


text:
#include <spawn.h>
#include <stdlib.h>
#include "fdop.h"

int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa)
{
	struct fdop *op = fa->__actions, *next;
	while (op) {
		next = op->next;
		free(op);
		op = next;
	}
	return 0;
}


text:
#include <spawn.h>

int posix_spawnattr_setsigdefault(posix_spawnattr_t *restrict attr, const sigset_t *restrict def)
{
	attr->__def = *def;
	return 0;
}


text:
#include <sys/wait.h>

pid_t wait(int *status)
{
	return waitpid((pid_t)-1, status, 0);
}


text:
#include <spawn.h>

int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgrp)
{
	attr->__pgrp = pgrp;
	return 0;
}


text:
#include <spawn.h>

int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
{
	attr->__flags = flags;
	return 0;
}


text:
#include <spawn.h>

int posix_spawn_file_actions_init(posix_spawn_file_actions_t *fa)
{
	fa->__actions = 0;
	return 0;
}


text:
.global __vfork
.weak vfork
.type __vfork,@function
.type vfork,@function
__vfork:
vfork:
	pop %edx
	mov $190,%eax
	int $128
	push %edx
	push %eax
	call __syscall_ret
	pop %edx
	ret


text:
.global __vfork
.weak vfork
.type __vfork,@function
.type vfork,@function
__vfork:
vfork:
	pop %rdx
	mov $0x4000003a,%eax /* SYS_vfork */
	syscall
	push %rdx
	mov %rax,%rdi
	jmp __syscall_ret


text:
.global __vfork
.weak vfork
.type __vfork,@function
.type vfork,@function
__vfork:
vfork:
	pop %rdx
	mov $58,%eax
	syscall
	push %rdx
	mov %rax,%rdi
	jmp __syscall_ret


text:
#include <stdlib.h>
#include <string.h>
#include <errno.h>

extern char **__environ;
extern char **__env_map;

int unsetenv(const char *name)
{
	int i, j;
	size_t l = strlen(name);

	if (!*name || strchr(name, '=')) {
		errno = EINVAL;
		return -1;
	}
again:
	for (i=0; __environ[i] && (memcmp(name, __environ[i], l) || __environ[i][l] != '='); i++);
	if (__environ[i]) {
		if (__env_map) {
			for (j=0; __env_map[j] && __env_map[j] != __environ[i]; j++);
			free (__env_map[j]);
			for (; __env_map[j]; j++)
				__env_map[j] = __env_map[j+1];
		}
		for (; __environ[i]; i++)
			__environ[i] = __environ[i+1];
		goto again;
	}
	return 0;
}


text:
#ifndef SHARED

#include <string.h>
#include "pthread_impl.h"
#include "libc.h"

extern struct tls_image {
	void *image;
	size_t len, size, align;
} __static_tls ATTR_LIBC_VISIBILITY;

#define T __static_tls

void __reset_tls()
{
	if (!T.size) return;
	pthread_t self = __pthread_self();
	memcpy(self->dtv[1], T.image, T.len);
	memset((char *)self->dtv[1]+T.len, 0, T.size-T.len);
}

#endif


text:
#include <elf.h>
#include <poll.h>
#include <fcntl.h>
#include <signal.h>
#include "syscall.h"
#include "atomic.h"
#include "libc.h"

void __init_tls(size_t *);

#ifndef SHARED
static void dummy() {}
weak_alias(dummy, _init);
extern void (*const __init_array_start)() __attribute__((weak));
extern void (*const __init_array_end)() __attribute__((weak));
#endif

static void dummy1(void *p) {}
weak_alias(dummy1, __init_ssp);

#define AUX_CNT 38

extern size_t __hwcap, __sysinfo;
extern char *__progname, *__progname_full;

#ifndef SHARED
static
#endif
void __init_libc(char **envp, char *pn)
{
	size_t i, *auxv, aux[AUX_CNT] = { 0 };
	__environ = envp;
	for (i=0; envp[i]; i++);
	libc.auxv = auxv = (void *)(envp+i+1);
	for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT) aux[auxv[i]] = auxv[i+1];
	__hwcap = aux[AT_HWCAP];
	__sysinfo = aux[AT_SYSINFO];
	libc.page_size = aux[AT_PAGESZ];

	if (pn) {
		__progname = __progname_full = pn;
		for (i=0; pn[i]; i++) if (pn[i]=='/') __progname = pn+i+1;
	}

	__init_tls(aux);
	__init_ssp((void *)aux[AT_RANDOM]);

	if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID]
		&& !aux[AT_SECURE]) return;

	struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} };
#ifdef SYS_poll
	__syscall(SYS_poll, pfd, 3, 0);
#else
	__syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG/8);
#endif
	for (i=0; i<3; i++) if (pfd[i].revents&POLLNVAL)
		if (__sys_open("/dev/null", O_RDWR)<0)
			a_crash();
	libc.secure = 1;
}

int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv)
{
	char **envp = argv+argc+1;

#ifndef SHARED
	__init_libc(envp, argv[0]);
	_init();
	uintptr_t a = (uintptr_t)&__init_array_start;
	for (; a<(uintptr_t)&__init_array_end; a+=sizeof(void(*)()))
		(*(void (**)())a)();
#endif

	/* Pass control to the application */
	exit(main(argc, argv, envp));
	return 0;
}


text:
#include <stdlib.h>
#include <string.h>
#include "libc.h"

char *getenv(const char *name)
{
	int i;
	size_t l = strlen(name);
	if (!__environ || !*name || strchr(name, '=')) return NULL;
	for (i=0; __environ[i] && (strncmp(name, __environ[i], l)
		|| __environ[i][l] != '='); i++);
	if (__environ[i]) return __environ[i] + l+1;
	return NULL;
}


text:
#define _GNU_SOURCE
#include <stdlib.h>

extern char **__environ;

int clearenv()
{
	__environ[0] = 0;
	return 0;
}


text:
#include <elf.h>
#include <limits.h>
#include <sys/mman.h>
#include <string.h>
#include "pthread_impl.h"
#include "libc.h"
#include "atomic.h"
#include "syscall.h"

int __init_tp(void *p)
{
	pthread_t td = p;
	td->self = td;
	int r = __set_thread_area(TP_ADJ(p));
	if (r < 0) return -1;
	if (!r) libc.can_do_threads = 1;
	libc.has_thread_pointer = 1;
	td->tid = __syscall(SYS_set_tid_address, &td->tid);
	td->locale = &libc.global_locale;
	return 0;
}

#ifndef SHARED

static long long builtin_tls[(sizeof(struct pthread) + 64)/sizeof(long long)];

struct tls_image {
	void *image;
	size_t len, size, align;
} __static_tls ATTR_LIBC_VISIBILITY;

#define T __static_tls

void *__copy_tls(unsigned char *mem)
{
	pthread_t td;
	if (!T.image) return mem;
	void **dtv = (void *)mem;
	dtv[0] = (void *)1;
#ifdef TLS_ABOVE_TP
	mem += sizeof(void *) * 2;
	mem += -((uintptr_t)mem + sizeof(struct pthread)) & (T.align-1);
	td = (pthread_t)mem;
	mem += sizeof(struct pthread);
#else
	mem += libc.tls_size - sizeof(struct pthread);
	mem -= (uintptr_t)mem & (T.align-1);
	td = (pthread_t)mem;
	mem -= T.size;
#endif
	td->dtv = dtv;
	dtv[1] = mem;
	memcpy(mem, T.image, T.len);
	return td;
}

#if ULONG_MAX == 0xffffffff
typedef Elf32_Phdr Phdr;
#else
typedef Elf64_Phdr Phdr;
#endif

void __init_tls(size_t *aux)
{
	unsigned char *p;
	size_t n;
	Phdr *phdr, *tls_phdr=0;
	size_t base = 0;
	void *mem;

	libc.tls_size = sizeof(struct pthread);

	for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
		phdr = (void *)p;
		if (phdr->p_type == PT_PHDR)
			base = aux[AT_PHDR] - phdr->p_vaddr;
		if (phdr->p_type == PT_TLS)
			tls_phdr = phdr;
	}

	if (tls_phdr) {
		T.image = (void *)(base + tls_phdr->p_vaddr);
		T.len = tls_phdr->p_filesz;
		T.size = tls_phdr->p_memsz;
		T.align = tls_phdr->p_align;
	}

	T.size += (-T.size - (uintptr_t)T.image) & (T.align-1);
	if (T.align < 4*sizeof(size_t)) T.align = 4*sizeof(size_t);

	libc.tls_size = 2*sizeof(void *)+T.size+T.align+sizeof(struct pthread);

	if (libc.tls_size > sizeof builtin_tls) {
#ifndef SYS_mmap2
#define SYS_mmap2 SYS_mmap
#endif
		mem = (void *)__syscall(
			SYS_mmap2,
			0, libc.tls_size, PROT_READ|PROT_WRITE,
			MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
		/* -4095...-1 cast to void * will crash on dereference anyway,
		 * so don't bloat the init code checking for error codes and
		 * explicitly calling a_crash(). */
	} else {
		mem = builtin_tls;
	}

	/* Failure to initialize thread pointer is fatal if TLS is used. */
	if (__init_tp(__copy_tls(mem)) < 0 && tls_phdr)
		a_crash();
}
#else
void __init_tls(size_t *auxv) { }
#endif


text:
#include <stdlib.h>
#include <string.h>

extern char **__environ;
char **__env_map;

int __putenv(char *s, int a)
{
	int i=0, j=0;
	char *z = strchr(s, '=');
	char **newenv = 0;
	char **newmap = 0;
	static char **oldenv;

	if (!z) return unsetenv(s);
	if (z==s) return -1;
	for (; __environ[i] && memcmp(s, __environ[i], z-s+1); i++);
	if (a) {
		if (!__env_map) {
			__env_map = calloc(2, sizeof(char *));
			if (__env_map) __env_map[0] = s;
		} else {
			for (; __env_map[j] && __env_map[j] != __environ[i]; j++);
			if (!__env_map[j]) {
				newmap = realloc(__env_map, sizeof(char *)*(j+2));
				if (newmap) {
					__env_map = newmap;
					__env_map[j] = s;
					__env_map[j+1] = NULL;
				}
			} else {
				free(__env_map[j]);
			}
		}
	}
	if (!__environ[i]) {
		newenv = malloc(sizeof(char *)*(i+2));
		if (!newenv) {
			if (a && __env_map) __env_map[j] = 0;
			return -1;
		}
		memcpy(newenv, __environ, sizeof(char *)*i);
		newenv[i] = s;
		newenv[i+1] = 0;
		__environ = newenv;
		free(oldenv);
		oldenv = __environ;
	}

	__environ[i] = s;
	return 0;
}

int putenv(char *s)
{
	return __putenv(s, 0);
}


text:
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int __putenv(char *s, int a);

int setenv(const char *var, const char *value, int overwrite)
{
	char *s;
	int l1, l2;

	if (!var || !*var || strchr(var, '=')) {
		errno = EINVAL;
		return -1;
	}
	if (!overwrite && getenv(var)) return 0;

	l1 = strlen(var);
	l2 = strlen(value);
	s = malloc(l1+l2+2);
	if (s) {
		memcpy(s, var, l1);
		s[l1] = '=';
		memcpy(s+l1+1, value, l2);
		s[l1+l2+1] = 0;
		if (!__putenv(s, 1)) return 0;
	}
	free(s);
	return -1;
}


text:
#include "libc.h"

char **__environ = 0;
weak_alias(__environ, ___environ);
weak_alias(__environ, _environ);
weak_alias(__environ, environ);


text:
#include <string.h>
#include <stdint.h>
#include "pthread_impl.h"

uintptr_t __stack_chk_guard;

void __init_ssp(void *entropy)
{
	if (entropy) memcpy(&__stack_chk_guard, entropy, sizeof(uintptr_t));
	else __stack_chk_guard = (uintptr_t)&__stack_chk_guard * 1103515245;

	if (libc.has_thread_pointer)
		__pthread_self()->canary = __stack_chk_guard;
}

void __stack_chk_fail(void)
{
	a_crash();
}


text:
	.global _longjmp
	.global longjmp
	.type   _longjmp,@function
	.type   longjmp,@function
_longjmp:
longjmp:
# void longjmp(jmp_buf env, int val);
# put val into return register and restore the env saved in setjmp
# if val(r4) is 0, put 1 there.
	# 0) move old return address into r0
	lwz 0, 0(3)
	# 1) put it into link reg
	mtlr 0
	#2 ) restore stack ptr
	lwz 1, 4(3)
	#3) restore control reg
	lwz 0, 8(3)
	mtcr 0
	#4) restore r14-r31
	lwz 14, 12(3)
	lwz 15, 16(3)
	lwz 16, 20(3)
	lwz 17, 24(3)
	lwz 18, 28(3)
	lwz 19, 32(3)
	lwz 20, 36(3)
	lwz 21, 40(3)
	lwz 22, 44(3)
	lwz 23, 48(3)
	lwz 24, 52(3)
	lwz 25, 56(3)
	lwz 26, 60(3)
	lwz 27, 64(3)
	lwz 28, 68(3)
	lwz 29, 72(3)
	lwz 30, 76(3)
	lwz 31, 80(3)
	lfd 14,88(3)
	lfd 15,96(3)
	lfd 16,104(3)
	lfd 17,112(3)
	lfd 18,120(3)
	lfd 19,128(3)
	lfd 20,136(3)
	lfd 21,144(3)
	lfd 22,152(3)
	lfd 23,160(3)
	lfd 24,168(3)
	lfd 25,176(3)
	lfd 26,184(3)
	lfd 27,192(3)
	lfd 28,200(3)
	lfd 29,208(3)
	lfd 30,216(3)
	lfd 31,224(3)
	#5) put val into return reg r3
	mr 3, 4

	#6) check if return value is 0, make it 1 in that case
	cmpwi cr7, 4, 0
	bne cr7, 1f
	li 3, 1
1:
	blr


text:
	.global __setjmp
	.global _setjmp
	.global setjmp
	.type   __setjmp,@function
	.type   _setjmp,@function
	.type   setjmp,@function
__setjmp:
_setjmp:
setjmp:
	# 0) store IP int 0, then into the jmpbuf pointed to by r3 (first arg)
	mflr 0
	stw 0, 0(3)
	# 1) store reg1 (SP)
	stw 1, 4(3)
	# 2) store cr
	mfcr 0
	stw 0, 8(3)
	# 3) store r14-31
	stw 14, 12(3)
	stw 15, 16(3)
	stw 16, 20(3)
	stw 17, 24(3)
	stw 18, 28(3)
	stw 19, 32(3)
	stw 20, 36(3)
	stw 21, 40(3)
	stw 22, 44(3)
	stw 23, 48(3)
	stw 24, 52(3)
	stw 25, 56(3)
	stw 26, 60(3)
	stw 27, 64(3)
	stw 28, 68(3)
	stw 29, 72(3)
	stw 30, 76(3)
	stw 31, 80(3)
	stfd 14,88(3)
	stfd 15,96(3)
	stfd 16,104(3)
	stfd 17,112(3)
	stfd 18,120(3)
	stfd 19,128(3)
	stfd 20,136(3)
	stfd 21,144(3)
	stfd 22,152(3)
	stfd 23,160(3)
	stfd 24,168(3)
	stfd 25,176(3)
	stfd 26,184(3)
	stfd 27,192(3)
	stfd 28,200(3)
	stfd 29,208(3)
	stfd 30,216(3)
	stfd 31,224(3)
	# 4) set return value to 0
	li 3, 0
	# 5) return
	blr


text: longjmp.s


text:
.set noreorder

.global _longjmp
.global longjmp
.type   _longjmp,@function
.type   longjmp,@function
_longjmp:
longjmp:
	move    $2, $5
	bne     $2, $0, 1f
	nop
	addu    $2, $2, 1
1:	lw      $ra,  0($4)
	lw      $sp,  4($4)
	lw      $16,  8($4)
	lw      $17, 12($4)
	lw      $18, 16($4)
	lw      $19, 20($4)
	lw      $20, 24($4)
	lw      $21, 28($4)
	lw      $22, 32($4)
	lw      $23, 36($4)
	lw      $30, 40($4)
	jr      $ra
	lw      $28, 44($4)


text:
.set noreorder

.global __setjmp
.global _setjmp
.global setjmp
.type   __setjmp,@function
.type   _setjmp,@function
.type   setjmp,@function
__setjmp:
_setjmp:
setjmp:
	sw      $ra,  0($4)
	sw      $sp,  4($4)
	sw      $16,  8($4)
	sw      $17, 12($4)
	sw      $18, 16($4)
	sw      $19, 20($4)
	sw      $20, 24($4)
	sw      $21, 28($4)
	sw      $22, 32($4)
	sw      $23, 36($4)
	sw      $30, 40($4)
	sw      $28, 44($4)
	jr      $ra
	li      $2, 0


text: setjmp.s


text:
.global _longjmp
.global longjmp
.type   _longjmp, @function
.type   longjmp,  @function
_longjmp:
longjmp:
	mov.l  @r4+, r8
	mov.l  @r4+, r9
	mov.l  @r4+, r10
	mov.l  @r4+, r11
	mov.l  @r4+, r12
	mov.l  @r4+, r13
	mov.l  @r4+, r14
	mov.l  @r4+, r15
	lds.l  @r4+, pr
	fmov.s @r4+, fr12
	fmov.s @r4+, fr13
	fmov.s @r4+, fr14
	fmov.s @r4+, fr15

	tst  r5, r5
	movt r0
	add  r5, r0

	rts
	 nop


text:
.global __setjmp
.global _setjmp
.global setjmp
.type   __setjmp, @function
.type   _setjmp,  @function
.type   setjmp,   @function
__setjmp:
_setjmp:
setjmp:
	add   #52, r4
	fmov.s fr15, @-r4
	fmov.s fr14, @-r4
	fmov.s fr13, @-r4
	fmov.s fr12, @-r4
	sts.l  pr,   @-r4
	mov.l  r15   @-r4
	mov.l  r14,  @-r4
	mov.l  r13,  @-r4
	mov.l  r12,  @-r4
	mov.l  r11,  @-r4
	mov.l  r10,  @-r4
	mov.l  r9,   @-r4
	mov.l  r8,   @-r4
	rts
	 mov  #0, r0


text:
.global _longjmp
.global longjmp
.type   _longjmp,@function
.type   longjmp,@function
_longjmp:
longjmp:
	addi    r3, r6, 0
	bnei    r3, 1f
	addi    r3, r3, 1
1:      lwi     r1,  r5, 0
	lwi     r15, r5, 4
	lwi     r2,  r5, 8
	lwi     r13, r5, 12
	lwi     r18, r5, 16
	lwi     r19, r5, 20
	lwi     r20, r5, 24
	lwi     r21, r5, 28
	lwi     r22, r5, 32
	lwi     r23, r5, 36
	lwi     r24, r5, 40
	lwi     r25, r5, 44
	lwi     r26, r5, 48
	lwi     r27, r5, 52
	lwi     r28, r5, 56
	lwi     r29, r5, 60
	lwi     r30, r5, 64
	lwi     r31, r5, 68
	rtsd    r15, 8
	nop


text:
.global __setjmp
.global _setjmp
.global setjmp
.type __setjmp,@function
.type _setjmp,@function
.type setjmp,@function
__setjmp:
_setjmp:
setjmp:
	swi     r1,  r5, 0
	swi     r15, r5, 4
	swi     r2,  r5, 8
	swi     r13, r5, 12
	swi     r18, r5, 16
	swi     r19, r5, 20
	swi     r20, r5, 24
	swi     r21, r5, 28
	swi     r22, r5, 32
	swi     r23, r5, 36
	swi     r24, r5, 40
	swi     r25, r5, 44
	swi     r26, r5, 48
	swi     r27, r5, 52
	swi     r28, r5, 56
	swi     r29, r5, 60
	swi     r30, r5, 64
	swi     r31, r5, 68
	rtsd    r15, 8
	ori     r3, r0, 0


text:
.set noreorder

.global _longjmp
.global longjmp
.type   _longjmp,@function
.type   longjmp,@function
_longjmp:
longjmp:
	move    $2, $5
	bne     $2, $0, 1f
	nop
	addu    $2, $2, 1
1:	lwc1    $20, 56($4)
	lwc1    $21, 60($4)
	lwc1    $22, 64($4)
	lwc1    $23, 68($4)
	lwc1    $24, 72($4)
	lwc1    $25, 76($4)
	lwc1    $26, 80($4)
	lwc1    $27, 84($4)
	lwc1    $28, 88($4)
	lwc1    $29, 92($4)
	lwc1    $30, 96($4)
	lwc1    $31, 100($4)
	lw      $ra,  0($4)
	lw      $sp,  4($4)
	lw      $16,  8($4)
	lw      $17, 12($4)
	lw      $18, 16($4)
	lw      $19, 20($4)
	lw      $20, 24($4)
	lw      $21, 28($4)
	lw      $22, 32($4)
	lw      $23, 36($4)
	lw      $30, 40($4)
	jr      $ra
	lw      $28, 44($4)


text:
.set noreorder

.global __setjmp
.global _setjmp
.global setjmp
.type   __setjmp,@function
.type   _setjmp,@function
.type   setjmp,@function
__setjmp:
_setjmp:
setjmp:
	sw      $ra,  0($4)
	sw      $sp,  4($4)
	sw      $16,  8($4)
	sw      $17, 12($4)
	sw      $18, 16($4)
	sw      $19, 20($4)
	sw      $20, 24($4)
	sw      $21, 28($4)
	sw      $22, 32($4)
	sw      $23, 36($4)
	sw      $30, 40($4)
	sw      $28, 44($4)
	swc1    $20, 56($4)
	swc1    $21, 60($4)
	swc1    $22, 64($4)
	swc1    $23, 68($4)
	swc1    $24, 72($4)
	swc1    $25, 76($4)
	swc1    $26, 80($4)
	swc1    $27, 84($4)
	swc1    $28, 88($4)
	swc1    $29, 92($4)
	swc1    $30, 96($4)
	swc1    $31, 100($4)
	jr      $ra
	li      $2, 0


text:
.global _longjmp
.global longjmp
.type   _longjmp, @function
.type   longjmp,  @function
_longjmp:
longjmp:
	mov.l  @r4+, r8
	mov.l  @r4+, r9
	mov.l  @r4+, r10
	mov.l  @r4+, r11
	mov.l  @r4+, r12
	mov.l  @r4+, r13
	mov.l  @r4+, r14
	mov.l  @r4+, r15
	lds.l  @r4+, pr

	tst  r5, r5
	movt r0
	add  r5, r0

	rts
	 nop


text:
.global __setjmp
.global _setjmp
.global setjmp
.type   __setjmp, @function
.type   _setjmp,  @function
.type   setjmp,   @function
__setjmp:
_setjmp:
setjmp:
	add   #36, r4
	sts.l  pr,   @-r4
	mov.l  r15   @-r4
	mov.l  r14,  @-r4
	mov.l  r13,  @-r4
	mov.l  r12,  @-r4
	mov.l  r11,  @-r4
	mov.l  r10,  @-r4
	mov.l  r9,   @-r4
	mov.l  r8,   @-r4
	rts
	 mov  #0, r0


text:
.global _longjmp
.global longjmp
.type _longjmp,@function
.type longjmp,@function
_longjmp:
longjmp:
	mov  4(%esp),%edx
	mov  8(%esp),%eax
	test    %eax,%eax
	jnz 1f
	inc     %eax
1:
	mov   (%edx),%ebx
	mov  4(%edx),%esi
	mov  8(%edx),%edi
	mov 12(%edx),%ebp
	mov 16(%edx),%ecx
	mov     %ecx,%esp
	mov 20(%edx),%ecx
	jmp *%ecx


text:
.global __setjmp
.global _setjmp
.global setjmp
.type __setjmp,@function
.type _setjmp,@function
.type setjmp,@function
__setjmp:
_setjmp:
setjmp:
	mov 4(%esp), %eax
	mov    %ebx, (%eax)
	mov    %esi, 4(%eax)
	mov    %edi, 8(%eax)
	mov    %ebp, 12(%eax)
	lea 4(%esp), %ecx
	mov    %ecx, 16(%eax)
	mov  (%esp), %ecx
	mov    %ecx, 20(%eax)
	xor    %eax, %eax
	ret


text:
/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
.global _longjmp
.global longjmp
.type _longjmp,@function
.type longjmp,@function
_longjmp:
longjmp:
	mov %rsi,%rax           /* val will be longjmp return */
	test %rax,%rax
	jnz 1f
	inc %rax                /* if val==0, val=1 per longjmp semantics */
1:
	mov (%rdi),%rbx         /* rdi is the jmp_buf, restore regs from it */
	mov 8(%rdi),%rbp
	mov 16(%rdi),%r12
	mov 24(%rdi),%r13
	mov 32(%rdi),%r14
	mov 40(%rdi),%r15
	mov 48(%rdi),%rdx       /* this ends up being the stack pointer */
	mov %rdx,%rsp
	mov 56(%rdi),%rdx       /* this is the instruction pointer */
	jmp *%rdx               /* goto saved address without altering rsp */


text:
/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
.global __setjmp
.global _setjmp
.global setjmp
.type __setjmp,@function
.type _setjmp,@function
.type setjmp,@function
__setjmp:
_setjmp:
setjmp:
	mov %rbx,(%rdi)         /* rdi is jmp_buf, move registers onto it */
	mov %rbp,8(%rdi)
	mov %r12,16(%rdi)
	mov %r13,24(%rdi)
	mov %r14,32(%rdi)
	mov %r15,40(%rdi)
	lea 8(%rsp),%rdx        /* this is our rsp WITHOUT current ret addr */
	mov %rdx,48(%rdi)
	mov (%rsp),%rdx         /* save return addr ptr for new rip */
	mov %rdx,56(%rdi)
	xor %rax,%rax           /* always return 0 */
	ret


text:
.global _longjmp
.global longjmp
.type _longjmp,%function
.type longjmp,%function
_longjmp:
longjmp:
	mov ip,r0
	movs r0,r1
	moveq r0,#1
	ldmia ip!, {v1,v2,v3,v4,v5,v6,sl,fp,sp,lr}

	adr r1,1f
	ldr r2,1f
	ldr r1,[r1,r2]

	tst r1,#0x260
	beq 3f
	tst r1,#0x20
	beq 2f
	ldc p2, cr4, [ip], #48
2:	tst r1,#0x40
	beq 2f
	ldc p11, cr8, [ip], #64
2:	tst r1,#0x200
	beq 3f
	ldcl p1, cr10, [ip], #8
	ldcl p1, cr11, [ip], #8
	ldcl p1, cr12, [ip], #8
	ldcl p1, cr13, [ip], #8
	ldcl p1, cr14, [ip], #8
	ldcl p1, cr15, [ip], #8
3:	tst lr,#1
	moveq pc,lr
	bx lr

.hidden __hwcap
1:	.word __hwcap-1b


text:
.global __setjmp
.global _setjmp
.global setjmp
.type __setjmp,%function
.type _setjmp,%function
.type setjmp,%function
__setjmp:
_setjmp:
setjmp:
	mov ip,r0
	stmia ip!,{v1,v2,v3,v4,v5,v6,sl,fp,sp,lr}
	mov r0,#0

	adr r1,1f
	ldr r2,1f
	ldr r1,[r1,r2]

	tst r1,#0x260
	beq 3f
	tst r1,#0x20
	beq 2f
	stc p2, cr4, [ip], #48
2:	tst r1,#0x40
	beq 2f
	stc p11, cr8, [ip], #64
2:	tst r1,#0x200
	beq 3f
	stcl p1, cr10, [ip], #8
	stcl p1, cr11, [ip], #8
	stcl p1, cr12, [ip], #8
	stcl p1, cr13, [ip], #8
	stcl p1, cr14, [ip], #8
	stcl p1, cr15, [ip], #8
3:	tst lr,#1
	moveq pc,lr
	bx lr

.hidden __hwcap
1:	.word __hwcap-1b


text:
.global _longjmp
.global longjmp
.type   _longjmp,@function
.type   longjmp,@function
_longjmp:
longjmp:
	l.sfeqi	r4, 0
	l.bnf	1f
	 l.addi	r11, r4,0
	l.ori	r11, r0, 1
1:	l.lwz	r1, 0(r3)
	l.lwz	r2, 4(r3)
	l.lwz	r9, 8(r3)
	l.lwz	r10, 12(r3)
	l.lwz	r14, 16(r3)
	l.lwz	r16, 20(r3)
	l.lwz	r18, 24(r3)
	l.lwz	r20, 28(r3)
	l.lwz	r22, 32(r3)
	l.lwz	r24, 36(r3)
	l.lwz	r26, 40(r3)
	l.lwz	r28, 44(r3)
	l.lwz	r30, 48(r3)
	l.jr	r9
	 l.nop


text:
.global __setjmp
.global _setjmp
.global setjmp
.type __setjmp,@function
.type _setjmp,@function
.type setjmp,@function
__setjmp:
_setjmp:
setjmp:
	l.sw	0(r3), r1
	l.sw	4(r3), r2
	l.sw	8(r3), r9
	l.sw	12(r3), r10
	l.sw	16(r3), r14
	l.sw	20(r3), r16
	l.sw	24(r3), r18
	l.sw	28(r3), r20
	l.sw	32(r3), r22
	l.sw	36(r3), r24
	l.sw	40(r3), r26
	l.sw	44(r3), r28
	l.sw	48(r3), r30
	l.jr	r9
	 l.ori	r11,r0,0