xref: /plan9-contrib/sys/src/libmach/executable.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include	<u.h>
2 #include	<libc.h>
3 #include	<bio.h>
4 #include	<bootexec.h>
5 #include	<mach.h>
6 #include	"elf.h"
7 
8 /*
9  *	All a.out header types.  The dummy entry allows canonical
10  *	processing of the union as a sequence of longs
11  */
12 
13 typedef struct {
14 	union{
15 		struct {
16 			Exec;		/* a.out.h */
17 			uvlong hdr[1];
18 		};
19 		Ehdr;			/* elf.h */
20 		struct mipsexec;	/* bootexec.h */
21 		struct mips4kexec;	/* bootexec.h */
22 		struct sparcexec;	/* bootexec.h */
23 		struct nextexec;	/* bootexec.h */
24 	} e;
25 	long dummy;			/* padding to ensure extra long */
26 } ExecHdr;
27 
28 static	int	nextboot(int, Fhdr*, ExecHdr*);
29 static	int	sparcboot(int, Fhdr*, ExecHdr*);
30 static	int	mipsboot(int, Fhdr*, ExecHdr*);
31 static	int	mips4kboot(int, Fhdr*, ExecHdr*);
32 static	int	common(int, Fhdr*, ExecHdr*);
33 static	int	commonllp64(int, Fhdr*, ExecHdr*);
34 static	int	adotout(int, Fhdr*, ExecHdr*);
35 static	int	elfdotout(int, Fhdr*, ExecHdr*);
36 static	int	armdotout(int, Fhdr*, ExecHdr*);
37 static	int	alphadotout(int, Fhdr*, ExecHdr*);
38 static	void	setsym(Fhdr*, long, long, long, vlong);
39 static	void	setdata(Fhdr*, uvlong, long, vlong, long);
40 static	void	settext(Fhdr*, uvlong, uvlong, long, vlong);
41 static	void	hswal(void*, int, ulong(*)(ulong));
42 static	uvlong	_round(uvlong, ulong);
43 
44 /*
45  *	definition of per-executable file type structures
46  */
47 
48 typedef struct Exectable{
49 	long	magic;			/* big-endian magic number of file */
50 	char	*name;			/* executable identifier */
51 	char	*dlmname;		/* dynamically loadable module identifier */
52 	int	type;			/* Internal code */
53 	Mach	*mach;			/* Per-machine data */
54 	long	hsize;			/* header size */
55 	ulong	(*swal)(ulong);		/* beswal or leswal */
56 	int	(*hparse)(int, Fhdr*, ExecHdr*);
57 } ExecTable;
58 
59 extern	Mach	mmips;
60 extern	Mach	mmips2le;
61 extern	Mach	mmips2be;
62 extern	Mach	msparc;
63 extern	Mach	msparc64;
64 extern	Mach	m68020;
65 extern	Mach	mi386;
66 extern	Mach	mamd64;
67 extern	Mach	marm;
68 extern	Mach	mpower;
69 extern	Mach	malpha;
70 
71 ExecTable exectab[] =
72 {
73 	{ V_MAGIC,			/* Mips v.out */
74 		"mips plan 9 executable",
75 		"mips plan 9 dlm",
76 		FMIPS,
77 		&mmips,
78 		sizeof(Exec),
79 		beswal,
80 		adotout },
81 	{ M_MAGIC,			/* Mips 4.out */
82 		"mips 4k plan 9 executable BE",
83 		"mips 4k plan 9 dlm BE",
84 		FMIPS2BE,
85 		&mmips2be,
86 		sizeof(Exec),
87 		beswal,
88 		adotout },
89 	{ N_MAGIC,			/* Mips 0.out */
90 		"mips 4k plan 9 executable LE",
91 		"mips 4k plan 9 dlm LE",
92 		FMIPS2LE,
93 		&mmips2le,
94 		sizeof(Exec),
95 		beswal,
96 		adotout },
97 	{ 0x160<<16,			/* Mips boot image */
98 		"mips plan 9 boot image",
99 		nil,
100 		FMIPSB,
101 		&mmips,
102 		sizeof(struct mipsexec),
103 		beswal,
104 		mipsboot },
105 	{ (0x160<<16)|3,		/* Mips boot image */
106 		"mips 4k plan 9 boot image",
107 		nil,
108 		FMIPSB,
109 		&mmips2be,
110 		sizeof(struct mips4kexec),
111 		beswal,
112 		mips4kboot },
113 	{ K_MAGIC,			/* Sparc k.out */
114 		"sparc plan 9 executable",
115 		"sparc plan 9 dlm",
116 		FSPARC,
117 		&msparc,
118 		sizeof(Exec),
119 		beswal,
120 		adotout },
121 	{ 0x01030107, 			/* Sparc boot image */
122 		"sparc plan 9 boot image",
123 		nil,
124 		FSPARCB,
125 		&msparc,
126 		sizeof(struct sparcexec),
127 		beswal,
128 		sparcboot },
129 	{ U_MAGIC,			/* Sparc64 u.out */
130 		"sparc64 plan 9 executable",
131 		"sparc64 plan 9 dlm",
132 		FSPARC64,
133 		&msparc64,
134 		sizeof(Exec),
135 		beswal,
136 		adotout },
137 	{ A_MAGIC,			/* 68020 2.out & boot image */
138 		"68020 plan 9 executable",
139 		"68020 plan 9 dlm",
140 		F68020,
141 		&m68020,
142 		sizeof(Exec),
143 		beswal,
144 		common },
145 	{ 0xFEEDFACE,			/* Next boot image */
146 		"next plan 9 boot image",
147 		nil,
148 		FNEXTB,
149 		&m68020,
150 		sizeof(struct nextexec),
151 		beswal,
152 		nextboot },
153 	{ I_MAGIC,			/* I386 8.out & boot image */
154 		"386 plan 9 executable",
155 		"386 plan 9 dlm",
156 		FI386,
157 		&mi386,
158 		sizeof(Exec),
159 		beswal,
160 		common },
161 	{ S_MAGIC,			/* amd64 6.out & boot image */
162 		"amd64 plan 9 executable",
163 		"amd64 plan 9 dlm",
164 		FAMD64,
165 		&mamd64,
166 		sizeof(Exec)+8,
167 		nil,
168 		commonllp64 },
169 	{ Q_MAGIC,			/* PowerPC q.out & boot image */
170 		"power plan 9 executable",
171 		"power plan 9 dlm",
172 		FPOWER,
173 		&mpower,
174 		sizeof(Exec),
175 		beswal,
176 		common },
177 	{ ELF_MAG,			/* any elf32 */
178 		"elf executable",
179 		nil,
180 		FNONE,
181 		&mi386,
182 		sizeof(Ehdr),
183 		nil,
184 		elfdotout },
185 	{ E_MAGIC,			/* Arm 5.out */
186 		"arm plan 9 executable",
187 		"arm plan 9 dlm",
188 		FARM,
189 		&marm,
190 		sizeof(Exec),
191 		beswal,
192 		common },
193 	{ (143<<16)|0413,		/* (Free|Net)BSD Arm */
194 		"arm *bsd executable",
195 		nil,
196 		FARM,
197 		&marm,
198 		sizeof(Exec),
199 		leswal,
200 		armdotout },
201 	{ L_MAGIC,			/* alpha 7.out */
202 		"alpha plan 9 executable",
203 		"alpha plan 9 dlm",
204 		FALPHA,
205 		&malpha,
206 		sizeof(Exec),
207 		beswal,
208 		common },
209 	{ 0x0700e0c3,			/* alpha boot image */
210 		"alpha plan 9 boot image",
211 		nil,
212 		FALPHAB,
213 		&malpha,
214 		sizeof(Exec),
215 		beswal,
216 		alphadotout },
217 	{ 0 },
218 };
219 
220 Mach	*mach = &mi386;			/* Global current machine table */
221 
222 static ExecTable*
223 couldbe4k(ExecTable *mp)
224 {
225 	Dir *d;
226 	ExecTable *f;
227 
228 	if((d=dirstat("/proc/1/regs")) == nil)
229 		return mp;
230 	if(d->length < 32*8){		/* R3000 */
231 		free(d);
232 		return mp;
233 	}
234 	free(d);
235 	for (f = exectab; f->magic; f++)
236 		if(f->magic == M_MAGIC) {
237 			f->name = "mips plan 9 executable on mips2 kernel";
238 			return f;
239 		}
240 	return mp;
241 }
242 
243 int
244 crackhdr(int fd, Fhdr *fp)
245 {
246 	ExecTable *mp;
247 	ExecHdr d;
248 	int nb, ret;
249 	ulong magic;
250 
251 	fp->type = FNONE;
252 	nb = read(fd, (char *)&d.e, sizeof(d.e));
253 	if (nb <= 0)
254 		return 0;
255 
256 	ret = 0;
257 	fp->magic = magic = beswal(d.e.magic);		/* big-endian */
258 	for (mp = exectab; mp->magic; mp++) {
259 		if (nb < mp->hsize)
260 			continue;
261 		if (mp->magic == (magic & ~DYN_MAGIC)) {
262 			if(mp->magic == V_MAGIC)
263 				mp = couldbe4k(mp);
264 
265 			fp->type = mp->type;
266 			if ((magic & DYN_MAGIC) && mp->dlmname != nil)
267 				fp->name = mp->dlmname;
268 			else
269 				fp->name = mp->name;
270 			fp->hdrsz = mp->hsize;		/* zero on bootables */
271 			mach = mp->mach;
272 			if(mp->swal != nil)
273 				hswal(&d, sizeof(d.e)/sizeof(ulong), mp->swal);
274 			ret = mp->hparse(fd, fp, &d);
275 			seek(fd, mp->hsize, 0);		/* seek to end of header */
276 			break;
277 		}
278 	}
279 	if(mp->magic == 0)
280 		werrstr("unknown header type");
281 	return ret;
282 }
283 
284 /*
285  * Convert header to canonical form
286  */
287 static void
288 hswal(void *v, int n, ulong (*swap)(ulong))
289 {
290 	ulong *ulp;
291 
292 	for(ulp = v; n--; ulp++)
293 		*ulp = (*swap)(*ulp);
294 }
295 
296 /*
297  *	Crack a normal a.out-type header
298  */
299 static int
300 adotout(int fd, Fhdr *fp, ExecHdr *hp)
301 {
302 	long pgsize;
303 
304 	USED(fd);
305 	pgsize = mach->pgsize;
306 	settext(fp, hp->e.entry, pgsize+sizeof(Exec),
307 			hp->e.text, sizeof(Exec));
308 	setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
309 		hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss);
310 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
311 	return 1;
312 }
313 
314 static void
315 commonboot(Fhdr *fp)
316 {
317 	uvlong kbase;
318 
319 	kbase = mach->kbase;
320 	if ((fp->entry & kbase) != kbase)
321 		return;
322 
323 	switch(fp->type) {				/* boot image */
324 	case F68020:
325 		fp->type = F68020B;
326 		fp->name = "68020 plan 9 boot image";
327 		break;
328 	case FI386:
329 		fp->type = FI386B;
330 		fp->txtaddr = (u32int)fp->entry;
331 		fp->name = "386 plan 9 boot image";
332 		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
333 		break;
334 	case FARM:
335 		fp->txtaddr = kbase+0x8010;
336 		fp->name = "ARM plan 9 boot image";
337 		fp->dataddr = fp->txtaddr+fp->txtsz;
338 		return;
339 	case FALPHA:
340 		fp->type = FALPHAB;
341 		fp->txtaddr = (u32int)fp->entry;
342 		fp->name = "alpha plan 9 boot image?";
343 		fp->dataddr = fp->txtaddr+fp->txtsz;
344 		break;
345 	case FPOWER:
346 		fp->type = FPOWERB;
347 		fp->txtaddr = (u32int)fp->entry;
348 		fp->name = "power plan 9 boot image";
349 		fp->dataddr = fp->txtaddr+fp->txtsz;
350 		break;
351 	case FAMD64:
352 		fp->type = FAMD64B;
353 		fp->txtaddr = fp->entry;
354 		fp->name = "amd64 plan 9 boot image";
355 		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
356 		break;
357 	default:
358 		return;
359 	}
360 	fp->hdrsz = 0;					/* header stripped */
361 }
362 
363 /*
364  *	68020 2.out and 68020 bootable images
365  *	386I 8.out and 386I bootable images
366  *	alpha plan9-style bootable images for axp "headerless" boot
367  *
368  */
369 static int
370 common(int fd, Fhdr *fp, ExecHdr *hp)
371 {
372 	adotout(fd, fp, hp);
373 	if(hp->e.magic & DYN_MAGIC) {
374 		fp->txtaddr = 0;
375 		fp->dataddr = fp->txtsz;
376 		return 1;
377 	}
378 	commonboot(fp);
379 	return 1;
380 }
381 
382 static int
383 commonllp64(int, Fhdr *fp, ExecHdr *hp)
384 {
385 	long pgsize;
386 	uvlong entry;
387 
388 	hswal(&hp->e, sizeof(Exec)/sizeof(long), beswal);
389 	if(!(hp->e.magic & HDR_MAGIC))
390 		return 0;
391 
392 	/*
393 	 * There can be more magic here if the
394 	 * header ever needs more expansion.
395 	 * For now just catch use of any of the
396 	 * unused bits.
397 	 */
398 	if((hp->e.magic & ~DYN_MAGIC)>>16)
399 		return 0;
400 	entry = beswav(hp->e.hdr[0]);
401 
402 	pgsize = mach->pgsize;
403 	settext(fp, entry, pgsize+fp->hdrsz, hp->e.text, fp->hdrsz);
404 	setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
405 		hp->e.data, fp->txtsz+fp->hdrsz, hp->e.bss);
406 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
407 
408 	if(hp->e.magic & DYN_MAGIC) {
409 		fp->txtaddr = 0;
410 		fp->dataddr = fp->txtsz;
411 		return 1;
412 	}
413 	commonboot(fp);
414 	return 1;
415 }
416 
417 /*
418  *	mips bootable image.
419  */
420 static int
421 mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
422 {
423 	USED(fd);
424 	switch(hp->e.amagic) {
425 	default:
426 	case 0407:	/* some kind of mips */
427 		fp->type = FMIPSB;
428 		settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize,
429 					sizeof(struct mipsexec)+4);
430 		setdata(fp, hp->e.data_start, hp->e.dsize,
431 				fp->txtoff+hp->e.tsize, hp->e.bsize);
432 		break;
433 	case 0413:	/* some kind of mips */
434 		fp->type = FMIPSB;
435 		settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 0);
436 		setdata(fp, hp->e.data_start, hp->e.dsize, hp->e.tsize,
437 					hp->e.bsize);
438 		break;
439 	}
440 	setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
441 	fp->hdrsz = 0;		/* header stripped */
442 	return 1;
443 }
444 
445 /*
446  *	mips4k bootable image.
447  */
448 static int
449 mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
450 {
451 	USED(fd);
452 	switch(hp->e.h.amagic) {
453 	default:
454 	case 0407:	/* some kind of mips */
455 		fp->type = FMIPSB;
456 		settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize,
457 					sizeof(struct mips4kexec));
458 		setdata(fp, hp->e.h.data_start, hp->e.h.dsize,
459 				fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
460 		break;
461 	case 0413:	/* some kind of mips */
462 		fp->type = FMIPSB;
463 		settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 0);
464 		setdata(fp, hp->e.h.data_start, hp->e.h.dsize, hp->e.h.tsize,
465 					hp->e.h.bsize);
466 		break;
467 	}
468 	setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
469 	fp->hdrsz = 0;		/* header stripped */
470 	return 1;
471 }
472 
473 /*
474  *	sparc bootable image
475  */
476 static int
477 sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
478 {
479 	USED(fd);
480 	fp->type = FSPARCB;
481 	settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
482 					sizeof(struct sparcexec));
483 	setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
484 					fp->txtoff+hp->e.stext, hp->e.sbss);
485 	setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
486 	fp->hdrsz = 0;		/* header stripped */
487 	return 1;
488 }
489 
490 /*
491  *	next bootable image
492  */
493 static int
494 nextboot(int fd, Fhdr *fp, ExecHdr *hp)
495 {
496 	USED(fd);
497 	fp->type = FNEXTB;
498 	settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
499 					hp->e.texts.size, hp->e.texts.offset);
500 	setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
501 				hp->e.datas.offset, hp->e.bsss.size);
502 	setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
503 					hp->e.symc.symoff);
504 	fp->hdrsz = 0;		/* header stripped */
505 	return 1;
506 }
507 
508 /*
509  * Elf32 binaries.
510  */
511 static int
512 elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
513 {
514 
515 	ulong (*swal)(ulong);
516 	ushort (*swab)(ushort);
517 	Ehdr *ep;
518 	Phdr *ph;
519 	int i, it, id, is, phsz;
520 
521 	/* bitswap the header according to the DATA format */
522 	ep = &hp->e;
523 	if(ep->ident[CLASS] != ELFCLASS32) {
524 		werrstr("bad ELF class - not 32 bit");
525 		return 0;
526 	}
527 	if(ep->ident[DATA] == ELFDATA2LSB) {
528 		swab = leswab;
529 		swal = leswal;
530 	} else if(ep->ident[DATA] == ELFDATA2MSB) {
531 		swab = beswab;
532 		swal = beswal;
533 	} else {
534 		werrstr("bad ELF encoding - not big or little endian");
535 		return 0;
536 	}
537 
538 	ep->type = swab(ep->type);
539 	ep->machine = swab(ep->machine);
540 	ep->version = swal(ep->version);
541 	ep->elfentry = swal(ep->elfentry);
542 	ep->phoff = swal(ep->phoff);
543 	ep->shoff = swal(ep->shoff);
544 	ep->flags = swal(ep->flags);
545 	ep->ehsize = swab(ep->ehsize);
546 	ep->phentsize = swab(ep->phentsize);
547 	ep->phnum = swab(ep->phnum);
548 	ep->shentsize = swab(ep->shentsize);
549 	ep->shnum = swab(ep->shnum);
550 	ep->shstrndx = swab(ep->shstrndx);
551 	if(ep->type != EXEC || ep->version != CURRENT)
552 		return 0;
553 
554 	/* we could definitely support a lot more machines here */
555 	fp->magic = ELF_MAG;
556 	fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
557 	switch(ep->machine) {
558 	case I386:
559 		mach = &mi386;
560 		fp->type = FI386;
561 		break;
562 	case MIPS:
563 		mach = &mmips;
564 		fp->type = FMIPS;
565 		break;
566 	case SPARC64:
567 		mach = &msparc64;
568 		fp->type = FSPARC64;
569 		break;
570 	case POWER:
571 		mach = &mpower;
572 		fp->type = FPOWER;
573 		break;
574 	case AMD64:
575 		mach = &mamd64;
576 		fp->type = FAMD64;
577 		break;
578 	default:
579 		return 0;
580 	}
581 
582 	if(ep->phentsize != sizeof(Phdr)) {
583 		werrstr("bad ELF header size");
584 		return 0;
585 	}
586 	phsz = sizeof(Phdr)*ep->phnum;
587 	ph = malloc(phsz);
588 	if(!ph)
589 		return 0;
590 	seek(fd, ep->phoff, 0);
591 	if(read(fd, ph, phsz) < 0) {
592 		free(ph);
593 		return 0;
594 	}
595 	hswal(ph, phsz/sizeof(ulong), swal);
596 
597 	/* find text, data and symbols and install them */
598 	it = id = is = -1;
599 	for(i = 0; i < ep->phnum; i++) {
600 		if(ph[i].type == LOAD
601 		&& (ph[i].flags & (R|X)) == (R|X) && it == -1)
602 			it = i;
603 		else if(ph[i].type == LOAD
604 		&& (ph[i].flags & (R|W)) == (R|W) && id == -1)
605 			id = i;
606 		else if(ph[i].type == NOPTYPE && is == -1)
607 			is = i;
608 	}
609 	if(it == -1 || id == -1) {
610 		/*
611 		 * The SPARC64 boot image is something of an ELF hack.
612 		 * Text+Data+BSS are represented by ph[0].  Symbols
613 		 * are represented by ph[1]:
614 		 *
615 		 *		filesz, memsz, vaddr, paddr, off
616 		 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
617 		 * ph[1] : symsz, lcsz, 0, 0, symoff
618 		 */
619 		if(ep->machine == SPARC64 && ep->phnum == 2) {
620 			ulong txtaddr, txtsz, dataddr, bsssz;
621 
622 			txtaddr = ph[0].vaddr | 0x80000000;
623 			txtsz = ph[0].filesz - ph[0].paddr;
624 			dataddr = txtaddr + txtsz;
625 			bsssz = ph[0].memsz - ph[0].filesz;
626 			settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
627 			setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
628 			setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset);
629 			free(ph);
630 			return 1;
631 		}
632 
633 		werrstr("No TEXT or DATA sections");
634 		free(ph);
635 		return 0;
636 	}
637 
638 	settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
639 	setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
640 	if(is != -1)
641 		setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
642 	free(ph);
643 	return 1;
644 }
645 
646 /*
647  * alpha bootable
648  */
649 static int
650 alphadotout(int fd, Fhdr *fp, ExecHdr *hp)
651 {
652 	uvlong kbase;
653 
654 	USED(fd);
655 	settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec));
656 	setdata(fp, fp->txtsz+sizeof(Exec), hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss);
657 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
658 
659 	/*
660 	 * Boot images have some of bits <31:28> set:
661 	 *	0x80400000	kernel
662 	 *	0x20000000	secondary bootstrap
663 	 */
664 	kbase = 0xF0000000;
665 	if (fp->entry & kbase) {
666 		fp->txtaddr = fp->entry;
667 		fp->name = "alpha plan 9 boot image";
668 		fp->hdrsz = 0;		/* header stripped */
669 		fp->dataddr = fp->entry+fp->txtsz;
670 	}
671 	return 1;
672 }
673 
674 /*
675  * (Free|Net)BSD ARM header.
676  */
677 static int
678 armdotout(int fd, Fhdr *fp, ExecHdr *hp)
679 {
680 	uvlong kbase;
681 
682 	USED(fd);
683 	settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec));
684 	setdata(fp, fp->txtsz, hp->e.data, fp->txtsz, hp->e.bss);
685 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
686 
687 	kbase = 0xF0000000;
688 	if ((fp->entry & kbase) == kbase) {		/* Boot image */
689 		fp->txtaddr = kbase+sizeof(Exec);
690 		fp->name = "ARM *BSD boot image";
691 		fp->hdrsz = 0;		/* header stripped */
692 		fp->dataddr = kbase+fp->txtsz;
693 	}
694 	return 1;
695 }
696 
697 static void
698 settext(Fhdr *fp, uvlong e, uvlong a, long s, vlong off)
699 {
700 	fp->txtaddr = a;
701 	fp->entry = e;
702 	fp->txtsz = s;
703 	fp->txtoff = off;
704 }
705 
706 static void
707 setdata(Fhdr *fp, uvlong a, long s, vlong off, long bss)
708 {
709 	fp->dataddr = a;
710 	fp->datsz = s;
711 	fp->datoff = off;
712 	fp->bsssz = bss;
713 }
714 
715 static void
716 setsym(Fhdr *fp, long symsz, long sppcsz, long lnpcsz, vlong symoff)
717 {
718 	fp->symsz = symsz;
719 	fp->symoff = symoff;
720 	fp->sppcsz = sppcsz;
721 	fp->sppcoff = fp->symoff+fp->symsz;
722 	fp->lnpcsz = lnpcsz;
723 	fp->lnpcoff = fp->sppcoff+fp->sppcsz;
724 }
725 
726 
727 static uvlong
728 _round(uvlong a, ulong b)
729 {
730 	uvlong w;
731 
732 	w = (a/b)*b;
733 	if (a!=w)
734 		w += b;
735 	return(w);
736 }
737