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