1 // Inferno libmach/executable.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c
3 //
4 // Copyright © 1994-1999 Lucent Technologies Inc.
5 // Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
6 // Portions Copyright © 1997-1999 Vita Nuova Limited.
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
8 // Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
9 // Portions Copyright © 2009 The Go Authors. All rights reserved.
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28
29 #include <u.h>
30 #include <libc.h>
31 #include <bio.h>
32 #include <bootexec.h>
33 #include <mach.h>
34 #include "elf.h"
35 #include "macho.h"
36
37 /*
38 * All a.out header types. The dummy entry allows canonical
39 * processing of the union as a sequence of int32s
40 */
41
42 typedef struct {
43 union{
44 /*struct { */
45 Exec exechdr; /* a.out.h */
46 /* uvlong hdr[1];*/
47 /*};*/
48 Ehdr32 elfhdr32; /* elf.h */
49 Ehdr64 elfhdr64; /* elf.h */
50 struct mipsexec mips; /* bootexec.h */
51 struct mips4kexec mipsk4; /* bootexec.h */
52 struct sparcexec sparc; /* bootexec.h */
53 struct nextexec next; /* bootexec.h */
54 Machhdr machhdr; /* macho.h */
55 } e;
56 int32 dummy; /* padding to ensure extra int32 */
57 } ExecHdr;
58
59 static int nextboot(int, Fhdr*, ExecHdr*);
60 static int sparcboot(int, Fhdr*, ExecHdr*);
61 static int mipsboot(int, Fhdr*, ExecHdr*);
62 static int mips4kboot(int, Fhdr*, ExecHdr*);
63 static int common(int, Fhdr*, ExecHdr*);
64 static int commonllp64(int, Fhdr*, ExecHdr*);
65 static int adotout(int, Fhdr*, ExecHdr*);
66 static int elfdotout(int, Fhdr*, ExecHdr*);
67 static int machdotout(int, Fhdr*, ExecHdr*);
68 static int armdotout(int, Fhdr*, ExecHdr*);
69 static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
70 static void setdata(Fhdr*, uvlong, int32, vlong, int32);
71 static void settext(Fhdr*, uvlong, uvlong, int32, vlong);
72 static void hswal(void*, int, uint32(*)(uint32));
73 static uvlong _round(uvlong, uint32);
74
75 /*
76 * definition of per-executable file type structures
77 */
78
79 typedef struct Exectable{
80 int32 magic; /* big-endian magic number of file */
81 char *name; /* executable identifier */
82 char *dlmname; /* dynamically loadable module identifier */
83 uchar type; /* Internal code */
84 uchar _magic; /* _MAGIC() magic */
85 Mach *mach; /* Per-machine data */
86 int32 hsize; /* header size */
87 uint32 (*swal)(uint32); /* beswal or leswal */
88 int (*hparse)(int, Fhdr*, ExecHdr*);
89 } ExecTable;
90
91 extern Mach mmips;
92 extern Mach mmips2le;
93 extern Mach mmips2be;
94 extern Mach msparc;
95 extern Mach msparc64;
96 extern Mach m68020;
97 extern Mach mi386;
98 extern Mach mamd64;
99 extern Mach marm;
100 extern Mach mpower;
101 extern Mach mpower64;
102 extern Mach malpha;
103
104 /* BUG: FIX THESE WHEN NEEDED */
105 Mach mmips;
106 Mach mmips2le;
107 Mach mmips2be;
108 Mach msparc;
109 Mach msparc64;
110 Mach m68020;
111 Mach mpower;
112 Mach mpower64;
113 Mach malpha;
114
115 ExecTable exectab[] =
116 {
117 { V_MAGIC, /* Mips v.out */
118 "mips plan 9 executable BE",
119 "mips plan 9 dlm BE",
120 FMIPS,
121 1,
122 &mmips,
123 sizeof(Exec),
124 beswal,
125 adotout },
126 { P_MAGIC, /* Mips 0.out (r3k le) */
127 "mips plan 9 executable LE",
128 "mips plan 9 dlm LE",
129 FMIPSLE,
130 1,
131 &mmips,
132 sizeof(Exec),
133 beswal,
134 adotout },
135 { M_MAGIC, /* Mips 4.out */
136 "mips 4k plan 9 executable BE",
137 "mips 4k plan 9 dlm BE",
138 FMIPS2BE,
139 1,
140 &mmips2be,
141 sizeof(Exec),
142 beswal,
143 adotout },
144 { N_MAGIC, /* Mips 0.out */
145 "mips 4k plan 9 executable LE",
146 "mips 4k plan 9 dlm LE",
147 FMIPS2LE,
148 1,
149 &mmips2le,
150 sizeof(Exec),
151 beswal,
152 adotout },
153 { 0x160<<16, /* Mips boot image */
154 "mips plan 9 boot image",
155 nil,
156 FMIPSB,
157 0,
158 &mmips,
159 sizeof(struct mipsexec),
160 beswal,
161 mipsboot },
162 { (0x160<<16)|3, /* Mips boot image */
163 "mips 4k plan 9 boot image",
164 nil,
165 FMIPSB,
166 0,
167 &mmips2be,
168 sizeof(struct mips4kexec),
169 beswal,
170 mips4kboot },
171 { K_MAGIC, /* Sparc k.out */
172 "sparc plan 9 executable",
173 "sparc plan 9 dlm",
174 FSPARC,
175 1,
176 &msparc,
177 sizeof(Exec),
178 beswal,
179 adotout },
180 { 0x01030107, /* Sparc boot image */
181 "sparc plan 9 boot image",
182 nil,
183 FSPARCB,
184 0,
185 &msparc,
186 sizeof(struct sparcexec),
187 beswal,
188 sparcboot },
189 { U_MAGIC, /* Sparc64 u.out */
190 "sparc64 plan 9 executable",
191 "sparc64 plan 9 dlm",
192 FSPARC64,
193 1,
194 &msparc64,
195 sizeof(Exec),
196 beswal,
197 adotout },
198 { A_MAGIC, /* 68020 2.out & boot image */
199 "68020 plan 9 executable",
200 "68020 plan 9 dlm",
201 F68020,
202 1,
203 &m68020,
204 sizeof(Exec),
205 beswal,
206 common },
207 { 0xFEEDFACE, /* Next boot image */
208 "next plan 9 boot image",
209 nil,
210 FNEXTB,
211 0,
212 &m68020,
213 sizeof(struct nextexec),
214 beswal,
215 nextboot },
216 { I_MAGIC, /* I386 8.out & boot image */
217 "386 plan 9 executable",
218 "386 plan 9 dlm",
219 FI386,
220 1,
221 &mi386,
222 sizeof(Exec),
223 beswal,
224 common },
225 { S_MAGIC, /* amd64 6.out & boot image */
226 "amd64 plan 9 executable",
227 "amd64 plan 9 dlm",
228 FAMD64,
229 1,
230 &mamd64,
231 sizeof(Exec)+8,
232 nil,
233 commonllp64 },
234 { Q_MAGIC, /* PowerPC q.out & boot image */
235 "power plan 9 executable",
236 "power plan 9 dlm",
237 FPOWER,
238 1,
239 &mpower,
240 sizeof(Exec),
241 beswal,
242 common },
243 { T_MAGIC, /* power64 9.out & boot image */
244 "power64 plan 9 executable",
245 "power64 plan 9 dlm",
246 FPOWER64,
247 1,
248 &mpower64,
249 sizeof(Exec)+8,
250 nil,
251 commonllp64 },
252 { ELF_MAG, /* any elf32 or elf64 */
253 "elf executable",
254 nil,
255 FNONE,
256 0,
257 &mi386,
258 sizeof(Ehdr64),
259 nil,
260 elfdotout },
261 { MACH64_MAG, /* 64-bit MACH (apple mac) */
262 "mach executable",
263 nil,
264 FAMD64,
265 0,
266 &mamd64,
267 sizeof(Machhdr),
268 nil,
269 machdotout },
270 { MACH32_MAG, /* 32-bit MACH (apple mac) */
271 "mach executable",
272 nil,
273 FI386,
274 0,
275 &mi386,
276 sizeof(Machhdr),
277 nil,
278 machdotout },
279 { E_MAGIC, /* Arm 5.out and boot image */
280 "arm plan 9 executable",
281 "arm plan 9 dlm",
282 FARM,
283 1,
284 &marm,
285 sizeof(Exec),
286 beswal,
287 common },
288 { (143<<16)|0413, /* (Free|Net)BSD Arm */
289 "arm *bsd executable",
290 nil,
291 FARM,
292 0,
293 &marm,
294 sizeof(Exec),
295 leswal,
296 armdotout },
297 { L_MAGIC, /* alpha 7.out */
298 "alpha plan 9 executable",
299 "alpha plan 9 dlm",
300 FALPHA,
301 1,
302 &malpha,
303 sizeof(Exec),
304 beswal,
305 common },
306 { 0x0700e0c3, /* alpha boot image */
307 "alpha plan 9 boot image",
308 nil,
309 FALPHA,
310 0,
311 &malpha,
312 sizeof(Exec),
313 beswal,
314 common },
315 { 0 },
316 };
317
318 Mach *mach = &mi386; /* Global current machine table */
319
320 static ExecTable*
321 couldbe4k(ExecTable *mp)
322 {
323 Dir *d;
324 ExecTable *f;
325
326 if((d=dirstat("/proc/1/regs")) == nil)
327 return mp;
328 if(d->length < 32*8){ /* R3000 */
329 free(d);
330 return mp;
331 }
332 free(d);
333 for (f = exectab; f->magic; f++)
334 if(f->magic == M_MAGIC) {
335 f->name = "mips plan 9 executable on mips2 kernel";
336 return f;
337 }
338 return mp;
339 }
340
341 int
342 crackhdr(int fd, Fhdr *fp)
343 {
344 ExecTable *mp;
345 ExecHdr d;
346 int nb, ret;
347 uint32 magic;
348
349 fp->type = FNONE;
350 nb = read(fd, (char *)&d.e, sizeof(d.e));
351 if (nb <= 0)
352 return 0;
353
354 ret = 0;
355 magic = beswal(d.e.exechdr.magic); /* big-endian */
356 for (mp = exectab; mp->magic; mp++) {
357 if (nb < mp->hsize)
358 continue;
359
360 /*
361 * The magic number has morphed into something
362 * with fields (the straw was DYN_MAGIC) so now
363 * a flag is needed in Fhdr to distinguish _MAGIC()
364 * magic numbers from foreign magic numbers.
365 *
366 * This code is creaking a bit and if it has to
367 * be modified/extended much more it's probably
368 * time to step back and redo it all.
369 */
370 if(mp->_magic){
371 if(mp->magic != (magic & ~DYN_MAGIC))
372 continue;
373
374 if(mp->magic == V_MAGIC)
375 mp = couldbe4k(mp);
376
377 if ((magic & DYN_MAGIC) && mp->dlmname != nil)
378 fp->name = mp->dlmname;
379 else
380 fp->name = mp->name;
381 }
382 else{
383 if(mp->magic != magic)
384 continue;
385 fp->name = mp->name;
386 }
387 fp->type = mp->type;
388 fp->hdrsz = mp->hsize; /* will be zero on bootables */
389 fp->_magic = mp->_magic;
390 fp->magic = magic;
391
392 mach = mp->mach;
393 if(mp->swal != nil)
394 hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal);
395 ret = mp->hparse(fd, fp, &d);
396 seek(fd, mp->hsize, 0); /* seek to end of header */
397 break;
398 }
399 if(mp->magic == 0)
400 werrstr("unknown header type");
401 return ret;
402 }
403
404 /*
405 * Convert header to canonical form
406 */
407 static void
408 hswal(void *v, int n, uint32 (*swap)(uint32))
409 {
410 uint32 *ulp;
411
412 for(ulp = v; n--; ulp++)
413 *ulp = (*swap)(*ulp);
414 }
415
416 /*
417 * Crack a normal a.out-type header
418 */
419 static int
420 adotout(int fd, Fhdr *fp, ExecHdr *hp)
421 {
422 int32 pgsize;
423
424 USED(fd);
425 pgsize = mach->pgsize;
426 settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec),
427 hp->e.exechdr.text, sizeof(Exec));
428 setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
429 hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss);
430 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
431 return 1;
432 }
433
434 static void
435 commonboot(Fhdr *fp)
436 {
437 if (!(fp->entry & mach->ktmask))
438 return;
439
440 switch(fp->type) { /* boot image */
441 case F68020:
442 fp->type = F68020B;
443 fp->name = "68020 plan 9 boot image";
444 break;
445 case FI386:
446 fp->type = FI386B;
447 fp->txtaddr = (u32int)fp->entry;
448 fp->name = "386 plan 9 boot image";
449 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
450 break;
451 case FARM:
452 fp->type = FARMB;
453 fp->txtaddr = (u32int)fp->entry;
454 fp->name = "ARM plan 9 boot image";
455 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
456 return;
457 case FALPHA:
458 fp->type = FALPHAB;
459 fp->txtaddr = (u32int)fp->entry;
460 fp->name = "alpha plan 9 boot image";
461 fp->dataddr = fp->txtaddr+fp->txtsz;
462 break;
463 case FPOWER:
464 fp->type = FPOWERB;
465 fp->txtaddr = (u32int)fp->entry;
466 fp->name = "power plan 9 boot image";
467 fp->dataddr = fp->txtaddr+fp->txtsz;
468 break;
469 case FAMD64:
470 fp->type = FAMD64B;
471 fp->txtaddr = fp->entry;
472 fp->name = "amd64 plan 9 boot image";
473 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
474 break;
475 default:
476 return;
477 }
478 fp->hdrsz = 0; /* header stripped */
479 }
480
481 /*
482 * _MAGIC() style headers and
483 * alpha plan9-style bootable images for axp "headerless" boot
484 *
485 */
486 static int
487 common(int fd, Fhdr *fp, ExecHdr *hp)
488 {
489 adotout(fd, fp, hp);
490 if(hp->e.exechdr.magic & DYN_MAGIC) {
491 fp->txtaddr = 0;
492 fp->dataddr = fp->txtsz;
493 return 1;
494 }
495 commonboot(fp);
496 return 1;
497 }
498
499 static int
500 commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
501 {
502 int32 pgsize;
503 uvlong entry;
504
505 hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal);
506 if(!(hp->e.exechdr.magic & HDR_MAGIC))
507 return 0;
508
509 /*
510 * There can be more magic here if the
511 * header ever needs more expansion.
512 * For now just catch use of any of the
513 * unused bits.
514 */
515 if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16)
516 return 0;
517 union {
518 char *p;
519 uvlong *v;
520 } u;
521 u.p = (char*)&hp->e.exechdr;
522 entry = beswav(*u.v);
523
524 pgsize = mach->pgsize;
525 settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz);
526 setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
527 hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss);
528 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
529
530 if(hp->e.exechdr.magic & DYN_MAGIC) {
531 fp->txtaddr = 0;
532 fp->dataddr = fp->txtsz;
533 return 1;
534 }
535 commonboot(fp);
536 return 1;
537 }
538
539 /*
540 * mips bootable image.
541 */
542 static int
543 mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
544 {
545 abort();
546 #ifdef unused
547 USED(fd);
548 fp->type = FMIPSB;
549 switch(hp->e.exechdr.amagic) {
550 default:
551 case 0407: /* some kind of mips */
552 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
553 hp->e.tsize, sizeof(struct mipsexec)+4);
554 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
555 fp->txtoff+hp->e.tsize, hp->e.bsize);
556 break;
557 case 0413: /* some kind of mips */
558 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
559 hp->e.tsize, 0);
560 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
561 hp->e.tsize, hp->e.bsize);
562 break;
563 }
564 setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
565 fp->hdrsz = 0; /* header stripped */
566 #endif
567 return 1;
568 }
569
570 /*
571 * mips4k bootable image.
572 */
573 static int
574 mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
575 {
576 abort();
577 #ifdef unused
578 USED(fd);
579 fp->type = FMIPSB;
580 switch(hp->e.h.amagic) {
581 default:
582 case 0407: /* some kind of mips */
583 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
584 hp->e.h.tsize, sizeof(struct mips4kexec));
585 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
586 fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
587 break;
588 case 0413: /* some kind of mips */
589 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
590 hp->e.h.tsize, 0);
591 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
592 hp->e.h.tsize, hp->e.h.bsize);
593 break;
594 }
595 setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
596 fp->hdrsz = 0; /* header stripped */
597 #endif
598 return 1;
599 }
600
601 /*
602 * sparc bootable image
603 */
604 static int
605 sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
606 {
607 abort();
608 #ifdef unused
609 USED(fd);
610 fp->type = FSPARCB;
611 settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
612 sizeof(struct sparcexec));
613 setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
614 fp->txtoff+hp->e.stext, hp->e.sbss);
615 setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
616 fp->hdrsz = 0; /* header stripped */
617 #endif
618 return 1;
619 }
620
621 /*
622 * next bootable image
623 */
624 static int
625 nextboot(int fd, Fhdr *fp, ExecHdr *hp)
626 {
627 abort();
628 #ifdef unused
629 USED(fd);
630 fp->type = FNEXTB;
631 settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
632 hp->e.texts.size, hp->e.texts.offset);
633 setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
634 hp->e.datas.offset, hp->e.bsss.size);
635 setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
636 hp->e.symc.symoff);
637 fp->hdrsz = 0; /* header stripped */
638 #endif
639 return 1;
640 }
641
642 /*
643 * Elf32 and Elf64 binaries.
644 */
645 static int
646 elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
647 {
648
649 uvlong (*swav)(uvlong);
650 uint32 (*swal)(uint32);
651 ushort (*swab)(ushort);
652 Ehdr64 *ep;
653 Phdr64 *ph;
654 Shdr64 *sh;
655 int i, it, id, is, phsz, shsz;
656
657 /* bitswap the header according to the DATA format */
658 ep = &hp->e.elfhdr64;
659 if(ep->ident[CLASS] != ELFCLASS64) {
660 werrstr("bad ELF class - not 32 bit or 64 bit");
661 return 0;
662 }
663 if(ep->ident[DATA] == ELFDATA2LSB) {
664 swab = leswab;
665 swal = leswal;
666 swav = leswav;
667 } else if(ep->ident[DATA] == ELFDATA2MSB) {
668 swab = beswab;
669 swal = beswal;
670 swav = beswav;
671 } else {
672 werrstr("bad ELF encoding - not big or little endian");
673 return 0;
674 }
675
676 ep->type = swab(ep->type);
677 ep->machine = swab(ep->machine);
678 ep->version = swal(ep->version);
679 ep->elfentry = swal(ep->elfentry);
680 ep->phoff = swav(ep->phoff);
681 ep->shoff = swav(ep->shoff);
682 ep->flags = swav(ep->flags);
683 ep->ehsize = swab(ep->ehsize);
684 ep->phentsize = swab(ep->phentsize);
685 ep->phnum = swab(ep->phnum);
686 ep->shentsize = swab(ep->shentsize);
687 ep->shnum = swab(ep->shnum);
688 ep->shstrndx = swab(ep->shstrndx);
689 if(ep->type != EXEC || ep->version != CURRENT)
690 return 0;
691
692 /* we could definitely support a lot more machines here */
693 fp->magic = ELF_MAG;
694 fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
695 switch(ep->machine) {
696 case AMD64:
697 mach = &mamd64;
698 fp->type = FAMD64;
699 break;
700 default:
701 return 0;
702 }
703
704 if(ep->phentsize != sizeof(Phdr64)) {
705 werrstr("bad ELF header size");
706 return 0;
707 }
708 phsz = sizeof(Phdr64)*ep->phnum;
709 ph = malloc(phsz);
710 if(!ph)
711 return 0;
712 seek(fd, ep->phoff, 0);
713 if(read(fd, ph, phsz) < 0) {
714 free(ph);
715 return 0;
716 }
717 hswal(ph, phsz/sizeof(uint32), swal);
718
719 shsz = sizeof(Shdr64)*ep->shnum;
720 sh = malloc(shsz);
721 if(sh) {
722 seek(fd, ep->shoff, 0);
723 if(read(fd, sh, shsz) < 0) {
724 free(sh);
725 sh = 0;
726 } else
727 hswal(sh, shsz/sizeof(uint32), swal);
728 }
729
730 /* find text, data and symbols and install them */
731 it = id = is = -1;
732 for(i = 0; i < ep->phnum; i++) {
733 if(ph[i].type == LOAD
734 && (ph[i].flags & (R|X)) == (R|X) && it == -1)
735 it = i;
736 else if(ph[i].type == LOAD
737 && (ph[i].flags & (R|W)) == (R|W) && id == -1)
738 id = i;
739 else if(ph[i].type == NOPTYPE && is == -1)
740 is = i;
741 }
742 if(it == -1 || id == -1) {
743 /*
744 * The SPARC64 boot image is something of an ELF hack.
745 * Text+Data+BSS are represented by ph[0]. Symbols
746 * are represented by ph[1]:
747 *
748 * filesz, memsz, vaddr, paddr, off
749 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
750 * ph[1] : symsz, lcsz, 0, 0, symoff
751 */
752 if(ep->machine == SPARC64 && ep->phnum == 2) {
753 uint32 txtaddr, txtsz, dataddr, bsssz;
754
755 txtaddr = ph[0].vaddr | 0x80000000;
756 txtsz = ph[0].filesz - ph[0].paddr;
757 dataddr = txtaddr + txtsz;
758 bsssz = ph[0].memsz - ph[0].filesz;
759 settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
760 setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
761 setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
762 free(ph);
763 return 1;
764 }
765
766 werrstr("No TEXT or DATA sections");
767 free(ph);
768 free(sh);
769 return 0;
770 }
771
772 settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
773 setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
774 if(is != -1)
775 setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
776 else if(sh != 0){
777 char *buf;
778 uvlong symsize = 0;
779 uvlong symoff = 0;
780 uvlong pclnsz = 0;
781 uvlong pclnoff = 0;
782
783 /* load shstrtab names */
784 buf = malloc(sh[ep->shstrndx].size);
785 if (buf == 0)
786 goto done;
787 memset(buf, 0, sizeof buf);
788 seek(fd, sh[ep->shstrndx].offset, 0);
789 i = read(fd, buf, sh[ep->shstrndx].size);
790 USED(i); // shut up ubuntu gcc
791
792 for(i = 0; i < ep->shnum; i++) {
793 if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
794 symsize = sh[i].size;
795 symoff = sh[i].offset;
796 }
797 if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
798 pclnsz = sh[i].size;
799 pclnoff = sh[i].offset;
800 }
801 }
802 setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
803 free(buf);
804 }
805 done:
806 free(ph);
807 free(sh);
808 return 1;
809 }
810
811 static int
812 elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
813 {
814
815 uint32 (*swal)(uint32);
816 ushort (*swab)(ushort);
817 Ehdr32 *ep;
818 Phdr32 *ph;
819 int i, it, id, is, phsz, shsz;
820 Shdr32 *sh;
821
822 /* bitswap the header according to the DATA format */
823 ep = &hp->e.elfhdr32;
824 if(ep->ident[CLASS] != ELFCLASS32) {
825 return elf64dotout(fd, fp, hp);
826 }
827 if(ep->ident[DATA] == ELFDATA2LSB) {
828 swab = leswab;
829 swal = leswal;
830 } else if(ep->ident[DATA] == ELFDATA2MSB) {
831 swab = beswab;
832 swal = beswal;
833 } else {
834 werrstr("bad ELF encoding - not big or little endian");
835 return 0;
836 }
837
838 ep->type = swab(ep->type);
839 ep->machine = swab(ep->machine);
840 ep->version = swal(ep->version);
841 ep->elfentry = swal(ep->elfentry);
842 ep->phoff = swal(ep->phoff);
843 ep->shoff = swal(ep->shoff);
844 ep->flags = swal(ep->flags);
845 ep->ehsize = swab(ep->ehsize);
846 ep->phentsize = swab(ep->phentsize);
847 ep->phnum = swab(ep->phnum);
848 ep->shentsize = swab(ep->shentsize);
849 ep->shnum = swab(ep->shnum);
850 ep->shstrndx = swab(ep->shstrndx);
851 if(ep->type != EXEC || ep->version != CURRENT)
852 return 0;
853
854 /* we could definitely support a lot more machines here */
855 fp->magic = ELF_MAG;
856 fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
857 switch(ep->machine) {
858 case I386:
859 mach = &mi386;
860 fp->type = FI386;
861 break;
862 case MIPS:
863 mach = &mmips;
864 fp->type = FMIPS;
865 break;
866 case SPARC64:
867 mach = &msparc64;
868 fp->type = FSPARC64;
869 break;
870 case POWER:
871 mach = &mpower;
872 fp->type = FPOWER;
873 break;
874 case ARM:
875 mach = &marm;
876 fp->type = FARM;
877 break;
878 default:
879 return 0;
880 }
881
882 if(ep->phentsize != sizeof(Phdr32)) {
883 werrstr("bad ELF header size");
884 return 0;
885 }
886 phsz = sizeof(Phdr32)*ep->phnum;
887 ph = malloc(phsz);
888 if(!ph)
889 return 0;
890 seek(fd, ep->phoff, 0);
891 if(read(fd, ph, phsz) < 0) {
892 free(ph);
893 return 0;
894 }
895 hswal(ph, phsz/sizeof(uint32), swal);
896
897 shsz = sizeof(Shdr32)*ep->shnum;
898 sh = malloc(shsz);
899 if(sh) {
900 seek(fd, ep->shoff, 0);
901 if(read(fd, sh, shsz) < 0) {
902 free(sh);
903 sh = 0;
904 } else
905 hswal(sh, shsz/sizeof(uint32), swal);
906 }
907
908 /* find text, data and symbols and install them */
909 it = id = is = -1;
910 for(i = 0; i < ep->phnum; i++) {
911 if(ph[i].type == LOAD
912 && (ph[i].flags & (R|X)) == (R|X) && it == -1)
913 it = i;
914 else if(ph[i].type == LOAD
915 && (ph[i].flags & (R|W)) == (R|W) && id == -1)
916 id = i;
917 else if(ph[i].type == NOPTYPE && is == -1)
918 is = i;
919 }
920 if(it == -1 || id == -1) {
921 /*
922 * The SPARC64 boot image is something of an ELF hack.
923 * Text+Data+BSS are represented by ph[0]. Symbols
924 * are represented by ph[1]:
925 *
926 * filesz, memsz, vaddr, paddr, off
927 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
928 * ph[1] : symsz, lcsz, 0, 0, symoff
929 */
930 if(ep->machine == SPARC64 && ep->phnum == 2) {
931 uint32 txtaddr, txtsz, dataddr, bsssz;
932
933 txtaddr = ph[0].vaddr | 0x80000000;
934 txtsz = ph[0].filesz - ph[0].paddr;
935 dataddr = txtaddr + txtsz;
936 bsssz = ph[0].memsz - ph[0].filesz;
937 settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
938 setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
939 setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
940 free(ph);
941 return 1;
942 }
943
944 werrstr("No TEXT or DATA sections");
945 free(sh);
946 free(ph);
947 return 0;
948 }
949
950 settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
951 setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
952 if(is != -1)
953 setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
954 else if(sh != 0){
955 char *buf;
956 uvlong symsize = 0;
957 uvlong symoff = 0;
958 uvlong pclnsize = 0;
959 uvlong pclnoff = 0;
960
961 /* load shstrtab names */
962 buf = malloc(sh[ep->shstrndx].size);
963 if (buf == 0)
964 goto done;
965 memset(buf, 0, sizeof buf);
966 seek(fd, sh[ep->shstrndx].offset, 0);
967 i = read(fd, buf, sh[ep->shstrndx].size);
968 USED(i); // shut up ubuntu gcc
969
970 for(i = 0; i < ep->shnum; i++) {
971 if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
972 symsize = sh[i].size;
973 symoff = sh[i].offset;
974 }
975 if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
976 pclnsize = sh[i].size;
977 pclnoff = sh[i].offset;
978 }
979 }
980 setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
981 free(buf);
982 }
983 done:
984 free(sh);
985 free(ph);
986 return 1;
987 }
988
989 static int
990 machdotout(int fd, Fhdr *fp, ExecHdr *hp)
991 {
992 uvlong (*swav)(uvlong);
993 uint32 (*swal)(uint32);
994 Machhdr *mp;
995 MachCmd **cmd;
996 MachSymSeg *symtab;
997 MachSymSeg *pclntab;
998 MachSeg64 *seg;
999 MachSect64 *sect;
1000 MachSeg32 *seg32;
1001 MachSect32 *sect32;
1002 uvlong textsize, datasize, bsssize;
1003 uchar *cmdbuf;
1004 uchar *cmdp;
1005 int i, hdrsize;
1006 uint32 textva, textoff, datava, dataoff;
1007
1008 mp = &hp->e.machhdr;
1009 if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) {
1010 werrstr("bad MACH executable type %#ux", leswal(mp->filetype));
1011 return 0;
1012 }
1013
1014 swal = leswal;
1015 swav = leswav;
1016
1017 mp->magic = swal(mp->magic);
1018 mp->cputype = swal(mp->cputype);
1019 mp->cpusubtype = swal(mp->cpusubtype);
1020 mp->filetype = swal(mp->filetype);
1021 mp->ncmds = swal(mp->ncmds);
1022 mp->sizeofcmds = swal(mp->sizeofcmds);
1023 mp->flags = swal(mp->flags);
1024 mp->reserved = swal(mp->reserved);
1025 hdrsize = 0;
1026
1027 switch(mp->magic) {
1028 case 0xFEEDFACE: // 32-bit mach
1029 if (mp->cputype != MACH_CPU_TYPE_X86) {
1030 werrstr("bad MACH cpu type - not 386");
1031 return 0;
1032 }
1033 if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
1034 werrstr("bad MACH cpu subtype - not 386");
1035 return 0;
1036 }
1037 if (mp->filetype != MACH_EXECUTABLE_TYPE) {
1038 werrstr("bad MACH executable type");
1039 return 0;
1040 }
1041 mach = &mi386;
1042 fp->type = FI386;
1043 hdrsize = 28;
1044 break;
1045
1046 case 0xFEEDFACF: // 64-bit mach
1047 if (mp->cputype != MACH_CPU_TYPE_X86_64) {
1048 werrstr("bad MACH cpu type - not amd64");
1049 return 0;
1050 }
1051
1052 if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
1053 werrstr("bad MACH cpu subtype - not amd64");
1054 return 0;
1055 }
1056 mach = &mamd64;
1057 fp->type = FAMD64;
1058 hdrsize = 32;
1059 break;
1060
1061 default:
1062 werrstr("not mach %#ux", mp->magic);
1063 return 0;
1064 }
1065
1066 cmdbuf = malloc(mp->sizeofcmds);
1067 seek(fd, hdrsize, 0);
1068 if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) {
1069 free(cmdbuf);
1070 return 0;
1071 }
1072 cmd = malloc(mp->ncmds * sizeof(MachCmd*));
1073 cmdp = cmdbuf;
1074 textva = 0;
1075 textoff = 0;
1076 dataoff = 0;
1077 datava = 0;
1078 symtab = 0;
1079 pclntab = 0;
1080 textsize = datasize = bsssize = 0;
1081 for (i = 0; i < mp->ncmds; i++) {
1082 MachCmd *c;
1083
1084 cmd[i] = (MachCmd*)cmdp;
1085 c = cmd[i];
1086 c->type = swal(c->type);
1087 c->size = swal(c->size);
1088 switch(c->type) {
1089 case MACH_SEGMENT_32:
1090 if(mp->magic != 0xFEEDFACE) {
1091 werrstr("segment 32 in mach 64");
1092 goto bad;
1093 }
1094 seg32 = (MachSeg32*)c;
1095 seg32->vmaddr = swav(seg32->vmaddr);
1096 seg32->vmsize = swav(seg32->vmsize);
1097 seg32->fileoff = swav(seg32->fileoff);
1098 seg32->filesize = swav(seg32->filesize);
1099 seg32->maxprot = swal(seg32->maxprot);
1100 seg32->initprot = swal(seg32->initprot);
1101 seg32->nsects = swal(seg32->nsects);
1102 seg32->flags = swal(seg32->flags);
1103 if (strcmp(seg32->segname, "__TEXT") == 0) {
1104 textva = seg32->vmaddr;
1105 textoff = seg32->fileoff;
1106 sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
1107 if (strcmp(sect32->sectname, "__text") == 0) {
1108 textsize = swal(sect32->size);
1109 } else {
1110 werrstr("no text section");
1111 goto bad;
1112 }
1113 }
1114 if (strcmp(seg32->segname, "__DATA") == 0) {
1115 datava = seg32->vmaddr;
1116 dataoff = seg32->fileoff;
1117 sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
1118 if (strcmp(sect32->sectname, "__data") == 0) {
1119 datasize = swal(sect32->size);
1120 } else {
1121 werrstr("no data section");
1122 goto bad;
1123 }
1124 sect32++;
1125 if (strcmp(sect32->sectname, "__nl_symbol_ptr") == 0)
1126 sect32++;
1127 if (strcmp(sect32->sectname, "__bss") == 0) {
1128 bsssize = swal(sect32->size);
1129 } else {
1130 werrstr("no bss section");
1131 goto bad;
1132 }
1133 }
1134 break;
1135
1136 case MACH_SEGMENT_64:
1137 if(mp->magic != 0xFEEDFACF) {
1138 werrstr("segment 32 in mach 64");
1139 goto bad;
1140 }
1141 seg = (MachSeg64*)c;
1142 seg->vmaddr = swav(seg->vmaddr);
1143 seg->vmsize = swav(seg->vmsize);
1144 seg->fileoff = swav(seg->fileoff);
1145 seg->filesize = swav(seg->filesize);
1146 seg->maxprot = swal(seg->maxprot);
1147 seg->initprot = swal(seg->initprot);
1148 seg->nsects = swal(seg->nsects);
1149 seg->flags = swal(seg->flags);
1150 if (strcmp(seg->segname, "__TEXT") == 0) {
1151 textva = seg->vmaddr;
1152 textoff = seg->fileoff;
1153 sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
1154 if (strcmp(sect->sectname, "__text") == 0) {
1155 textsize = swav(sect->size);
1156 } else {
1157 werrstr("no text section");
1158 goto bad;
1159 }
1160 }
1161 if (strcmp(seg->segname, "__DATA") == 0) {
1162 datava = seg->vmaddr;
1163 dataoff = seg->fileoff;
1164 sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
1165 if (strcmp(sect->sectname, "__data") == 0) {
1166 datasize = swav(sect->size);
1167 } else {
1168 werrstr("no data section");
1169 goto bad;
1170 }
1171 sect++;
1172 if (strcmp(sect->sectname, "__nl_symbol_ptr") == 0)
1173 sect++;
1174 if (strcmp(sect->sectname, "__bss") == 0) {
1175 bsssize = swav(sect->size);
1176 } else {
1177 werrstr("no bss section");
1178 goto bad;
1179 }
1180 }
1181 break;
1182 case MACH_UNIXTHREAD:
1183 break;
1184 case MACH_SYMSEG:
1185 if (symtab == 0)
1186 symtab = (MachSymSeg*)c;
1187 else if (pclntab == 0)
1188 pclntab = (MachSymSeg*)c;
1189 break;
1190 }
1191 cmdp += c->size;
1192 }
1193 if (textva == 0 || datava == 0) {
1194 free(cmd);
1195 free(cmdbuf);
1196 return 0;
1197 }
1198 /* compute entry by taking address after header - weird - BUG? */
1199 settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
1200 setdata(fp, datava, datasize, dataoff, bsssize);
1201 if(symtab != 0)
1202 setsym(fp, symtab->fileoff, symtab->filesize, 0, 0, 0, pclntab? pclntab->filesize : 0);
1203 free(cmd);
1204 free(cmdbuf);
1205 return 1;
1206 bad:
1207 free(cmd);
1208 free(cmdbuf);
1209 return 0;
1210 }
1211
1212 /*
1213 * (Free|Net)BSD ARM header.
1214 */
1215 static int
1216 armdotout(int fd, Fhdr *fp, ExecHdr *hp)
1217 {
1218 uvlong kbase;
1219
1220 USED(fd);
1221 settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec));
1222 setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss);
1223 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
1224
1225 kbase = 0xF0000000;
1226 if ((fp->entry & kbase) == kbase) { /* Boot image */
1227 fp->txtaddr = kbase+sizeof(Exec);
1228 fp->name = "ARM *BSD boot image";
1229 fp->hdrsz = 0; /* header stripped */
1230 fp->dataddr = kbase+fp->txtsz;
1231 }
1232 return 1;
1233 }
1234
1235 static void
1236 settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
1237 {
1238 fp->txtaddr = a;
1239 fp->entry = e;
1240 fp->txtsz = s;
1241 fp->txtoff = off;
1242 }
1243
1244 static void
1245 setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
1246 {
1247 fp->dataddr = a;
1248 fp->datsz = s;
1249 fp->datoff = off;
1250 fp->bsssz = bss;
1251 }
1252
1253 static void
1254 setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
1255 {
1256 fp->symoff = symoff;
1257 fp->symsz = symsz;
1258
1259 if(sppcoff == 0)
1260 sppcoff = symoff+symsz;
1261 fp->sppcoff = symoff;
1262 fp->sppcsz = sppcsz;
1263
1264 if(lnpcoff == 0)
1265 lnpcoff = sppcoff + sppcsz;
1266 fp->lnpcoff = lnpcoff;
1267 fp->lnpcsz = lnpcsz;
1268 }
1269
1270
1271 static uvlong
1272 _round(uvlong a, uint32 b)
1273 {
1274 uvlong w;
1275
1276 w = (a/b)*b;
1277 if (a!=w)
1278 w += b;
1279 return(w);
1280 }