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