xref: /plan9-contrib/sys/src/libmach/executable.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	<u.h>
2 #include	<libc.h>
3 #include	<bio.h>
4 #include	<bootexec.h>
5 #include	<mach.h>
6 
7 /*
8  *	All a.out header types.  The dummy entry allows canonical
9  *	processing of the union as a sequence of longs
10  */
11 
12 typedef struct {
13 	union{
14 		Exec;			/* in a.out.h */
15 		struct mipsexec;	/* Hobbit uses this header too */
16 		struct mips4kexec;
17 		struct sparcexec;
18 		struct nextexec;
19 		struct i960exec;
20 	} e;
21 	long dummy;		/* padding to ensure extra long */
22 } ExecHdr;
23 
24 static	void	i960boot(Fhdr *, ExecHdr *);
25 static	void	nextboot(Fhdr *, ExecHdr *);
26 static	void	sparcboot(Fhdr *, ExecHdr *);
27 static	void	mipsboot(Fhdr *, ExecHdr *);
28 static	void	mips4kboot(Fhdr *, ExecHdr *);
29 static	void	common(Fhdr *, ExecHdr *);
30 static	void	adotout(Fhdr *, ExecHdr *);
31 static	void	setsym(Fhdr *, long, long, long, long);
32 static	void	setdata(Fhdr *, long, long, long, long);
33 static	void	settext(Fhdr *, long, long, long, long);
34 static	void	hswal(long *, int, long (*) (long));
35 static	long	_round(long, long);
36 
37 /*
38  *	definition of per-executable file type structures
39  */
40 
41 typedef struct Exectable{
42 	long	magic;			/* big-endian magic number of file */
43 	char	*name;			/* executable identifier */
44 	int	type;			/* Internal code */
45 	Mach	*mach;			/* Per-machine data */
46 	ulong	hsize;			/* header size */
47 	long	(*swal)(long);		/* beswal or leswal */
48 	void	(*hparse)(Fhdr *, ExecHdr *);
49 } ExecTable;
50 
51 extern	Mach	mmips;
52 extern	Mach	msparc;
53 extern	Mach	m68020;
54 extern	Mach	mi386;
55 extern	Mach	mi960;
56 extern	Mach	m3210;
57 
58 ExecTable exectab[] =
59 {
60 	{ V_MAGIC,			/* Mips v.out */
61 		"mips plan 9 executable",
62 		FMIPS,
63 		&mmips,
64 		sizeof(Exec),
65 		beswal,
66 		adotout },
67 	{ 0x160<<16,			/* Mips boot image */
68 		"mips plan 9 boot image",
69 		FMIPSB,
70 		&mmips,
71 		sizeof(struct mipsexec),
72 		beswal,
73 		mipsboot },
74 	{ (0x160<<16)|3,		/* Mips boot image */
75 		"mips 4k plan 9 boot image",
76 		FMIPSB,
77 		&mmips,
78 		sizeof(struct mips4kexec),
79 		beswal,
80 		mips4kboot },
81 	{ K_MAGIC,			/* Sparc k.out */
82 		"sparc plan 9 executable",
83 		FSPARC,
84 		&msparc,
85 		sizeof(Exec),
86 		beswal,
87 		adotout },
88 	{ 0x01030107, 			/* Sparc boot image */
89 		"sparc plan 9 boot image",
90 		FSPARCB,
91 		&msparc,
92 		sizeof(struct sparcexec),
93 		beswal,
94 		sparcboot },
95 	{ A_MAGIC,			/* 68020 2.out & boot image */
96 		"68020 plan 9 executable",
97 		F68020,
98 		&m68020,
99 		sizeof(Exec),
100 		beswal,
101 		common },
102 	{ 0xFEEDFACE,			/* Next boot image */
103 		"next plan 9 boot image",
104 		FNEXTB,
105 		&m68020,
106 		sizeof(struct nextexec),
107 		beswal,
108 		nextboot },
109 	{ I_MAGIC,			/* I386 8.out & boot image */
110 		"386 plan 9 executable",
111 		FI386,
112 		&mi386,
113 		sizeof(Exec),
114 		beswal,
115 		common },
116 	{ J_MAGIC,			/* I960 6.out (big-endian) */
117 		"960 plan 9 executable",
118 		FI960,
119 		&mi960,
120 		sizeof(Exec),
121 		beswal,
122 		adotout },
123 	{ 0x61010200, 			/* I960 boot image (little endian) */
124 		"960 plan 9 boot image",
125 		FI960B,
126 		&mi960,
127 		sizeof(struct i960exec),
128 		leswal,
129 		i960boot },
130 	{ X_MAGIC,			/* 3210 x.out */
131 		"3210 plan 9 executable",
132 		F3210,
133 		&m3210,
134 		sizeof(Exec),
135 		beswal,
136 		adotout },
137 	{ 0 },
138 };
139 
140 Mach	*mach = &mmips;			/* Global current machine table */
141 
142 int
143 crackhdr(int fd, Fhdr *fp)
144 {
145 	ExecTable *mp;
146 	ExecHdr d;
147 	int nb, magic;
148 
149 	fp->type = FNONE;
150 	if ((nb = read(fd, (char *)&d.e, sizeof(d.e))) <= 0)
151 		return 0;
152 	fp->magic = magic = beswal(d.e.magic);		/* big-endian */
153 	for (mp = exectab; mp->magic; mp++) {
154 		if (mp->magic == magic && nb >= mp->hsize) {
155 			hswal((long *) &d, sizeof(d.e)/sizeof(long), mp->swal);
156 			fp->type = mp->type;
157 			fp->name = mp->name;
158 			fp->hdrsz = mp->hsize;		/* zero on bootables */
159 			mach = mp->mach;
160 			mp->hparse(fp, &d);
161 			seek(fd, mp->hsize, 0);		/* seek to end of header */
162 			return 1;
163 		}
164 	}
165 	return 0;
166 }
167 /*
168  * Convert header to canonical form
169  */
170 static void
171 hswal(long *lp, int n, long (*swap) (long))
172 {
173 	while (n--) {
174 		*lp = (*swap) (*lp);
175 		lp++;
176 	}
177 }
178 /*
179  *	Crack a normal a.out-type header
180  */
181 static void
182 adotout(Fhdr *fp, ExecHdr *hp)
183 {
184 	long pgsize = mach->pgsize;
185 
186 	settext(fp, hp->e.entry, pgsize+sizeof(Exec),
187 			hp->e.text, sizeof(Exec));
188 	setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
189 		hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss);
190 	setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
191 }
192 
193 /*
194  *	68020 2.out and 68020 bootable images
195  *	386I 8.out and 386I bootable images
196  *
197  */
198 static void
199 common(Fhdr *fp, ExecHdr *hp)
200 {
201 	long kbase = mach->kbase;
202 
203 	adotout(fp, hp);
204 	if (fp->entry & kbase) {		/* Boot image */
205 		switch(fp->type) {
206 		case F68020:
207 			fp->type = F68020B;
208 			fp->name = "68020 plan 9 boot image";
209 			fp->hdrsz = 0;		/* header stripped */
210 			break;
211 		case FI386:
212 			fp->type = FI386B;
213 			fp->txtaddr = sizeof(Exec);
214 			fp->name = "386 plan 9 boot image";
215 			fp->hdrsz = 0;		/* header stripped */
216 			fp->dataddr = fp->txtaddr+fp->txtsz;
217 			break;
218 		default:
219 			break;
220 		}
221 		fp->txtaddr |= kbase;
222 		fp->entry |= kbase;
223 		fp->dataddr |= kbase;
224 	}
225 }
226 
227 /*
228  *	mips bootable image.
229  */
230 static void
231 mipsboot(Fhdr *fp, ExecHdr *hp)
232 {
233 	switch(hp->e.amagic) {
234 	default:
235 	case 0407:	/* some kind of mips */
236 		fp->type = FMIPSB;
237 		settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize,
238 					sizeof(struct mipsexec)+4);
239 		setdata(fp, hp->e.data_start, hp->e.dsize,
240 				fp->txtoff+hp->e.tsize, hp->e.bsize);
241 		break;
242 	case 0413:	/* some kind of mips */
243 		fp->type = FMIPSB;
244 		settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 0);
245 		setdata(fp, hp->e.data_start, hp->e.dsize, hp->e.tsize,
246 					hp->e.bsize);
247 		break;
248 	}
249 	setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
250 	fp->hdrsz = 0;		/* header stripped */
251 }
252 
253 /*
254  *	mips4k bootable image.
255  */
256 static void
257 mips4kboot(Fhdr *fp, ExecHdr *hp)
258 {
259 	switch(hp->e.h.amagic) {
260 	default:
261 	case 0407:	/* some kind of mips */
262 		fp->type = FMIPSB;
263 		settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize,
264 					sizeof(struct mips4kexec));
265 		setdata(fp, hp->e.h.data_start, hp->e.h.dsize,
266 				fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
267 		break;
268 	case 0413:	/* some kind of mips */
269 		fp->type = FMIPSB;
270 		settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 0);
271 		setdata(fp, hp->e.h.data_start, hp->e.h.dsize, hp->e.h.tsize,
272 					hp->e.h.bsize);
273 		break;
274 	}
275 	setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
276 	fp->hdrsz = 0;		/* header stripped */
277 }
278 
279 /*
280  *	sparc bootable image
281  */
282 static void
283 sparcboot(Fhdr *fp, ExecHdr *hp)
284 {
285 	fp->type = FSPARCB;
286 	settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
287 					sizeof(struct sparcexec));
288 	setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
289 					fp->txtoff+hp->e.stext, hp->e.sbss);
290 	setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
291 	fp->hdrsz = 0;		/* header stripped */
292 }
293 
294 /*
295  *	next bootable image
296  */
297 static void
298 nextboot(Fhdr *fp, ExecHdr *hp)
299 {
300 	fp->type = FNEXTB;
301 	settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
302 					hp->e.texts.size, hp->e.texts.offset);
303 	setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
304 				hp->e.datas.offset, hp->e.bsss.size);
305 	setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
306 					hp->e.symc.symoff);
307 	fp->hdrsz = 0;		/* header stripped */
308 }
309 
310 /*
311  *	I960 bootable image
312  */
313 static void
314 i960boot(Fhdr *fp, ExecHdr *hp)
315 {
316 	/* long n = hp->e.i6comments.fptrlineno-hp->e.i6comments.fptrreloc; */
317 
318 	settext(fp, hp->e.i6entry, hp->e.i6texts.virt, hp->e.i6texts.size,
319 					hp->e.i6texts.fptr);
320 	setdata(fp, hp->e.i6datas.virt, hp->e.i6datas.size,
321 				hp->e.i6datas.fptr, hp->e.i6bsssize);
322 	setsym(fp, 0, 0, 0, 0);
323 	/*setsym(fp, n, 0, hp->e.i6comments.size-n, hp->e.i6comments.fptr); */
324 	fp->hdrsz = 0;		/* header stripped */
325 }
326 
327 
328 static void
329 settext(Fhdr *fp, long e, long a, long s, long off)
330 {
331 	fp->txtaddr = a;
332 	fp->entry = e;
333 	fp->txtsz = s;
334 	fp->txtoff = off;
335 }
336 static void
337 setdata(Fhdr *fp, long a, long s, long off, long bss)
338 {
339 	fp->dataddr = a;
340 	fp->datsz = s;
341 	fp->datoff = off;
342 	fp->bsssz = bss;
343 }
344 static void
345 setsym(Fhdr *fp, long sy, long sppc, long lnpc, long symoff)
346 {
347 	fp->symsz = sy;
348 	fp->symoff = symoff;
349 	fp->sppcsz = sppc;
350 	fp->sppcoff = fp->symoff+fp->symsz;
351 	fp->lnpcsz = lnpc;
352 	fp->lnpcoff = fp->sppcoff+fp->sppcsz;
353 }
354 
355 
356 static long
357 _round(long a, long b)
358 {
359 	long w;
360 
361 	w = (a/b)*b;
362 	if (a!=w)
363 		w += b;
364 	return(w);
365 }
366