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