xref: /plan9/sys/src/libmach/executable.c (revision 70b8e0103a6fc04254076ea6a1a33497e2b04a62)
1bd389b36SDavid du Colombier #include	<u.h>
2bd389b36SDavid du Colombier #include	<libc.h>
3bd389b36SDavid du Colombier #include	<bio.h>
4bd389b36SDavid du Colombier #include	<bootexec.h>
5bd389b36SDavid du Colombier #include	<mach.h>
67dd7cddfSDavid du Colombier #include	"elf.h"
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier /*
93e12c5d1SDavid du Colombier  *	All a.out header types.  The dummy entry allows canonical
103e12c5d1SDavid du Colombier  *	processing of the union as a sequence of longs
113e12c5d1SDavid du Colombier  */
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier typedef struct {
143e12c5d1SDavid du Colombier 	union{
153e12c5d1SDavid du Colombier 		Exec;			/* in a.out.h */
167dd7cddfSDavid du Colombier 		Ehdr;			/* in elf.h */
177dd7cddfSDavid du Colombier 		struct mipsexec;
18219b2ee8SDavid du Colombier 		struct mips4kexec;
193e12c5d1SDavid du Colombier 		struct sparcexec;
203e12c5d1SDavid du Colombier 		struct nextexec;
213e12c5d1SDavid du Colombier 	} e;
223e12c5d1SDavid du Colombier 	long dummy;		/* padding to ensure extra long */
233e12c5d1SDavid du Colombier } ExecHdr;
243e12c5d1SDavid du Colombier 
257dd7cddfSDavid du Colombier static	int	nextboot(int, Fhdr*, ExecHdr*);
267dd7cddfSDavid du Colombier static	int	sparcboot(int, Fhdr*, ExecHdr*);
277dd7cddfSDavid du Colombier static	int	mipsboot(int, Fhdr*, ExecHdr*);
287dd7cddfSDavid du Colombier static	int	mips4kboot(int, Fhdr*, ExecHdr*);
297dd7cddfSDavid du Colombier static	int	common(int, Fhdr*, ExecHdr*);
307dd7cddfSDavid du Colombier static	int	adotout(int, Fhdr*, ExecHdr*);
317dd7cddfSDavid du Colombier static	int	elfdotout(int, Fhdr*, ExecHdr*);
327dd7cddfSDavid du Colombier static	int	armdotout(int, Fhdr*, ExecHdr*);
337dd7cddfSDavid du Colombier static	int	alphadotout(int, Fhdr*, ExecHdr*);
343e12c5d1SDavid du Colombier static	void	setsym(Fhdr*, long, long, long, long);
353e12c5d1SDavid du Colombier static	void	setdata(Fhdr*, long, long, long, long);
363e12c5d1SDavid du Colombier static	void	settext(Fhdr*, long, long, long, long);
373e12c5d1SDavid du Colombier static	void	hswal(long*, int, long(*)(long));
38*70b8e010SDavid du Colombier static	long	noswal(long);
39219b2ee8SDavid du Colombier static	long	_round(long, long);
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier /*
423e12c5d1SDavid du Colombier  *	definition of per-executable file type structures
433e12c5d1SDavid du Colombier  */
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier typedef struct Exectable{
463e12c5d1SDavid du Colombier 	long	magic;			/* big-endian magic number of file */
473e12c5d1SDavid du Colombier 	char	*name;			/* executable identifier */
4812fd1c83SDavid du Colombier 	char	*dlmname;		/* dynamically loadable module identifier */
493e12c5d1SDavid du Colombier 	int	type;			/* Internal code */
503e12c5d1SDavid du Colombier 	Mach	*mach;			/* Per-machine data */
513e12c5d1SDavid du Colombier 	ulong	hsize;			/* header size */
523e12c5d1SDavid du Colombier 	long	(*swal)(long);		/* beswal or leswal */
537dd7cddfSDavid du Colombier 	int	(*hparse)(int, Fhdr*, ExecHdr*);
543e12c5d1SDavid du Colombier } ExecTable;
553e12c5d1SDavid du Colombier 
563e12c5d1SDavid du Colombier extern	Mach	mmips;
577dd7cddfSDavid du Colombier extern	Mach	mmips2le;
587dd7cddfSDavid du Colombier extern	Mach	mmips2be;
593e12c5d1SDavid du Colombier extern	Mach	msparc;
603e12c5d1SDavid du Colombier extern	Mach	m68020;
613e12c5d1SDavid du Colombier extern	Mach	mi386;
627dd7cddfSDavid du Colombier extern	Mach	marm;
637dd7cddfSDavid du Colombier extern	Mach	mpower;
647dd7cddfSDavid du Colombier extern	Mach	malpha;
653e12c5d1SDavid du Colombier 
663e12c5d1SDavid du Colombier ExecTable exectab[] =
673e12c5d1SDavid du Colombier {
683e12c5d1SDavid du Colombier 	{ V_MAGIC,			/* Mips v.out */
693e12c5d1SDavid du Colombier 		"mips plan 9 executable",
7012fd1c83SDavid du Colombier 		"mips plan 9 dlm",
713e12c5d1SDavid du Colombier 		FMIPS,
723e12c5d1SDavid du Colombier 		&mmips,
733e12c5d1SDavid du Colombier 		sizeof(Exec),
743e12c5d1SDavid du Colombier 		beswal,
753e12c5d1SDavid du Colombier 		adotout },
767dd7cddfSDavid du Colombier 	{ M_MAGIC,			/* Mips 4.out */
777dd7cddfSDavid du Colombier 		"mips 4k plan 9 executable BE",
7812fd1c83SDavid du Colombier 		"mips 4k plan 9 dlm BE",
797dd7cddfSDavid du Colombier 		FMIPS2BE,
807dd7cddfSDavid du Colombier 		&mmips2be,
817dd7cddfSDavid du Colombier 		sizeof(Exec),
827dd7cddfSDavid du Colombier 		beswal,
837dd7cddfSDavid du Colombier 		adotout },
847dd7cddfSDavid du Colombier 	{ N_MAGIC,			/* Mips 0.out */
857dd7cddfSDavid du Colombier 		"mips 4k plan 9 executable LE",
8612fd1c83SDavid du Colombier 		"mips 4k plan 9 dlm LE",
877dd7cddfSDavid du Colombier 		FMIPS2LE,
887dd7cddfSDavid du Colombier 		&mmips2le,
897dd7cddfSDavid du Colombier 		sizeof(Exec),
907dd7cddfSDavid du Colombier 		beswal,
917dd7cddfSDavid du Colombier 		adotout },
923e12c5d1SDavid du Colombier 	{ 0x160<<16,			/* Mips boot image */
933e12c5d1SDavid du Colombier 		"mips plan 9 boot image",
9412fd1c83SDavid du Colombier 		nil,
953e12c5d1SDavid du Colombier 		FMIPSB,
963e12c5d1SDavid du Colombier 		&mmips,
973e12c5d1SDavid du Colombier 		sizeof(struct mipsexec),
983e12c5d1SDavid du Colombier 		beswal,
993e12c5d1SDavid du Colombier 		mipsboot },
100219b2ee8SDavid du Colombier 	{ (0x160<<16)|3,		/* Mips boot image */
101219b2ee8SDavid du Colombier 		"mips 4k plan 9 boot image",
10212fd1c83SDavid du Colombier 		nil,
103219b2ee8SDavid du Colombier 		FMIPSB,
10480ee5cbfSDavid du Colombier 		&mmips2be,
105219b2ee8SDavid du Colombier 		sizeof(struct mips4kexec),
1063e12c5d1SDavid du Colombier 		beswal,
107219b2ee8SDavid du Colombier 		mips4kboot },
1083e12c5d1SDavid du Colombier 	{ K_MAGIC,			/* Sparc k.out */
1093e12c5d1SDavid du Colombier 		"sparc plan 9 executable",
11012fd1c83SDavid du Colombier 		"sparc plan 9 dlm",
1113e12c5d1SDavid du Colombier 		FSPARC,
1123e12c5d1SDavid du Colombier 		&msparc,
1133e12c5d1SDavid du Colombier 		sizeof(Exec),
1143e12c5d1SDavid du Colombier 		beswal,
1153e12c5d1SDavid du Colombier 		adotout },
1163e12c5d1SDavid du Colombier 	{ 0x01030107, 			/* Sparc boot image */
1173e12c5d1SDavid du Colombier 		"sparc plan 9 boot image",
11812fd1c83SDavid du Colombier 		nil,
1193e12c5d1SDavid du Colombier 		FSPARCB,
1203e12c5d1SDavid du Colombier 		&msparc,
1213e12c5d1SDavid du Colombier 		sizeof(struct sparcexec),
1223e12c5d1SDavid du Colombier 		beswal,
1233e12c5d1SDavid du Colombier 		sparcboot },
1243e12c5d1SDavid du Colombier 	{ A_MAGIC,			/* 68020 2.out & boot image */
1253e12c5d1SDavid du Colombier 		"68020 plan 9 executable",
12612fd1c83SDavid du Colombier 		"68020 plan 9 dlm",
1273e12c5d1SDavid du Colombier 		F68020,
1283e12c5d1SDavid du Colombier 		&m68020,
1293e12c5d1SDavid du Colombier 		sizeof(Exec),
1303e12c5d1SDavid du Colombier 		beswal,
1313e12c5d1SDavid du Colombier 		common },
1323e12c5d1SDavid du Colombier 	{ 0xFEEDFACE,			/* Next boot image */
1333e12c5d1SDavid du Colombier 		"next plan 9 boot image",
13412fd1c83SDavid du Colombier 		nil,
1353e12c5d1SDavid du Colombier 		FNEXTB,
1363e12c5d1SDavid du Colombier 		&m68020,
1373e12c5d1SDavid du Colombier 		sizeof(struct nextexec),
1383e12c5d1SDavid du Colombier 		beswal,
1393e12c5d1SDavid du Colombier 		nextboot },
1403e12c5d1SDavid du Colombier 	{ I_MAGIC,			/* I386 8.out & boot image */
1413e12c5d1SDavid du Colombier 		"386 plan 9 executable",
14212fd1c83SDavid du Colombier 		"386 plan 9 dlm",
1433e12c5d1SDavid du Colombier 		FI386,
1443e12c5d1SDavid du Colombier 		&mi386,
1453e12c5d1SDavid du Colombier 		sizeof(Exec),
1463e12c5d1SDavid du Colombier 		beswal,
1473e12c5d1SDavid du Colombier 		common },
1489a747e4fSDavid du Colombier 	{ Q_MAGIC,			/* PowerPC q.out & boot image */
1497dd7cddfSDavid du Colombier 		"power plan 9 executable",
15012fd1c83SDavid du Colombier 		"power plan 9 dlm",
1517dd7cddfSDavid du Colombier 		FPOWER,
1527dd7cddfSDavid du Colombier 		&mpower,
1537dd7cddfSDavid du Colombier 		sizeof(Exec),
1547dd7cddfSDavid du Colombier 		beswal,
1557dd7cddfSDavid du Colombier 		common },
156*70b8e010SDavid du Colombier 	{ ELF_MAG,			/* any elf32 */
157*70b8e010SDavid du Colombier 		"Elf executable",
15812fd1c83SDavid du Colombier 		nil,
159*70b8e010SDavid du Colombier 		FNONE,
160*70b8e010SDavid du Colombier 		&mi386,
1617dd7cddfSDavid du Colombier 		sizeof(Ehdr),
162*70b8e010SDavid du Colombier 		noswal,
1637dd7cddfSDavid du Colombier 		elfdotout },
1647dd7cddfSDavid du Colombier 	{ E_MAGIC,			/* Arm 5.out */
1657dd7cddfSDavid du Colombier 		"Arm plan 9 executable",
16612fd1c83SDavid du Colombier 		"Arm plan 9 dlm",
1677dd7cddfSDavid du Colombier 		FARM,
1687dd7cddfSDavid du Colombier 		&marm,
1697dd7cddfSDavid du Colombier 		sizeof(Exec),
1707dd7cddfSDavid du Colombier 		beswal,
1717dd7cddfSDavid du Colombier 		common },
1727dd7cddfSDavid du Colombier 	{ (143<<16)|0413,		/* (Free|Net)BSD Arm */
1737dd7cddfSDavid du Colombier 		"Arm *BSD executable",
17412fd1c83SDavid du Colombier 		nil,
1757dd7cddfSDavid du Colombier 		FARM,
1767dd7cddfSDavid du Colombier 		&marm,
1777dd7cddfSDavid du Colombier 		sizeof(Exec),
1787dd7cddfSDavid du Colombier 		leswal,
1797dd7cddfSDavid du Colombier 		armdotout },
1807dd7cddfSDavid du Colombier 	{ L_MAGIC,			/* alpha 7.out */
1817dd7cddfSDavid du Colombier 		"alpha plan 9 executable",
18212fd1c83SDavid du Colombier 		"alpha plan 9 dlm",
1837dd7cddfSDavid du Colombier 		FALPHA,
1847dd7cddfSDavid du Colombier 		&malpha,
1857dd7cddfSDavid du Colombier 		sizeof(Exec),
1867dd7cddfSDavid du Colombier 		beswal,
1877dd7cddfSDavid du Colombier 		common },
1887dd7cddfSDavid du Colombier 	{ 0x0700e0c3,			/* alpha boot image */
1897dd7cddfSDavid du Colombier 		"alpha plan 9 boot image",
19012fd1c83SDavid du Colombier 		nil,
1917dd7cddfSDavid du Colombier 		FALPHAB,
1927dd7cddfSDavid du Colombier 		&malpha,
1937dd7cddfSDavid du Colombier 		sizeof(Exec),
1947dd7cddfSDavid du Colombier 		beswal,
1957dd7cddfSDavid du Colombier 		alphadotout },
1963e12c5d1SDavid du Colombier 	{ 0 },
1973e12c5d1SDavid du Colombier };
1983e12c5d1SDavid du Colombier 
1997dd7cddfSDavid du Colombier Mach	*mach = &mi386;			/* Global current machine table */
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier static ExecTable*
2027dd7cddfSDavid du Colombier couldbe4k(ExecTable *mp)
2037dd7cddfSDavid du Colombier {
2049a747e4fSDavid du Colombier 	Dir *d;
2057dd7cddfSDavid du Colombier 	ExecTable *f;
2067dd7cddfSDavid du Colombier 
2079a747e4fSDavid du Colombier 	if((d=dirstat("/proc/1/regs")) == nil)
2087dd7cddfSDavid du Colombier 		return mp;
2099a747e4fSDavid du Colombier 	if(d->length < 32*8){		/* R3000 */
2109a747e4fSDavid du Colombier 		free(d);
2117dd7cddfSDavid du Colombier 		return mp;
2129a747e4fSDavid du Colombier 	}
2139a747e4fSDavid du Colombier 	free(d);
2147dd7cddfSDavid du Colombier 	for (f = exectab; f->magic; f++)
2157dd7cddfSDavid du Colombier 		if(f->magic == M_MAGIC) {
2167dd7cddfSDavid du Colombier 			f->name = "mips plan 9 executable on mips2 kernel";
2177dd7cddfSDavid du Colombier 			return f;
2187dd7cddfSDavid du Colombier 		}
2197dd7cddfSDavid du Colombier 	return mp;
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier 
2223e12c5d1SDavid du Colombier int
2233e12c5d1SDavid du Colombier crackhdr(int fd, Fhdr *fp)
2243e12c5d1SDavid du Colombier {
2253e12c5d1SDavid du Colombier 	ExecTable *mp;
2263e12c5d1SDavid du Colombier 	ExecHdr d;
2277dd7cddfSDavid du Colombier 	int nb, magic, ret;
2283e12c5d1SDavid du Colombier 
2293e12c5d1SDavid du Colombier 	fp->type = FNONE;
2307dd7cddfSDavid du Colombier 	nb = read(fd, (char *)&d.e, sizeof(d.e));
2317dd7cddfSDavid du Colombier 	if (nb <= 0)
2323e12c5d1SDavid du Colombier 		return 0;
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 	ret = 0;
2353e12c5d1SDavid du Colombier 	fp->magic = magic = beswal(d.e.magic);		/* big-endian */
2363e12c5d1SDavid du Colombier 	for (mp = exectab; mp->magic; mp++) {
23712fd1c83SDavid du Colombier 		if (nb < mp->hsize)
23812fd1c83SDavid du Colombier 			continue;
23912fd1c83SDavid du Colombier 		if (mp->magic == (magic & ~DYN_MAGIC)) {
2407dd7cddfSDavid du Colombier 			if(mp->magic == V_MAGIC)
2417dd7cddfSDavid du Colombier 				mp = couldbe4k(mp);
2427dd7cddfSDavid du Colombier 
2433e12c5d1SDavid du Colombier 			hswal((long *) &d, sizeof(d.e)/sizeof(long), mp->swal);
2443e12c5d1SDavid du Colombier 			fp->type = mp->type;
24512fd1c83SDavid du Colombier 			if ((magic & DYN_MAGIC) && mp->dlmname != nil)
24612fd1c83SDavid du Colombier 				fp->name = mp->dlmname;
24712fd1c83SDavid du Colombier 			else
2483e12c5d1SDavid du Colombier 				fp->name = mp->name;
249219b2ee8SDavid du Colombier 			fp->hdrsz = mp->hsize;		/* zero on bootables */
2503e12c5d1SDavid du Colombier 			mach = mp->mach;
2517dd7cddfSDavid du Colombier 			ret  = mp->hparse(fd, fp, &d);
2523e12c5d1SDavid du Colombier 			seek(fd, mp->hsize, 0);		/* seek to end of header */
2537dd7cddfSDavid du Colombier 			break;
2543e12c5d1SDavid du Colombier 		}
2553e12c5d1SDavid du Colombier 	}
2567dd7cddfSDavid du Colombier 	if(mp->magic == 0)
2577dd7cddfSDavid du Colombier 		werrstr("unknown header type");
2587dd7cddfSDavid du Colombier 	return ret;
2593e12c5d1SDavid du Colombier }
2603e12c5d1SDavid du Colombier /*
2613e12c5d1SDavid du Colombier  * Convert header to canonical form
2623e12c5d1SDavid du Colombier  */
2633e12c5d1SDavid du Colombier static void
2643e12c5d1SDavid du Colombier hswal(long *lp, int n, long (*swap) (long))
2653e12c5d1SDavid du Colombier {
2663e12c5d1SDavid du Colombier 	while (n--) {
2673e12c5d1SDavid du Colombier 		*lp = (*swap) (*lp);
2683e12c5d1SDavid du Colombier 		lp++;
2693e12c5d1SDavid du Colombier 	}
2703e12c5d1SDavid du Colombier }
2713e12c5d1SDavid du Colombier /*
272*70b8e010SDavid du Colombier  * noop
273*70b8e010SDavid du Colombier  */
274*70b8e010SDavid du Colombier static long
275*70b8e010SDavid du Colombier noswal(long x)
276*70b8e010SDavid du Colombier {
277*70b8e010SDavid du Colombier 	return x;
278*70b8e010SDavid du Colombier }
279*70b8e010SDavid du Colombier /*
2803e12c5d1SDavid du Colombier  *	Crack a normal a.out-type header
2813e12c5d1SDavid du Colombier  */
2827dd7cddfSDavid du Colombier static int
2837dd7cddfSDavid du Colombier adotout(int fd, Fhdr *fp, ExecHdr *hp)
2843e12c5d1SDavid du Colombier {
2857dd7cddfSDavid du Colombier 	long pgsize;
2863e12c5d1SDavid du Colombier 
2877dd7cddfSDavid du Colombier 	USED(fd);
2887dd7cddfSDavid du Colombier 	pgsize = mach->pgsize;
289219b2ee8SDavid du Colombier 	settext(fp, hp->e.entry, pgsize+sizeof(Exec),
290219b2ee8SDavid du Colombier 			hp->e.text, sizeof(Exec));
291219b2ee8SDavid du Colombier 	setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
292219b2ee8SDavid du Colombier 		hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss);
2933e12c5d1SDavid du Colombier 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
2947dd7cddfSDavid du Colombier 	return 1;
2953e12c5d1SDavid du Colombier }
2963e12c5d1SDavid du Colombier 
2973e12c5d1SDavid du Colombier /*
2983e12c5d1SDavid du Colombier  *	68020 2.out and 68020 bootable images
2993e12c5d1SDavid du Colombier  *	386I 8.out and 386I bootable images
3007dd7cddfSDavid du Colombier  *	alpha plan9-style bootable images for axp "headerless" boot
3013e12c5d1SDavid du Colombier  *
3023e12c5d1SDavid du Colombier  */
3037dd7cddfSDavid du Colombier static int
3047dd7cddfSDavid du Colombier common(int fd, Fhdr *fp, ExecHdr *hp)
3053e12c5d1SDavid du Colombier {
3067dd7cddfSDavid du Colombier 	long kbase;
3073e12c5d1SDavid du Colombier 
3087dd7cddfSDavid du Colombier 	adotout(fd, fp, hp);
3099a747e4fSDavid du Colombier 	if(hp->e.magic & DYN_MAGIC) {
3109a747e4fSDavid du Colombier 		fp->txtaddr = 0;
3119a747e4fSDavid du Colombier 		fp->dataddr = fp->txtsz;
3129a747e4fSDavid du Colombier 		return 1;
3139a747e4fSDavid du Colombier 	}
3147dd7cddfSDavid du Colombier 	kbase = mach->kbase;
3157dd7cddfSDavid du Colombier 	if ((fp->entry & kbase) == kbase) {		/* Boot image */
3163e12c5d1SDavid du Colombier 		switch(fp->type) {
3173e12c5d1SDavid du Colombier 		case F68020:
3183e12c5d1SDavid du Colombier 			fp->type = F68020B;
3193e12c5d1SDavid du Colombier 			fp->name = "68020 plan 9 boot image";
320219b2ee8SDavid du Colombier 			fp->hdrsz = 0;		/* header stripped */
3213e12c5d1SDavid du Colombier 			break;
3223e12c5d1SDavid du Colombier 		case FI386:
3233e12c5d1SDavid du Colombier 			fp->type = FI386B;
324219b2ee8SDavid du Colombier 			fp->txtaddr = sizeof(Exec);
3253e12c5d1SDavid du Colombier 			fp->name = "386 plan 9 boot image";
326219b2ee8SDavid du Colombier 			fp->hdrsz = 0;		/* header stripped */
327219b2ee8SDavid du Colombier 			fp->dataddr = fp->txtaddr+fp->txtsz;
3283e12c5d1SDavid du Colombier 			break;
3297dd7cddfSDavid du Colombier 		case FARM:
33080ee5cbfSDavid du Colombier 			fp->txtaddr = kbase+0x8010;
3317dd7cddfSDavid du Colombier 			fp->name = "ARM plan 9 boot image";
3327dd7cddfSDavid du Colombier 			fp->hdrsz = 0;		/* header stripped */
3337dd7cddfSDavid du Colombier 			fp->dataddr = fp->txtaddr+fp->txtsz;
3347dd7cddfSDavid du Colombier 			return 1;
3357dd7cddfSDavid du Colombier 		case FALPHA:
3367dd7cddfSDavid du Colombier 			fp->type = FALPHAB;
3377dd7cddfSDavid du Colombier 			fp->txtaddr = fp->entry;
3389a747e4fSDavid du Colombier 			fp->name = "alpha plan 9 boot image?";
3397dd7cddfSDavid du Colombier 			fp->hdrsz = 0;		/* header stripped */
3407dd7cddfSDavid du Colombier 			fp->dataddr = fp->txtaddr+fp->txtsz;
3417dd7cddfSDavid du Colombier 			break;
3429a747e4fSDavid du Colombier 		case FPOWER:
3439a747e4fSDavid du Colombier 			fp->type = FPOWERB;
3449a747e4fSDavid du Colombier 			fp->txtaddr = fp->entry;
3459a747e4fSDavid du Colombier 			fp->name = "power plan 9 boot image";
3467dd7cddfSDavid du Colombier 			fp->hdrsz = 0;		/* header stripped */
3479a747e4fSDavid du Colombier 			fp->dataddr = fp->txtaddr+fp->txtsz;
3489a747e4fSDavid du Colombier 			break;
3493e12c5d1SDavid du Colombier 		default:
3503e12c5d1SDavid du Colombier 			break;
3513e12c5d1SDavid du Colombier 		}
3523e12c5d1SDavid du Colombier 		fp->txtaddr |= kbase;
3533e12c5d1SDavid du Colombier 		fp->entry |= kbase;
3543e12c5d1SDavid du Colombier 		fp->dataddr |= kbase;
3553e12c5d1SDavid du Colombier 	}
3567dd7cddfSDavid du Colombier 	return 1;
3573e12c5d1SDavid du Colombier }
3583e12c5d1SDavid du Colombier 
3593e12c5d1SDavid du Colombier /*
3603e12c5d1SDavid du Colombier  *	mips bootable image.
3613e12c5d1SDavid du Colombier  */
3627dd7cddfSDavid du Colombier static int
3637dd7cddfSDavid du Colombier mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
3643e12c5d1SDavid du Colombier {
3657dd7cddfSDavid du Colombier 	USED(fd);
3663e12c5d1SDavid du Colombier 	switch(hp->e.amagic) {
3673e12c5d1SDavid du Colombier 	default:
3683e12c5d1SDavid du Colombier 	case 0407:	/* some kind of mips */
3693e12c5d1SDavid du Colombier 		fp->type = FMIPSB;
3703e12c5d1SDavid du Colombier 		settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize,
3713e12c5d1SDavid du Colombier 					sizeof(struct mipsexec)+4);
3723e12c5d1SDavid du Colombier 		setdata(fp, hp->e.data_start, hp->e.dsize,
3733e12c5d1SDavid du Colombier 				fp->txtoff+hp->e.tsize, hp->e.bsize);
3743e12c5d1SDavid du Colombier 		break;
3753e12c5d1SDavid du Colombier 	case 0413:	/* some kind of mips */
3763e12c5d1SDavid du Colombier 		fp->type = FMIPSB;
3773e12c5d1SDavid du Colombier 		settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 0);
3783e12c5d1SDavid du Colombier 		setdata(fp, hp->e.data_start, hp->e.dsize, hp->e.tsize,
3793e12c5d1SDavid du Colombier 					hp->e.bsize);
3803e12c5d1SDavid du Colombier 		break;
3813e12c5d1SDavid du Colombier 	}
3823e12c5d1SDavid du Colombier 	setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
383219b2ee8SDavid du Colombier 	fp->hdrsz = 0;		/* header stripped */
3847dd7cddfSDavid du Colombier 	return 1;
3853e12c5d1SDavid du Colombier }
386219b2ee8SDavid du Colombier 
3873e12c5d1SDavid du Colombier /*
388219b2ee8SDavid du Colombier  *	mips4k bootable image.
3893e12c5d1SDavid du Colombier  */
3907dd7cddfSDavid du Colombier static int
3917dd7cddfSDavid du Colombier mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
3923e12c5d1SDavid du Colombier {
3937dd7cddfSDavid du Colombier 	USED(fd);
394219b2ee8SDavid du Colombier 	switch(hp->e.h.amagic) {
395219b2ee8SDavid du Colombier 	default:
396219b2ee8SDavid du Colombier 	case 0407:	/* some kind of mips */
397219b2ee8SDavid du Colombier 		fp->type = FMIPSB;
398219b2ee8SDavid du Colombier 		settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize,
399219b2ee8SDavid du Colombier 					sizeof(struct mips4kexec));
400219b2ee8SDavid du Colombier 		setdata(fp, hp->e.h.data_start, hp->e.h.dsize,
401219b2ee8SDavid du Colombier 				fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
402219b2ee8SDavid du Colombier 		break;
403219b2ee8SDavid du Colombier 	case 0413:	/* some kind of mips */
404219b2ee8SDavid du Colombier 		fp->type = FMIPSB;
405219b2ee8SDavid du Colombier 		settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 0);
406219b2ee8SDavid du Colombier 		setdata(fp, hp->e.h.data_start, hp->e.h.dsize, hp->e.h.tsize,
407219b2ee8SDavid du Colombier 					hp->e.h.bsize);
408219b2ee8SDavid du Colombier 		break;
4093e12c5d1SDavid du Colombier 	}
410219b2ee8SDavid du Colombier 	setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
411219b2ee8SDavid du Colombier 	fp->hdrsz = 0;		/* header stripped */
4127dd7cddfSDavid du Colombier 	return 1;
413219b2ee8SDavid du Colombier }
414219b2ee8SDavid du Colombier 
4153e12c5d1SDavid du Colombier /*
4163e12c5d1SDavid du Colombier  *	sparc bootable image
4173e12c5d1SDavid du Colombier  */
4187dd7cddfSDavid du Colombier static int
4197dd7cddfSDavid du Colombier sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
4203e12c5d1SDavid du Colombier {
4217dd7cddfSDavid du Colombier 	USED(fd);
4223e12c5d1SDavid du Colombier 	fp->type = FSPARCB;
4233e12c5d1SDavid du Colombier 	settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
4243e12c5d1SDavid du Colombier 					sizeof(struct sparcexec));
4253e12c5d1SDavid du Colombier 	setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
4263e12c5d1SDavid du Colombier 					fp->txtoff+hp->e.stext, hp->e.sbss);
4273e12c5d1SDavid du Colombier 	setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
428219b2ee8SDavid du Colombier 	fp->hdrsz = 0;		/* header stripped */
4297dd7cddfSDavid du Colombier 	return 1;
4303e12c5d1SDavid du Colombier }
4313e12c5d1SDavid du Colombier 
4323e12c5d1SDavid du Colombier /*
4333e12c5d1SDavid du Colombier  *	next bootable image
4343e12c5d1SDavid du Colombier  */
4357dd7cddfSDavid du Colombier static int
4367dd7cddfSDavid du Colombier nextboot(int fd, Fhdr *fp, ExecHdr *hp)
4373e12c5d1SDavid du Colombier {
4387dd7cddfSDavid du Colombier 	USED(fd);
4393e12c5d1SDavid du Colombier 	fp->type = FNEXTB;
4403e12c5d1SDavid du Colombier 	settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
4413e12c5d1SDavid du Colombier 					hp->e.texts.size, hp->e.texts.offset);
4423e12c5d1SDavid du Colombier 	setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
4433e12c5d1SDavid du Colombier 				hp->e.datas.offset, hp->e.bsss.size);
4443e12c5d1SDavid du Colombier 	setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
4453e12c5d1SDavid du Colombier 					hp->e.symc.symoff);
446219b2ee8SDavid du Colombier 	fp->hdrsz = 0;		/* header stripped */
4477dd7cddfSDavid du Colombier 	return 1;
4483e12c5d1SDavid du Colombier }
4493e12c5d1SDavid du Colombier 
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier /*
452*70b8e010SDavid du Colombier  * Elf32 binaries.
4537dd7cddfSDavid du Colombier  */
4547dd7cddfSDavid du Colombier static int
4557dd7cddfSDavid du Colombier elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier 
458*70b8e010SDavid du Colombier 	long (*swal)(long);
459*70b8e010SDavid du Colombier 	ushort (*swab)(ushort);
4607dd7cddfSDavid du Colombier 	Ehdr *ep;
461*70b8e010SDavid du Colombier 	Phdr *ph;
462*70b8e010SDavid du Colombier 	int i, it, id, is, phsz;
4637dd7cddfSDavid du Colombier 
464*70b8e010SDavid du Colombier 	/* bitswap the header according to the DATA format */
4657dd7cddfSDavid du Colombier 	ep = &hp->e;
466*70b8e010SDavid du Colombier 	if(ep->ident[CLASS] != ELFCLASS32) {
467*70b8e010SDavid du Colombier 		werrstr("bad ELF class - not 32 bit");
468*70b8e010SDavid du Colombier 		return 0;
469*70b8e010SDavid du Colombier 	}
470*70b8e010SDavid du Colombier 	if(ep->ident[DATA] == ELFDATA2LSB) {
471*70b8e010SDavid du Colombier 		swab = leswab;
472*70b8e010SDavid du Colombier 		swal = leswal;
473*70b8e010SDavid du Colombier 	} else if(ep->ident[DATA] == ELFDATA2MSB) {
474*70b8e010SDavid du Colombier 		swab = beswab;
475*70b8e010SDavid du Colombier 		swal = beswal;
476*70b8e010SDavid du Colombier 	} else {
477*70b8e010SDavid du Colombier 		werrstr("bad ELF encoding - not big or little endian");
478*70b8e010SDavid du Colombier 		return 0;
479*70b8e010SDavid du Colombier 	}
480*70b8e010SDavid du Colombier 
481*70b8e010SDavid du Colombier 	ep->type = swab(ep->type);
482*70b8e010SDavid du Colombier 	ep->machine = swab(ep->machine);
483*70b8e010SDavid du Colombier 	ep->version = swal(ep->version);
484*70b8e010SDavid du Colombier 	ep->elfentry = swal(ep->elfentry);
485*70b8e010SDavid du Colombier 	ep->phoff = swal(ep->phoff);
486*70b8e010SDavid du Colombier 	ep->shoff = swal(ep->shoff);
487*70b8e010SDavid du Colombier 	ep->flags = swal(ep->flags);
488*70b8e010SDavid du Colombier 	ep->ehsize = swab(ep->ehsize);
489*70b8e010SDavid du Colombier 	ep->phentsize = swab(ep->phentsize);
490*70b8e010SDavid du Colombier 	ep->phnum = swab(ep->phnum);
491*70b8e010SDavid du Colombier 	ep->shentsize = swab(ep->shentsize);
492*70b8e010SDavid du Colombier 	ep->shnum = swab(ep->shnum);
493*70b8e010SDavid du Colombier 	ep->shstrndx = swab(ep->shstrndx);
494*70b8e010SDavid du Colombier 	if(ep->type != EXEC || ep->version != CURRENT)
4957dd7cddfSDavid du Colombier 		return 0;
4967dd7cddfSDavid du Colombier 
497*70b8e010SDavid du Colombier 	/* we could definitely support a lot more machines here */
4987dd7cddfSDavid du Colombier 	fp->magic = ELF_MAG;
4997dd7cddfSDavid du Colombier 	fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
500*70b8e010SDavid du Colombier 	switch(ep->machine) {
501*70b8e010SDavid du Colombier 	case I386:
502*70b8e010SDavid du Colombier 		mach = &mi386;
503*70b8e010SDavid du Colombier 		fp->type = FI386;
504*70b8e010SDavid du Colombier 		break;
505*70b8e010SDavid du Colombier 	case MIPS:
506*70b8e010SDavid du Colombier 		mach = &mmips;
507*70b8e010SDavid du Colombier 		fp->type = FMIPS;
508*70b8e010SDavid du Colombier 		break;
509*70b8e010SDavid du Colombier 	case POWER:
510*70b8e010SDavid du Colombier 		mach = &mpower;
511*70b8e010SDavid du Colombier 		fp->type = FPOWER;
512*70b8e010SDavid du Colombier 		break;
513*70b8e010SDavid du Colombier 	default:
5147dd7cddfSDavid du Colombier 		return 0;
5157dd7cddfSDavid du Colombier 	}
5167dd7cddfSDavid du Colombier 
517*70b8e010SDavid du Colombier 	if(ep->phentsize != sizeof(Phdr)) {
518*70b8e010SDavid du Colombier 		werrstr("bad ELF header size");
519*70b8e010SDavid du Colombier 		return 0;
520*70b8e010SDavid du Colombier 	}
521*70b8e010SDavid du Colombier 	phsz = sizeof(Phdr)*ep->phnum;
522*70b8e010SDavid du Colombier 	ph = malloc(phsz);
523*70b8e010SDavid du Colombier 	if(!ph)
524*70b8e010SDavid du Colombier 		return 0;
525*70b8e010SDavid du Colombier 	seek(fd, ep->phoff, 0);
526*70b8e010SDavid du Colombier 	if(read(fd, ph, phsz) < 0) {
527*70b8e010SDavid du Colombier 		free(ph);
528*70b8e010SDavid du Colombier 		return 0;
529*70b8e010SDavid du Colombier 	}
530*70b8e010SDavid du Colombier 	hswal((long*)ph, phsz/sizeof(long), swal);
5317dd7cddfSDavid du Colombier 
532*70b8e010SDavid du Colombier 	/* find text, data and symbols and install them */
533*70b8e010SDavid du Colombier 	it = id = is = -1;
534*70b8e010SDavid du Colombier 	for(i = 0; i < ep->phnum; i++) {
535*70b8e010SDavid du Colombier 		if(ph[i].type == LOAD
536*70b8e010SDavid du Colombier 		&& (ph[i].flags & (R|X)) == (R|X) && it == -1)
537*70b8e010SDavid du Colombier 			it = i;
538*70b8e010SDavid du Colombier 		else if(ph[i].type == LOAD
539*70b8e010SDavid du Colombier 		&& (ph[i].flags & (R|W)) == (R|W) && id == -1)
540*70b8e010SDavid du Colombier 			id = i;
541*70b8e010SDavid du Colombier 		else if(ph[i].type == NOPTYPE && is == -1)
542*70b8e010SDavid du Colombier 			is = i;
543*70b8e010SDavid du Colombier 	}
544*70b8e010SDavid du Colombier 	if(it == -1 || id == -1) {
545*70b8e010SDavid du Colombier 		werrstr("No TEXT or DATA sections");
546*70b8e010SDavid du Colombier 		free(ph);
547*70b8e010SDavid du Colombier 		return 0;
5487dd7cddfSDavid du Colombier 	}
5497dd7cddfSDavid du Colombier 
550*70b8e010SDavid du Colombier 	settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
551*70b8e010SDavid du Colombier 	setdata(fp, ph[id].vaddr, ph[id].memsz, ph[id].offset, ph[id].memsz - ph[id].filesz);
552*70b8e010SDavid du Colombier 	if(is != -1)
553*70b8e010SDavid du Colombier 		setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
554*70b8e010SDavid du Colombier 	free(ph);
5557dd7cddfSDavid du Colombier 	return 1;
5567dd7cddfSDavid du Colombier }
5577dd7cddfSDavid du Colombier 
5587dd7cddfSDavid du Colombier /*
5597dd7cddfSDavid du Colombier  * alpha bootable
5607dd7cddfSDavid du Colombier  */
5617dd7cddfSDavid du Colombier static int
5627dd7cddfSDavid du Colombier alphadotout(int fd, Fhdr *fp, ExecHdr *hp)
5637dd7cddfSDavid du Colombier {
5647dd7cddfSDavid du Colombier 	long kbase;
5657dd7cddfSDavid du Colombier 
5667dd7cddfSDavid du Colombier 	USED(fd);
5677dd7cddfSDavid du Colombier 	settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec));
5687dd7cddfSDavid du Colombier 	setdata(fp, fp->txtsz+sizeof(Exec), hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss);
5697dd7cddfSDavid du Colombier 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
5707dd7cddfSDavid du Colombier 
5717dd7cddfSDavid du Colombier 	/*
5727dd7cddfSDavid du Colombier 	 * Boot images have some of bits <31:28> set:
5737dd7cddfSDavid du Colombier 	 *	0x80400000	kernel
5747dd7cddfSDavid du Colombier 	 *	0x20000000	secondary bootstrap
5757dd7cddfSDavid du Colombier 	 */
5767dd7cddfSDavid du Colombier 	kbase = 0xF0000000;
5777dd7cddfSDavid du Colombier 	if (fp->entry & kbase) {
5787dd7cddfSDavid du Colombier 		fp->txtaddr = fp->entry;
5797dd7cddfSDavid du Colombier 		fp->name = "alpha plan 9 boot image";
5807dd7cddfSDavid du Colombier 		fp->hdrsz = 0;		/* header stripped */
5817dd7cddfSDavid du Colombier 		fp->dataddr = fp->entry+fp->txtsz;
5827dd7cddfSDavid du Colombier 	}
5837dd7cddfSDavid du Colombier 	return 1;
5847dd7cddfSDavid du Colombier }
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier /*
5877dd7cddfSDavid du Colombier  * (Free|Net)BSD ARM header.
5887dd7cddfSDavid du Colombier  */
5897dd7cddfSDavid du Colombier static int
5907dd7cddfSDavid du Colombier armdotout(int fd, Fhdr *fp, ExecHdr *hp)
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier 	long kbase;
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier 	USED(fd);
5957dd7cddfSDavid du Colombier 	settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec));
5967dd7cddfSDavid du Colombier 	setdata(fp, fp->txtsz, hp->e.data, fp->txtsz, hp->e.bss);
5977dd7cddfSDavid du Colombier 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
5987dd7cddfSDavid du Colombier 
5997dd7cddfSDavid du Colombier 	kbase = 0xF0000000;
6007dd7cddfSDavid du Colombier 	if ((fp->entry & kbase) == kbase) {		/* Boot image */
6017dd7cddfSDavid du Colombier 		fp->txtaddr = kbase+sizeof(Exec);
6027dd7cddfSDavid du Colombier 		fp->name = "ARM *BSD boot image";
6037dd7cddfSDavid du Colombier 		fp->hdrsz = 0;		/* header stripped */
6047dd7cddfSDavid du Colombier 		fp->dataddr = kbase+fp->txtsz;
6057dd7cddfSDavid du Colombier 	}
6067dd7cddfSDavid du Colombier 	return 1;
6077dd7cddfSDavid du Colombier }
6083e12c5d1SDavid du Colombier 
6093e12c5d1SDavid du Colombier static void
6103e12c5d1SDavid du Colombier settext(Fhdr *fp, long e, long a, long s, long off)
6113e12c5d1SDavid du Colombier {
6123e12c5d1SDavid du Colombier 	fp->txtaddr = a;
6133e12c5d1SDavid du Colombier 	fp->entry = e;
6143e12c5d1SDavid du Colombier 	fp->txtsz = s;
6153e12c5d1SDavid du Colombier 	fp->txtoff = off;
6163e12c5d1SDavid du Colombier }
6173e12c5d1SDavid du Colombier static void
6183e12c5d1SDavid du Colombier setdata(Fhdr *fp, long a, long s, long off, long bss)
6193e12c5d1SDavid du Colombier {
6203e12c5d1SDavid du Colombier 	fp->dataddr = a;
6213e12c5d1SDavid du Colombier 	fp->datsz = s;
6223e12c5d1SDavid du Colombier 	fp->datoff = off;
6233e12c5d1SDavid du Colombier 	fp->bsssz = bss;
6243e12c5d1SDavid du Colombier }
6253e12c5d1SDavid du Colombier static void
6263e12c5d1SDavid du Colombier setsym(Fhdr *fp, long sy, long sppc, long lnpc, long symoff)
6273e12c5d1SDavid du Colombier {
6283e12c5d1SDavid du Colombier 	fp->symsz = sy;
6293e12c5d1SDavid du Colombier 	fp->symoff = symoff;
6303e12c5d1SDavid du Colombier 	fp->sppcsz = sppc;
6313e12c5d1SDavid du Colombier 	fp->sppcoff = fp->symoff+fp->symsz;
6323e12c5d1SDavid du Colombier 	fp->lnpcsz = lnpc;
6333e12c5d1SDavid du Colombier 	fp->lnpcoff = fp->sppcoff+fp->sppcsz;
6343e12c5d1SDavid du Colombier }
6353e12c5d1SDavid du Colombier 
636219b2ee8SDavid du Colombier 
637219b2ee8SDavid du Colombier static long
638219b2ee8SDavid du Colombier _round(long a, long b)
639219b2ee8SDavid du Colombier {
640219b2ee8SDavid du Colombier 	long w;
641219b2ee8SDavid du Colombier 
642219b2ee8SDavid du Colombier 	w = (a/b)*b;
643219b2ee8SDavid du Colombier 	if (a!=w)
644219b2ee8SDavid du Colombier 		w += b;
645219b2ee8SDavid du Colombier 	return(w);
646219b2ee8SDavid du Colombier }
647