]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/executable.c
46b1a07d74af93696ac4e79834445f66ee0a730d
[plan9front.git] / sys / src / libmach / executable.c
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                 E64hdr;
21                 struct mipsexec;        /* bootexec.h */
22                 struct mips4kexec;      /* bootexec.h */
23                 struct sparcexec;       /* bootexec.h */
24                 struct nextexec;        /* bootexec.h */
25         } e;
26         long dummy;                     /* padding to ensure extra long */
27 } ExecHdr;
28
29 static  int     nextboot(int, Fhdr*, ExecHdr*);
30 static  int     sparcboot(int, Fhdr*, ExecHdr*);
31 static  int     mipsboot(int, Fhdr*, ExecHdr*);
32 static  int     mips4kboot(int, Fhdr*, ExecHdr*);
33 static  int     common(int, Fhdr*, ExecHdr*);
34 static  int     commonllp64(int, Fhdr*, ExecHdr*);
35 static  int     adotout(int, Fhdr*, ExecHdr*);
36 static  int     elfdotout(int, Fhdr*, ExecHdr*);
37 static  int     armdotout(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         uchar   type;                   /* Internal code */
53         uchar   _magic;                 /* _MAGIC() magic */
54         Mach    *mach;                  /* Per-machine data */
55         long    hsize;                  /* header size */
56         ulong   (*swal)(ulong);         /* beswal or leswal */
57         int     (*hparse)(int, Fhdr*, ExecHdr*);
58 } ExecTable;
59
60 extern  Mach    mmips;
61 extern  Mach    mmips2le;
62 extern  Mach    mmips2be;
63 extern  Mach    msparc;
64 extern  Mach    msparc64;
65 extern  Mach    m68020;
66 extern  Mach    mi386;
67 extern  Mach    mamd64;
68 extern  Mach    marm;
69 extern  Mach    marm64;
70 extern  Mach    mpower;
71 extern  Mach    mpower64;
72
73 ExecTable exectab[] =
74 {
75         { V_MAGIC,                      /* Mips v.out */
76                 "mips plan 9 executable BE",
77                 "mips plan 9 dlm BE",
78                 FMIPS,
79                 1,
80                 &mmips,
81                 sizeof(Exec),
82                 beswal,
83                 adotout },
84         { P_MAGIC,                      /* Mips 0.out (r3k le) */
85                 "mips plan 9 executable LE",
86                 "mips plan 9 dlm LE",
87                 FMIPSLE,
88                 1,
89                 &mmips,
90                 sizeof(Exec),
91                 beswal,
92                 adotout },
93         { M_MAGIC,                      /* Mips 4.out */
94                 "mips 4k plan 9 executable BE",
95                 "mips 4k plan 9 dlm BE",
96                 FMIPS2BE,
97                 1,
98                 &mmips2be,
99                 sizeof(Exec),
100                 beswal,
101                 adotout },
102         { N_MAGIC,                      /* Mips 0.out */
103                 "mips 4k plan 9 executable LE",
104                 "mips 4k plan 9 dlm LE",
105                 FMIPS2LE,
106                 1,
107                 &mmips2le,
108                 sizeof(Exec),
109                 beswal,
110                 adotout },
111         { 0x160<<16,                    /* Mips boot image */
112                 "mips plan 9 boot image",
113                 nil,
114                 FMIPSB,
115                 0,
116                 &mmips,
117                 sizeof(struct mipsexec),
118                 beswal,
119                 mipsboot },
120         { (0x160<<16)|3,                /* Mips boot image */
121                 "mips 4k plan 9 boot image",
122                 nil,
123                 FMIPSB,
124                 0,
125                 &mmips2be,
126                 sizeof(struct mips4kexec),
127                 beswal,
128                 mips4kboot },
129         { K_MAGIC,                      /* Sparc k.out */
130                 "sparc plan 9 executable",
131                 "sparc plan 9 dlm",
132                 FSPARC,
133                 1,
134                 &msparc,
135                 sizeof(Exec),
136                 beswal,
137                 adotout },
138         { 0x01030107,                   /* Sparc boot image */
139                 "sparc plan 9 boot image",
140                 nil,
141                 FSPARCB,
142                 0,
143                 &msparc,
144                 sizeof(struct sparcexec),
145                 beswal,
146                 sparcboot },
147         { U_MAGIC,                      /* Sparc64 u.out */
148                 "sparc64 plan 9 executable",
149                 "sparc64 plan 9 dlm",
150                 FSPARC64,
151                 1,
152                 &msparc64,
153                 sizeof(Exec),
154                 beswal,
155                 adotout },
156         { A_MAGIC,                      /* 68020 2.out & boot image */
157                 "68020 plan 9 executable",
158                 "68020 plan 9 dlm",
159                 F68020,
160                 1,
161                 &m68020,
162                 sizeof(Exec),
163                 beswal,
164                 common },
165         { 0xFEEDFACE,                   /* Next boot image */
166                 "next plan 9 boot image",
167                 nil,
168                 FNEXTB,
169                 0,
170                 &m68020,
171                 sizeof(struct nextexec),
172                 beswal,
173                 nextboot },
174         { I_MAGIC,                      /* I386 8.out & boot image */
175                 "386 plan 9 executable",
176                 "386 plan 9 dlm",
177                 FI386,
178                 1,
179                 &mi386,
180                 sizeof(Exec),
181                 beswal,
182                 common },
183         { S_MAGIC,                      /* amd64 6.out & boot image */
184                 "amd64 plan 9 executable",
185                 "amd64 plan 9 dlm",
186                 FAMD64,
187                 1,
188                 &mamd64,
189                 sizeof(Exec)+8,
190                 nil,
191                 commonllp64 },
192         { Q_MAGIC,                      /* PowerPC q.out & boot image */
193                 "power plan 9 executable",
194                 "power plan 9 dlm",
195                 FPOWER,
196                 1,
197                 &mpower,
198                 sizeof(Exec),
199                 beswal,
200                 common },
201         { T_MAGIC,                      /* power64 9.out & boot image */
202                 "power64 plan 9 executable",
203                 "power64 plan 9 dlm",
204                 FPOWER64,
205                 1,
206                 &mpower64,
207                 sizeof(Exec)+8,
208                 nil,
209                 commonllp64 },
210         { ELF_MAG,                      /* any ELF */
211                 "elf executable",
212                 nil,
213                 FNONE,
214                 0,
215                 &mi386,
216                 sizeof(Ehdr),
217                 nil,
218                 elfdotout },
219         { E_MAGIC,                      /* Arm 5.out and boot image */
220                 "arm plan 9 executable",
221                 "arm plan 9 dlm",
222                 FARM,
223                 1,
224                 &marm,
225                 sizeof(Exec),
226                 beswal,
227                 common },
228         { (143<<16)|0413,               /* (Free|Net)BSD Arm */
229                 "arm *bsd executable",
230                 nil,
231                 FARM,
232                 0,
233                 &marm,
234                 sizeof(Exec),
235                 leswal,
236                 armdotout },
237         { R_MAGIC,                      /* Arm64 7.out and boot image */
238                 "arm64 plan 9 executable",
239                 "arm64 plan 9 dlm",
240                 FARM64,
241                 1,
242                 &marm64,
243                 sizeof(Exec)+8,
244                 nil,
245                 commonllp64 },
246         { 0 },
247 };
248
249 Mach    *mach = &mi386;                 /* Global current machine table */
250
251 static ExecTable*
252 couldbe4k(ExecTable *mp)
253 {
254         Dir *d;
255         ExecTable *f;
256
257         if((d=dirstat("/proc/1/regs")) == nil)
258                 return mp;
259         if(d->length < 32*8){           /* R3000 */
260                 free(d);
261                 return mp;
262         }
263         free(d);
264         for (f = exectab; f->magic; f++)
265                 if(f->magic == M_MAGIC) {
266                         f->name = "mips plan 9 executable on mips2 kernel";
267                         return f;
268                 }
269         return mp;
270 }
271
272 int
273 crackhdr(int fd, Fhdr *fp)
274 {
275         ExecTable *mp;
276         ExecHdr d;
277         int nb, ret;
278         ulong magic;
279
280         fp->type = FNONE;
281         nb = read(fd, (char *)&d.e, sizeof(d.e));
282         if (nb <= 0)
283                 return 0;
284
285         ret = 0;
286         magic = beswal(d.e.magic);              /* big-endian */
287         for (mp = exectab; mp->magic; mp++) {
288                 if (nb < mp->hsize)
289                         continue;
290
291                 /*
292                  * The magic number has morphed into something
293                  * with fields (the straw was DYN_MAGIC) so now
294                  * a flag is needed in Fhdr to distinguish _MAGIC()
295                  * magic numbers from foreign magic numbers.
296                  *
297                  * This code is creaking a bit and if it has to
298                  * be modified/extended much more it's probably
299                  * time to step back and redo it all.
300                  */
301                 if(mp->_magic){
302                         if(mp->magic != (magic & ~DYN_MAGIC))
303                                 continue;
304
305                         if(mp->magic == V_MAGIC)
306                                 mp = couldbe4k(mp);
307
308                         if ((magic & DYN_MAGIC) && mp->dlmname != nil)
309                                 fp->name = mp->dlmname;
310                         else
311                                 fp->name = mp->name;
312                 }
313                 else{
314                         if(mp->magic != magic)
315                                 continue;
316                         fp->name = mp->name;
317                 }
318                 fp->type = mp->type;
319                 fp->hdrsz = mp->hsize;          /* will be zero on bootables */
320                 fp->_magic = mp->_magic;
321                 fp->magic = magic;
322
323                 mach = mp->mach;
324                 if(mp->swal != nil)
325                         hswal(&d, sizeof(d.e)/sizeof(ulong), mp->swal);
326                 ret = mp->hparse(fd, fp, &d);
327                 seek(fd, mp->hsize, 0);         /* seek to end of header */
328                 break;
329         }
330         if(mp->magic == 0)
331                 werrstr("unknown header type");
332         return ret;
333 }
334
335 /*
336  * Convert header to canonical form
337  */
338 static void
339 hswal(void *v, int n, ulong (*swap)(ulong))
340 {
341         ulong *ulp;
342
343         for(ulp = v; n--; ulp++)
344                 *ulp = (*swap)(*ulp);
345 }
346
347 /*
348  *      Crack a normal a.out-type header
349  */
350 static int
351 adotout(int fd, Fhdr *fp, ExecHdr *hp)
352 {
353         long pgsize;
354
355         USED(fd);
356         pgsize = mach->pgsize;
357         settext(fp, hp->e.entry, pgsize+sizeof(Exec),
358                         hp->e.text, sizeof(Exec));
359         setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
360                 hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss);
361         setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
362         return 1;
363 }
364
365 static void
366 commonboot(Fhdr *fp)
367 {
368         if (!(fp->entry & mach->ktmask))
369                 return;
370
371         switch(fp->type) {                              /* boot image */
372         case F68020:
373                 fp->type = F68020B;
374                 fp->name = "68020 plan 9 boot image";
375                 break;
376         case FI386:
377                 fp->type = FI386B;
378                 fp->txtaddr = (u32int)fp->entry;
379                 fp->name = "386 plan 9 boot image";
380                 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
381                 break;
382         case FARM:
383                 fp->type = FARMB;
384                 fp->txtaddr = (u32int)fp->entry;
385                 fp->name = "ARM plan 9 boot image";
386                 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
387                 return;
388         case FARM64:
389                 fp->type = FARM64B;
390                 fp->txtaddr = fp->entry;
391                 fp->name = "arm64 plan 9 boot image";
392                 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
393                 return;
394         case FPOWER:
395                 fp->type = FPOWERB;
396                 fp->txtaddr = (u32int)fp->entry;
397                 fp->name = "power plan 9 boot image";
398                 fp->dataddr = fp->txtaddr+fp->txtsz;
399                 break;
400         case FAMD64:
401                 fp->type = FAMD64B;
402                 fp->txtaddr = fp->entry;
403                 fp->name = "amd64 plan 9 boot image";
404                 fp->dataddr = _round(fp->txtaddr+fp->txtsz, 4096);
405                 break;
406         case FPOWER64:
407                 fp->type = FPOWER64B;
408                 fp->txtaddr = fp->entry;
409                 fp->name = "power64 plan 9 boot image";
410                 fp->dataddr = fp->txtaddr+fp->txtsz;
411                 break;
412         default:
413                 return;
414         }
415         fp->hdrsz = 0;                  /* header stripped */
416 }
417
418 /*
419  *      _MAGIC() style headers and
420  *      alpha plan9-style bootable images for axp "headerless" boot
421  *
422  */
423 static int
424 common(int fd, Fhdr *fp, ExecHdr *hp)
425 {
426         adotout(fd, fp, hp);
427         if(hp->e.magic & DYN_MAGIC) {
428                 fp->txtaddr = 0;
429                 fp->dataddr = fp->txtsz;
430                 return 1;
431         }
432         commonboot(fp);
433         return 1;
434 }
435
436 static int
437 commonllp64(int, Fhdr *fp, ExecHdr *hp)
438 {
439         long pgsize;
440         uvlong entry;
441
442         hswal(&hp->e, sizeof(Exec)/sizeof(long), beswal);
443         if(!(hp->e.magic & HDR_MAGIC))
444                 return 0;
445
446         /*
447          * There can be more magic here if the
448          * header ever needs more expansion.
449          * For now just catch use of any of the
450          * unused bits.
451          */
452         if((hp->e.magic & ~DYN_MAGIC)>>16)
453                 return 0;
454         entry = beswav(hp->e.hdr[0]);
455
456         pgsize = mach->pgsize;
457         settext(fp, entry, pgsize+fp->hdrsz, hp->e.text, fp->hdrsz);
458         setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
459                 hp->e.data, fp->txtsz+fp->hdrsz, hp->e.bss);
460         setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
461
462         if(hp->e.magic & DYN_MAGIC) {
463                 fp->txtaddr = 0;
464                 fp->dataddr = fp->txtsz;
465                 return 1;
466         }
467         commonboot(fp);
468         return 1;
469 }
470
471 /*
472  *      mips bootable image.
473  */
474 static int
475 mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
476 {
477         USED(fd);
478         fp->type = FMIPSB;
479         switch(hp->e.amagic) {
480         default:
481         case 0407:      /* some kind of mips */
482                 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
483                         hp->e.tsize, sizeof(struct mipsexec)+4);
484                 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
485                         fp->txtoff+hp->e.tsize, hp->e.bsize);
486                 break;
487         case 0413:      /* some kind of mips */
488                 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
489                         hp->e.tsize, 0);
490                 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
491                         hp->e.tsize, hp->e.bsize);
492                 break;
493         }
494         setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
495         fp->hdrsz = 0;                  /* header stripped */
496         return 1;
497 }
498
499 /*
500  *      mips4k bootable image.
501  */
502 static int
503 mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
504 {
505         USED(fd);
506         fp->type = FMIPSB;
507         switch(hp->e.h.amagic) {
508         default:
509         case 0407:      /* some kind of mips */
510                 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
511                         hp->e.h.tsize, sizeof(struct mips4kexec));
512                 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
513                         fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
514                 break;
515         case 0413:      /* some kind of mips */
516                 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
517                         hp->e.h.tsize, 0);
518                 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
519                         hp->e.h.tsize, hp->e.h.bsize);
520                 break;
521         }
522         setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
523         fp->hdrsz = 0;                  /* header stripped */
524         return 1;
525 }
526
527 /*
528  *      sparc bootable image
529  */
530 static int
531 sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
532 {
533         USED(fd);
534         fp->type = FSPARCB;
535         settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
536                 sizeof(struct sparcexec));
537         setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
538                 fp->txtoff+hp->e.stext, hp->e.sbss);
539         setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
540         fp->hdrsz = 0;                  /* header stripped */
541         return 1;
542 }
543
544 /*
545  *      next bootable image
546  */
547 static int
548 nextboot(int fd, Fhdr *fp, ExecHdr *hp)
549 {
550         USED(fd);
551         fp->type = FNEXTB;
552         settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
553                 hp->e.texts.size, hp->e.texts.offset);
554         setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
555                 hp->e.datas.offset, hp->e.bsss.size);
556         setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
557                 hp->e.symc.symoff);
558         fp->hdrsz = 0;                  /* header stripped */
559         return 1;
560 }
561
562 /*
563  * ELF64 binaries.
564  */
565 static int
566 elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
567 {
568         E64hdr *ep;
569         P64hdr *ph;
570         ushort (*swab)(ushort);
571         ulong (*swal)(ulong);
572         uvlong (*swav)(uvlong);
573         int i, it, id, is, phsz;
574         uvlong uvl;
575
576         ep = &hp->e;
577         if(ep->ident[DATA] == ELFDATA2LSB) {
578                 swab = leswab;
579                 swal = leswal;
580                 swav = leswav;
581         } else if(ep->ident[DATA] == ELFDATA2MSB) {
582                 swab = beswab;
583                 swal = beswal;
584                 swav = beswav;
585         } else {
586                 werrstr("bad ELF64 encoding - not big or little endian");
587                 return 0;
588         }
589
590         ep->type = swab(ep->type);
591         ep->machine = swab(ep->machine);
592         ep->version = swal(ep->version);
593         if(ep->type != EXEC || ep->version != CURRENT)
594                 return 0;
595         ep->elfentry = swav(ep->elfentry);
596         ep->phoff = swav(ep->phoff);
597         ep->shoff = swav(ep->shoff);
598         ep->flags = swal(ep->flags);
599         ep->ehsize = swab(ep->ehsize);
600         ep->phentsize = swab(ep->phentsize);
601         ep->phnum = swab(ep->phnum);
602         ep->shentsize = swab(ep->shentsize);
603         ep->shnum = swab(ep->shnum);
604         ep->shstrndx = swab(ep->shstrndx);
605
606         fp->magic = ELF_MAG;
607         fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
608         switch(ep->machine) {
609         default:
610                 return 0;
611         case AMD64:
612                 mach = &mamd64;
613                 fp->type = FAMD64;
614                 fp->name = "amd64 ELF64 executable";
615                 break;
616         case POWER64:
617                 mach = &mpower64;
618                 fp->type = FPOWER64;
619                 fp->name = "power64 ELF64 executable";
620                 break;
621         }
622
623         if(ep->phentsize != sizeof(P64hdr)) {
624                 werrstr("bad ELF64 header size");
625                 return 0;
626         }
627         phsz = sizeof(P64hdr)*ep->phnum;
628         ph = malloc(phsz);
629         if(!ph)
630                 return 0;
631         seek(fd, ep->phoff, 0);
632         if(read(fd, ph, phsz) < 0) {
633                 free(ph);
634                 return 0;
635         }
636         for(i = 0; i < ep->phnum; i++) {
637                 ph[i].type = swal(ph[i].type);
638                 ph[i].flags = swal(ph[i].flags);
639                 ph[i].offset = swav(ph[i].offset);
640                 ph[i].vaddr = swav(ph[i].vaddr);
641                 ph[i].paddr = swav(ph[i].paddr);
642                 ph[i].filesz = swav(ph[i].filesz);
643                 ph[i].memsz = swav(ph[i].memsz);
644                 ph[i].align = swav(ph[i].align);
645         }
646
647         /* find text, data and symbols and install them */
648         it = id = is = -1;
649         for(i = 0; i < ep->phnum; i++) {
650                 if(ph[i].type == LOAD
651                 && (ph[i].flags & (R|X)) == (R|X) && it == -1)
652                         it = i;
653                 else if(ph[i].type == LOAD
654                 && (ph[i].flags & (R|W)) == (R|W) && id == -1)
655                         id = i;
656                 else if(ph[i].type == NOPTYPE && is == -1)
657                         is = i;
658         }
659         if(it == -1 || id == -1) {
660                 werrstr("No ELF64 TEXT or DATA sections");
661                 free(ph);
662                 return 0;
663         }
664
665         settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
666         /* 8c: out of fixed registers */
667         uvl = ph[id].memsz - ph[id].filesz;
668         setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, uvl);
669         if(is != -1)
670                 setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
671         free(ph);
672         return 1;
673 }
674
675 /*
676  * ELF32 binaries.
677  */
678 static int
679 elf32dotout(int fd, Fhdr *fp, ExecHdr *hp)
680 {
681         ulong (*swal)(ulong);
682         ushort (*swab)(ushort);
683         Ehdr *ep;
684         Phdr *ph;
685         int i, it, id, is, phsz;
686
687         /* bitswap the header according to the DATA format */
688         ep = &hp->e;
689         if(ep->ident[DATA] == ELFDATA2LSB) {
690                 swab = leswab;
691                 swal = leswal;
692         } else if(ep->ident[DATA] == ELFDATA2MSB) {
693                 swab = beswab;
694                 swal = beswal;
695         } else {
696                 werrstr("bad ELF32 encoding - not big or little endian");
697                 return 0;
698         }
699
700         ep->type = swab(ep->type);
701         ep->machine = swab(ep->machine);
702         ep->version = swal(ep->version);
703         ep->elfentry = swal(ep->elfentry);
704         ep->phoff = swal(ep->phoff);
705         ep->shoff = swal(ep->shoff);
706         ep->flags = swal(ep->flags);
707         ep->ehsize = swab(ep->ehsize);
708         ep->phentsize = swab(ep->phentsize);
709         ep->phnum = swab(ep->phnum);
710         ep->shentsize = swab(ep->shentsize);
711         ep->shnum = swab(ep->shnum);
712         ep->shstrndx = swab(ep->shstrndx);
713         if(ep->type != EXEC || ep->version != CURRENT)
714                 return 0;
715
716         /* we could definitely support a lot more machines here */
717         fp->magic = ELF_MAG;
718         fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
719         switch(ep->machine) {
720         case I386:
721                 mach = &mi386;
722                 fp->type = FI386;
723                 fp->name = "386 ELF32 executable";
724                 break;
725         case MIPS:
726                 mach = &mmips;
727                 if(ep->ident[DATA] == ELFDATA2LSB){
728                         fp->type = FMIPSLE;
729                         fp->name = "mips le ELF32 executable";
730                 } else {
731                         fp->type = FMIPS;
732                         fp->name = "mips be ELF32 executable";
733                 }
734                 break;
735         case SPARC64:
736                 mach = &msparc64;
737                 fp->type = FSPARC64;
738                 fp->name = "sparc64 ELF32 executable";
739                 break;
740         case POWER:
741                 mach = &mpower;
742                 fp->type = FPOWER;
743                 fp->name = "power ELF32 executable";
744                 break;
745         case POWER64:
746                 mach = &mpower64;
747                 fp->type = FPOWER64;
748                 fp->name = "power64 ELF32 executable";
749                 break;
750         case AMD64:
751                 mach = &mamd64;
752                 fp->type = FAMD64;
753                 fp->name = "amd64 ELF32 executable";
754                 break;
755         case ARM:
756                 mach = &marm;
757                 fp->type = FARM;
758                 fp->name = "arm ELF32 executable";
759                 break;
760         default:
761                 return 0;
762         }
763
764         if(ep->phentsize != sizeof(Phdr)) {
765                 werrstr("bad ELF32 header size");
766                 return 0;
767         }
768         phsz = sizeof(Phdr)*ep->phnum;
769         ph = malloc(phsz);
770         if(!ph)
771                 return 0;
772         seek(fd, ep->phoff, 0);
773         if(read(fd, ph, phsz) < 0) {
774                 free(ph);
775                 return 0;
776         }
777         hswal(ph, phsz/sizeof(ulong), swal);
778
779         /* find text, data and symbols and install them */
780         it = id = is = -1;
781         for(i = 0; i < ep->phnum; i++) {
782                 if(ph[i].type == LOAD
783                 && (ph[i].flags & (R|X)) == (R|X) && it == -1)
784                         it = i;
785                 else if(ph[i].type == LOAD
786                 && (ph[i].flags & (R|W)) == (R|W) && id == -1)
787                         id = i;
788                 else if(ph[i].type == NOPTYPE && is == -1)
789                         is = i;
790         }
791         if(it == -1 || id == -1) {
792                 /*
793                  * The SPARC64 boot image is something of an ELF hack.
794                  * Text+Data+BSS are represented by ph[0].  Symbols
795                  * are represented by ph[1]:
796                  *
797                  *              filesz, memsz, vaddr, paddr, off
798                  * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
799                  * ph[1] : symsz, lcsz, 0, 0, symoff
800                  */
801                 if(ep->machine == SPARC64 && ep->phnum == 2) {
802                         ulong txtaddr, txtsz, dataddr, bsssz;
803
804                         txtaddr = ph[0].vaddr | 0x80000000;
805                         txtsz = ph[0].filesz - ph[0].paddr;
806                         dataddr = txtaddr + txtsz;
807                         bsssz = ph[0].memsz - ph[0].filesz;
808                         settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
809                         setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
810                         setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset);
811                         free(ph);
812                         return 1;
813                 }
814
815                 werrstr("No ELF32 TEXT or DATA sections");
816                 free(ph);
817                 return 0;
818         }
819
820         settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
821         setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
822         if(is != -1)
823                 setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
824         free(ph);
825         return 1;
826 }
827
828 /*
829  * Elf binaries.
830  */
831 static int
832 elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
833 {
834         Ehdr *ep;
835
836         /* bitswap the header according to the DATA format */
837         ep = &hp->e;
838         if(ep->ident[CLASS] == ELFCLASS32)
839                 return elf32dotout(fd, fp, hp);
840         else if(ep->ident[CLASS] == ELFCLASS64)
841                 return elf64dotout(fd, fp, hp);
842
843         werrstr("bad ELF class - not 32 bit");
844         return 0;
845 }
846
847 /*
848  * (Free|Net)BSD ARM header.
849  */
850 static int
851 armdotout(int fd, Fhdr *fp, ExecHdr *hp)
852 {
853         uvlong kbase;
854
855         USED(fd);
856         settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec));
857         setdata(fp, fp->txtsz, hp->e.data, fp->txtsz, hp->e.bss);
858         setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
859
860         kbase = 0xF0000000;
861         if ((fp->entry & kbase) == kbase) {             /* Boot image */
862                 fp->txtaddr = kbase+sizeof(Exec);
863                 fp->name = "ARM *BSD boot image";
864                 fp->hdrsz = 0;          /* header stripped */
865                 fp->dataddr = kbase+fp->txtsz;
866         }
867         return 1;
868 }
869
870 static void
871 settext(Fhdr *fp, uvlong e, uvlong a, long s, vlong off)
872 {
873         fp->txtaddr = a;
874         fp->entry = e;
875         fp->txtsz = s;
876         fp->txtoff = off;
877 }
878
879 static void
880 setdata(Fhdr *fp, uvlong a, long s, vlong off, long bss)
881 {
882         fp->dataddr = a;
883         fp->datsz = s;
884         fp->datoff = off;
885         fp->bsssz = bss;
886 }
887
888 static void
889 setsym(Fhdr *fp, long symsz, long sppcsz, long lnpcsz, vlong symoff)
890 {
891         fp->symsz = symsz;
892         fp->symoff = symoff;
893         fp->sppcsz = sppcsz;
894         fp->sppcoff = fp->symoff+fp->symsz;
895         fp->lnpcsz = lnpcsz;
896         fp->lnpcoff = fp->sppcoff+fp->sppcsz;
897 }
898
899
900 static uvlong
901 _round(uvlong a, ulong b)
902 {
903         uvlong w;
904
905         w = (a/b)*b;
906         if (a!=w)
907                 w += b;
908         return(w);
909 }