github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/libmach/executable.c (about) 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 int pedotout(int, Fhdr*, ExecHdr*); 70 static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32); 71 static void setdata(Fhdr*, uvlong, int32, vlong, int32); 72 static void settext(Fhdr*, uvlong, uvlong, int32, vlong); 73 static void hswal(void*, int, uint32(*)(uint32)); 74 static uvlong _round(uvlong, uint32); 75 76 /* 77 * definition of per-executable file type structures 78 */ 79 80 typedef struct Exectable{ 81 int32 magic; /* big-endian magic number of file */ 82 char *name; /* executable identifier */ 83 char *dlmname; /* dynamically loadable module identifier */ 84 uchar type; /* Internal code */ 85 uchar _magic; /* _MAGIC() magic */ 86 Mach *mach; /* Per-machine data */ 87 int32 hsize; /* header size */ 88 uint32 (*swal)(uint32); /* beswal or leswal */ 89 int (*hparse)(int, Fhdr*, ExecHdr*); 90 } ExecTable; 91 92 extern Mach mmips; 93 extern Mach mmips2le; 94 extern Mach mmips2be; 95 extern Mach msparc; 96 extern Mach msparc64; 97 extern Mach m68020; 98 extern Mach mi386; 99 extern Mach mamd64; 100 extern Mach marm; 101 extern Mach mpower; 102 extern Mach mpower64; 103 extern Mach malpha; 104 105 /* BUG: FIX THESE WHEN NEEDED */ 106 Mach mmips; 107 Mach mmips2le; 108 Mach mmips2be; 109 Mach msparc; 110 Mach msparc64; 111 Mach m68020; 112 Mach mpower; 113 Mach mpower64; 114 Mach malpha; 115 116 ExecTable exectab[] = 117 { 118 { V_MAGIC, /* Mips v.out */ 119 "mips plan 9 executable BE", 120 "mips plan 9 dlm BE", 121 FMIPS, 122 1, 123 &mmips, 124 sizeof(Exec), 125 beswal, 126 adotout }, 127 { P_MAGIC, /* Mips 0.out (r3k le) */ 128 "mips plan 9 executable LE", 129 "mips plan 9 dlm LE", 130 FMIPSLE, 131 1, 132 &mmips, 133 sizeof(Exec), 134 beswal, 135 adotout }, 136 { M_MAGIC, /* Mips 4.out */ 137 "mips 4k plan 9 executable BE", 138 "mips 4k plan 9 dlm BE", 139 FMIPS2BE, 140 1, 141 &mmips2be, 142 sizeof(Exec), 143 beswal, 144 adotout }, 145 { N_MAGIC, /* Mips 0.out */ 146 "mips 4k plan 9 executable LE", 147 "mips 4k plan 9 dlm LE", 148 FMIPS2LE, 149 1, 150 &mmips2le, 151 sizeof(Exec), 152 beswal, 153 adotout }, 154 { 0x160<<16, /* Mips boot image */ 155 "mips plan 9 boot image", 156 nil, 157 FMIPSB, 158 0, 159 &mmips, 160 sizeof(struct mipsexec), 161 beswal, 162 mipsboot }, 163 { (0x160<<16)|3, /* Mips boot image */ 164 "mips 4k plan 9 boot image", 165 nil, 166 FMIPSB, 167 0, 168 &mmips2be, 169 sizeof(struct mips4kexec), 170 beswal, 171 mips4kboot }, 172 { K_MAGIC, /* Sparc k.out */ 173 "sparc plan 9 executable", 174 "sparc plan 9 dlm", 175 FSPARC, 176 1, 177 &msparc, 178 sizeof(Exec), 179 beswal, 180 adotout }, 181 { 0x01030107, /* Sparc boot image */ 182 "sparc plan 9 boot image", 183 nil, 184 FSPARCB, 185 0, 186 &msparc, 187 sizeof(struct sparcexec), 188 beswal, 189 sparcboot }, 190 { U_MAGIC, /* Sparc64 u.out */ 191 "sparc64 plan 9 executable", 192 "sparc64 plan 9 dlm", 193 FSPARC64, 194 1, 195 &msparc64, 196 sizeof(Exec), 197 beswal, 198 adotout }, 199 { A_MAGIC, /* 68020 2.out & boot image */ 200 "68020 plan 9 executable", 201 "68020 plan 9 dlm", 202 F68020, 203 1, 204 &m68020, 205 sizeof(Exec), 206 beswal, 207 common }, 208 { 0xFEEDFACE, /* Next boot image */ 209 "next plan 9 boot image", 210 nil, 211 FNEXTB, 212 0, 213 &m68020, 214 sizeof(struct nextexec), 215 beswal, 216 nextboot }, 217 { I_MAGIC, /* I386 8.out & boot image */ 218 "386 plan 9 executable", 219 "386 plan 9 dlm", 220 FI386, 221 1, 222 &mi386, 223 sizeof(Exec), 224 beswal, 225 common }, 226 { S_MAGIC, /* amd64 6.out & boot image */ 227 "amd64 plan 9 executable", 228 "amd64 plan 9 dlm", 229 FAMD64, 230 1, 231 &mamd64, 232 sizeof(Exec)+8, 233 nil, 234 commonllp64 }, 235 { Q_MAGIC, /* PowerPC q.out & boot image */ 236 "power plan 9 executable", 237 "power plan 9 dlm", 238 FPOWER, 239 1, 240 &mpower, 241 sizeof(Exec), 242 beswal, 243 common }, 244 { T_MAGIC, /* power64 9.out & boot image */ 245 "power64 plan 9 executable", 246 "power64 plan 9 dlm", 247 FPOWER64, 248 1, 249 &mpower64, 250 sizeof(Exec)+8, 251 nil, 252 commonllp64 }, 253 { ELF_MAG, /* any elf32 or elf64 */ 254 "elf executable", 255 nil, 256 FNONE, 257 0, 258 &mi386, 259 sizeof(Ehdr64), 260 nil, 261 elfdotout }, 262 { MACH64_MAG, /* 64-bit MACH (apple mac) */ 263 "mach executable", 264 nil, 265 FAMD64, 266 0, 267 &mamd64, 268 sizeof(Machhdr), 269 nil, 270 machdotout }, 271 { MACH32_MAG, /* 32-bit MACH (apple mac) */ 272 "mach executable", 273 nil, 274 FI386, 275 0, 276 &mi386, 277 sizeof(Machhdr), 278 nil, 279 machdotout }, 280 { E_MAGIC, /* Arm 5.out and boot image */ 281 "arm plan 9 executable", 282 "arm plan 9 dlm", 283 FARM, 284 1, 285 &marm, 286 sizeof(Exec), 287 beswal, 288 common }, 289 { (143<<16)|0413, /* (Free|Net)BSD Arm */ 290 "arm *bsd executable", 291 nil, 292 FARM, 293 0, 294 &marm, 295 sizeof(Exec), 296 leswal, 297 armdotout }, 298 { L_MAGIC, /* alpha 7.out */ 299 "alpha plan 9 executable", 300 "alpha plan 9 dlm", 301 FALPHA, 302 1, 303 &malpha, 304 sizeof(Exec), 305 beswal, 306 common }, 307 { 0x0700e0c3, /* alpha boot image */ 308 "alpha plan 9 boot image", 309 nil, 310 FALPHA, 311 0, 312 &malpha, 313 sizeof(Exec), 314 beswal, 315 common }, 316 { 0x4d5a9000, /* see dosstub[] in pe.c */ 317 "windows PE executable", 318 nil, 319 FWINPE, 320 0, 321 &mi386, 322 sizeof(Exec), /* TODO */ 323 nil, 324 pedotout }, 325 { 0 }, 326 }; 327 328 Mach *mach = &mi386; /* Global current machine table */ 329 330 static ExecTable* 331 couldbe4k(ExecTable *mp) 332 { 333 Dir *d; 334 ExecTable *f; 335 336 if((d=dirstat("/proc/1/regs")) == nil) 337 return mp; 338 if(d->length < 32*8){ /* R3000 */ 339 free(d); 340 return mp; 341 } 342 free(d); 343 for (f = exectab; f->magic; f++) 344 if(f->magic == M_MAGIC) { 345 f->name = "mips plan 9 executable on mips2 kernel"; 346 return f; 347 } 348 return mp; 349 } 350 351 int 352 crackhdr(int fd, Fhdr *fp) 353 { 354 ExecTable *mp; 355 ExecHdr d; 356 int nb, ret; 357 uint32 magic; 358 359 fp->type = FNONE; 360 nb = read(fd, (char *)&d.e, sizeof(d.e)); 361 if (nb <= 0) 362 return 0; 363 364 ret = 0; 365 magic = beswal(d.e.exechdr.magic); /* big-endian */ 366 for (mp = exectab; mp->magic; mp++) { 367 if (nb < mp->hsize) 368 continue; 369 370 /* 371 * The magic number has morphed into something 372 * with fields (the straw was DYN_MAGIC) so now 373 * a flag is needed in Fhdr to distinguish _MAGIC() 374 * magic numbers from foreign magic numbers. 375 * 376 * This code is creaking a bit and if it has to 377 * be modified/extended much more it's probably 378 * time to step back and redo it all. 379 */ 380 if(mp->_magic){ 381 if(mp->magic != (magic & ~DYN_MAGIC)) 382 continue; 383 384 if(mp->magic == V_MAGIC) 385 mp = couldbe4k(mp); 386 387 if ((magic & DYN_MAGIC) && mp->dlmname != nil) 388 fp->name = mp->dlmname; 389 else 390 fp->name = mp->name; 391 } 392 else{ 393 if(mp->magic != magic) 394 continue; 395 fp->name = mp->name; 396 } 397 fp->type = mp->type; 398 fp->hdrsz = mp->hsize; /* will be zero on bootables */ 399 fp->_magic = mp->_magic; 400 fp->magic = magic; 401 402 mach = mp->mach; 403 if(mp->swal != nil) 404 hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal); 405 ret = mp->hparse(fd, fp, &d); 406 seek(fd, mp->hsize, 0); /* seek to end of header */ 407 break; 408 } 409 if(mp->magic == 0) 410 werrstr("unknown header type"); 411 return ret; 412 } 413 414 /* 415 * Convert header to canonical form 416 */ 417 static void 418 hswal(void *v, int n, uint32 (*swap)(uint32)) 419 { 420 uint32 *ulp; 421 422 for(ulp = v; n--; ulp++) 423 *ulp = (*swap)(*ulp); 424 } 425 426 /* 427 * Crack a normal a.out-type header 428 */ 429 static int 430 adotout(int fd, Fhdr *fp, ExecHdr *hp) 431 { 432 int32 pgsize; 433 434 USED(fd); 435 pgsize = mach->pgsize; 436 settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec), 437 hp->e.exechdr.text, sizeof(Exec)); 438 setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize), 439 hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss); 440 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz); 441 return 1; 442 } 443 444 static void 445 commonboot(Fhdr *fp) 446 { 447 if (!(fp->entry & mach->ktmask)) 448 return; 449 450 switch(fp->type) { /* boot image */ 451 case F68020: 452 fp->type = F68020B; 453 fp->name = "68020 plan 9 boot image"; 454 break; 455 case FI386: 456 fp->type = FI386B; 457 fp->txtaddr = (u32int)fp->entry; 458 fp->name = "386 plan 9 boot image"; 459 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); 460 break; 461 case FARM: 462 fp->type = FARMB; 463 fp->txtaddr = (u32int)fp->entry; 464 fp->name = "ARM plan 9 boot image"; 465 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); 466 return; 467 case FALPHA: 468 fp->type = FALPHAB; 469 fp->txtaddr = (u32int)fp->entry; 470 fp->name = "alpha plan 9 boot image"; 471 fp->dataddr = fp->txtaddr+fp->txtsz; 472 break; 473 case FPOWER: 474 fp->type = FPOWERB; 475 fp->txtaddr = (u32int)fp->entry; 476 fp->name = "power plan 9 boot image"; 477 fp->dataddr = fp->txtaddr+fp->txtsz; 478 break; 479 case FAMD64: 480 fp->type = FAMD64B; 481 fp->txtaddr = fp->entry; 482 fp->name = "amd64 plan 9 boot image"; 483 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); 484 break; 485 default: 486 return; 487 } 488 fp->hdrsz = 0; /* header stripped */ 489 } 490 491 /* 492 * _MAGIC() style headers and 493 * alpha plan9-style bootable images for axp "headerless" boot 494 * 495 */ 496 static int 497 common(int fd, Fhdr *fp, ExecHdr *hp) 498 { 499 adotout(fd, fp, hp); 500 if(hp->e.exechdr.magic & DYN_MAGIC) { 501 fp->txtaddr = 0; 502 fp->dataddr = fp->txtsz; 503 return 1; 504 } 505 commonboot(fp); 506 return 1; 507 } 508 509 static int 510 commonllp64(int unused, Fhdr *fp, ExecHdr *hp) 511 { 512 int32 pgsize; 513 uvlong entry; 514 515 USED(unused); 516 517 hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal); 518 if(!(hp->e.exechdr.magic & HDR_MAGIC)) 519 return 0; 520 521 /* 522 * There can be more magic here if the 523 * header ever needs more expansion. 524 * For now just catch use of any of the 525 * unused bits. 526 */ 527 if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16) 528 return 0; 529 union { 530 char *p; 531 uvlong *v; 532 } u; 533 u.p = (char*)&hp->e.exechdr; 534 entry = beswav(*u.v); 535 536 pgsize = mach->pgsize; 537 settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz); 538 setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize), 539 hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss); 540 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz); 541 542 if(hp->e.exechdr.magic & DYN_MAGIC) { 543 fp->txtaddr = 0; 544 fp->dataddr = fp->txtsz; 545 return 1; 546 } 547 commonboot(fp); 548 return 1; 549 } 550 551 /* 552 * mips bootable image. 553 */ 554 static int 555 mipsboot(int fd, Fhdr *fp, ExecHdr *hp) 556 { 557 USED(fd); 558 USED(fp); 559 USED(hp); 560 561 abort(); 562 #ifdef unused 563 USED(fd); 564 fp->type = FMIPSB; 565 switch(hp->e.exechdr.amagic) { 566 default: 567 case 0407: /* some kind of mips */ 568 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start, 569 hp->e.tsize, sizeof(struct mipsexec)+4); 570 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize, 571 fp->txtoff+hp->e.tsize, hp->e.bsize); 572 break; 573 case 0413: /* some kind of mips */ 574 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start, 575 hp->e.tsize, 0); 576 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize, 577 hp->e.tsize, hp->e.bsize); 578 break; 579 } 580 setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr); 581 fp->hdrsz = 0; /* header stripped */ 582 #endif 583 return 1; 584 } 585 586 /* 587 * mips4k bootable image. 588 */ 589 static int 590 mips4kboot(int fd, Fhdr *fp, ExecHdr *hp) 591 { 592 USED(fd); 593 USED(fp); 594 USED(hp); 595 596 abort(); 597 #ifdef unused 598 USED(fd); 599 fp->type = FMIPSB; 600 switch(hp->e.h.amagic) { 601 default: 602 case 0407: /* some kind of mips */ 603 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start, 604 hp->e.h.tsize, sizeof(struct mips4kexec)); 605 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize, 606 fp->txtoff+hp->e.h.tsize, hp->e.h.bsize); 607 break; 608 case 0413: /* some kind of mips */ 609 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start, 610 hp->e.h.tsize, 0); 611 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize, 612 hp->e.h.tsize, hp->e.h.bsize); 613 break; 614 } 615 setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr); 616 fp->hdrsz = 0; /* header stripped */ 617 #endif 618 return 1; 619 } 620 621 /* 622 * sparc bootable image 623 */ 624 static int 625 sparcboot(int fd, Fhdr *fp, ExecHdr *hp) 626 { 627 USED(fd); 628 USED(fp); 629 USED(hp); 630 631 abort(); 632 #ifdef unused 633 USED(fd); 634 fp->type = FSPARCB; 635 settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext, 636 sizeof(struct sparcexec)); 637 setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata, 638 fp->txtoff+hp->e.stext, hp->e.sbss); 639 setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata); 640 fp->hdrsz = 0; /* header stripped */ 641 #endif 642 return 1; 643 } 644 645 /* 646 * next bootable image 647 */ 648 static int 649 nextboot(int fd, Fhdr *fp, ExecHdr *hp) 650 { 651 USED(fd); 652 USED(fp); 653 USED(hp); 654 655 abort(); 656 #ifdef unused 657 USED(fd); 658 fp->type = FNEXTB; 659 settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr, 660 hp->e.texts.size, hp->e.texts.offset); 661 setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size, 662 hp->e.datas.offset, hp->e.bsss.size); 663 setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff, 664 hp->e.symc.symoff); 665 fp->hdrsz = 0; /* header stripped */ 666 #endif 667 return 1; 668 } 669 670 /* 671 * Elf32 and Elf64 binaries. 672 */ 673 static int 674 elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) 675 { 676 uvlong (*swav)(uvlong); 677 uint32 (*swal)(uint32); 678 ushort (*swab)(ushort); 679 Ehdr64 *ep; 680 Phdr64 *ph, *pph; 681 Shdr64 *sh; 682 int i, it, id, is, phsz, shsz; 683 684 /* bitswap the header according to the DATA format */ 685 ep = &hp->e.elfhdr64; 686 if(ep->ident[CLASS] != ELFCLASS64) { 687 werrstr("bad ELF class - not 32 bit or 64 bit"); 688 return 0; 689 } 690 if(ep->ident[DATA] == ELFDATA2LSB) { 691 swab = leswab; 692 swal = leswal; 693 swav = leswav; 694 } else if(ep->ident[DATA] == ELFDATA2MSB) { 695 swab = beswab; 696 swal = beswal; 697 swav = beswav; 698 } else { 699 werrstr("bad ELF encoding - not big or little endian"); 700 return 0; 701 } 702 703 ep->type = swab(ep->type); 704 ep->machine = swab(ep->machine); 705 ep->version = swal(ep->version); 706 ep->elfentry = swal(ep->elfentry); 707 ep->phoff = swav(ep->phoff); 708 ep->shoff = swav(ep->shoff); 709 ep->flags = swav(ep->flags); 710 ep->ehsize = swab(ep->ehsize); 711 ep->phentsize = swab(ep->phentsize); 712 ep->phnum = swab(ep->phnum); 713 ep->shentsize = swab(ep->shentsize); 714 ep->shnum = swab(ep->shnum); 715 ep->shstrndx = swab(ep->shstrndx); 716 if(ep->type != EXEC || ep->version != CURRENT) 717 return 0; 718 719 /* we could definitely support a lot more machines here */ 720 fp->magic = ELF_MAG; 721 fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; 722 switch(ep->machine) { 723 case AMD64: 724 mach = &mamd64; 725 fp->type = FAMD64; 726 break; 727 default: 728 return 0; 729 } 730 731 if(ep->phentsize != sizeof(Phdr64)) { 732 werrstr("bad ELF header size"); 733 return 0; 734 } 735 phsz = sizeof(Phdr64)*ep->phnum; 736 ph = malloc(phsz); 737 if(!ph) 738 return 0; 739 seek(fd, ep->phoff, 0); 740 if(read(fd, ph, phsz) < 0) { 741 free(ph); 742 return 0; 743 } 744 hswal(ph, phsz/sizeof(uint32), swal); 745 746 shsz = sizeof(Shdr64)*ep->shnum; 747 sh = malloc(shsz); 748 if(sh) { 749 seek(fd, ep->shoff, 0); 750 if(read(fd, sh, shsz) < 0) { 751 free(sh); 752 sh = 0; 753 } else 754 hswal(sh, shsz/sizeof(uint32), swal); 755 } 756 757 /* find text, data and symbols and install them */ 758 it = id = is = -1; 759 for(i = 0; i < ep->phnum; i++) { 760 if(ph[i].type == LOAD 761 && (ph[i].flags & (R|X)) == (R|X) && it == -1) 762 it = i; 763 else if(ph[i].type == LOAD 764 && (ph[i].flags & (R|W)) == (R|W) && id == -1) 765 id = i; 766 else if(ph[i].type == NOPTYPE && is == -1) 767 is = i; 768 } 769 if(it == -1 || id == -1) { 770 /* 771 * The SPARC64 boot image is something of an ELF hack. 772 * Text+Data+BSS are represented by ph[0]. Symbols 773 * are represented by ph[1]: 774 * 775 * filesz, memsz, vaddr, paddr, off 776 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff 777 * ph[1] : symsz, lcsz, 0, 0, symoff 778 */ 779 if(ep->machine == SPARC64 && ep->phnum == 2) { 780 uint32 txtaddr, txtsz, dataddr, bsssz; 781 782 txtaddr = ph[0].vaddr | 0x80000000; 783 txtsz = ph[0].filesz - ph[0].paddr; 784 dataddr = txtaddr + txtsz; 785 bsssz = ph[0].memsz - ph[0].filesz; 786 settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset); 787 setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz); 788 setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz); 789 free(ph); 790 return 1; 791 } 792 793 werrstr("No TEXT or DATA sections"); 794 free(ph); 795 free(sh); 796 return 0; 797 } 798 799 settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); 800 pph = ph + id; 801 setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz); 802 if(is != -1) 803 setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz); 804 else if(sh != 0){ 805 char *buf; 806 uvlong symsize = 0; 807 uvlong symoff = 0; 808 uvlong pclnsz = 0; 809 uvlong pclnoff = 0; 810 811 /* load shstrtab names */ 812 buf = malloc(sh[ep->shstrndx].size); 813 if (buf == 0) 814 goto done; 815 memset(buf, 0, sh[ep->shstrndx].size); 816 seek(fd, sh[ep->shstrndx].offset, 0); 817 i = read(fd, buf, sh[ep->shstrndx].size); 818 USED(i); // shut up ubuntu gcc 819 820 for(i = 0; i < ep->shnum; i++) { 821 if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) { 822 symsize = sh[i].size; 823 symoff = sh[i].offset; 824 } 825 if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) { 826 pclnsz = sh[i].size; 827 pclnoff = sh[i].offset; 828 } 829 } 830 setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz); 831 free(buf); 832 } 833 done: 834 free(ph); 835 free(sh); 836 return 1; 837 } 838 839 static int 840 elfdotout(int fd, Fhdr *fp, ExecHdr *hp) 841 { 842 843 uint32 (*swal)(uint32); 844 ushort (*swab)(ushort); 845 Ehdr32 *ep; 846 Phdr32 *ph; 847 int i, it, id, is, phsz, shsz; 848 Shdr32 *sh; 849 850 /* bitswap the header according to the DATA format */ 851 ep = &hp->e.elfhdr32; 852 if(ep->ident[CLASS] != ELFCLASS32) { 853 return elf64dotout(fd, fp, hp); 854 } 855 if(ep->ident[DATA] == ELFDATA2LSB) { 856 swab = leswab; 857 swal = leswal; 858 } else if(ep->ident[DATA] == ELFDATA2MSB) { 859 swab = beswab; 860 swal = beswal; 861 } else { 862 werrstr("bad ELF encoding - not big or little endian"); 863 return 0; 864 } 865 866 ep->type = swab(ep->type); 867 ep->machine = swab(ep->machine); 868 ep->version = swal(ep->version); 869 ep->elfentry = swal(ep->elfentry); 870 ep->phoff = swal(ep->phoff); 871 ep->shoff = swal(ep->shoff); 872 ep->flags = swal(ep->flags); 873 ep->ehsize = swab(ep->ehsize); 874 ep->phentsize = swab(ep->phentsize); 875 ep->phnum = swab(ep->phnum); 876 ep->shentsize = swab(ep->shentsize); 877 ep->shnum = swab(ep->shnum); 878 ep->shstrndx = swab(ep->shstrndx); 879 if(ep->type != EXEC || ep->version != CURRENT) 880 return 0; 881 882 /* we could definitely support a lot more machines here */ 883 fp->magic = ELF_MAG; 884 fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; 885 switch(ep->machine) { 886 case I386: 887 mach = &mi386; 888 fp->type = FI386; 889 break; 890 case MIPS: 891 mach = &mmips; 892 fp->type = FMIPS; 893 break; 894 case SPARC64: 895 mach = &msparc64; 896 fp->type = FSPARC64; 897 break; 898 case POWER: 899 mach = &mpower; 900 fp->type = FPOWER; 901 break; 902 case ARM: 903 mach = &marm; 904 fp->type = FARM; 905 break; 906 default: 907 return 0; 908 } 909 910 if(ep->phentsize != sizeof(Phdr32)) { 911 werrstr("bad ELF header size"); 912 return 0; 913 } 914 phsz = sizeof(Phdr32)*ep->phnum; 915 ph = malloc(phsz); 916 if(!ph) 917 return 0; 918 seek(fd, ep->phoff, 0); 919 if(read(fd, ph, phsz) < 0) { 920 free(ph); 921 return 0; 922 } 923 hswal(ph, phsz/sizeof(uint32), swal); 924 925 shsz = sizeof(Shdr32)*ep->shnum; 926 sh = malloc(shsz); 927 if(sh) { 928 seek(fd, ep->shoff, 0); 929 if(read(fd, sh, shsz) < 0) { 930 free(sh); 931 sh = 0; 932 } else 933 hswal(sh, shsz/sizeof(uint32), swal); 934 } 935 936 /* find text, data and symbols and install them */ 937 it = id = is = -1; 938 for(i = 0; i < ep->phnum; i++) { 939 if(ph[i].type == LOAD 940 && (ph[i].flags & (R|X)) == (R|X) && it == -1) 941 it = i; 942 else if(ph[i].type == LOAD 943 && (ph[i].flags & (R|W)) == (R|W) && id == -1) 944 id = i; 945 else if(ph[i].type == NOPTYPE && is == -1) 946 is = i; 947 } 948 if(it == -1 || id == -1) { 949 /* 950 * The SPARC64 boot image is something of an ELF hack. 951 * Text+Data+BSS are represented by ph[0]. Symbols 952 * are represented by ph[1]: 953 * 954 * filesz, memsz, vaddr, paddr, off 955 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff 956 * ph[1] : symsz, lcsz, 0, 0, symoff 957 */ 958 if(ep->machine == SPARC64 && ep->phnum == 2) { 959 uint32 txtaddr, txtsz, dataddr, bsssz; 960 961 txtaddr = ph[0].vaddr | 0x80000000; 962 txtsz = ph[0].filesz - ph[0].paddr; 963 dataddr = txtaddr + txtsz; 964 bsssz = ph[0].memsz - ph[0].filesz; 965 settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset); 966 setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz); 967 setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz); 968 free(ph); 969 return 1; 970 } 971 972 werrstr("No TEXT or DATA sections"); 973 free(sh); 974 free(ph); 975 return 0; 976 } 977 978 settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); 979 setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz); 980 if(is != -1) 981 setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz); 982 else if(sh != 0){ 983 char *buf; 984 uvlong symsize = 0; 985 uvlong symoff = 0; 986 uvlong pclnsize = 0; 987 uvlong pclnoff = 0; 988 989 /* load shstrtab names */ 990 buf = malloc(sh[ep->shstrndx].size); 991 if (buf == 0) 992 goto done; 993 memset(buf, 0, sh[ep->shstrndx].size); 994 seek(fd, sh[ep->shstrndx].offset, 0); 995 i = read(fd, buf, sh[ep->shstrndx].size); 996 USED(i); // shut up ubuntu gcc 997 998 for(i = 0; i < ep->shnum; i++) { 999 if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) { 1000 symsize = sh[i].size; 1001 symoff = sh[i].offset; 1002 } 1003 if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) { 1004 pclnsize = sh[i].size; 1005 pclnoff = sh[i].offset; 1006 } 1007 } 1008 setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize); 1009 free(buf); 1010 } 1011 done: 1012 free(sh); 1013 free(ph); 1014 return 1; 1015 } 1016 1017 static int 1018 machdotout(int fd, Fhdr *fp, ExecHdr *hp) 1019 { 1020 uvlong (*swav)(uvlong); 1021 uint32 (*swal)(uint32); 1022 Machhdr *mp; 1023 MachCmd **cmd; 1024 MachSymSeg *symtab; 1025 MachSymSeg *pclntab; 1026 MachSeg64 *seg; 1027 MachSect64 *sect; 1028 MachSeg32 *seg32; 1029 MachSect32 *sect32; 1030 uvlong textsize, datasize, bsssize; 1031 uchar *cmdbuf; 1032 uchar *cmdp; 1033 int i, j, hdrsize; 1034 uint32 textva, textoff, datava, dataoff, symoff, symsize, pclnoff, pclnsize; 1035 1036 mp = &hp->e.machhdr; 1037 if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) { 1038 werrstr("bad MACH executable type %#ux", leswal(mp->filetype)); 1039 return 0; 1040 } 1041 1042 swal = leswal; 1043 swav = leswav; 1044 1045 mp->magic = swal(mp->magic); 1046 mp->cputype = swal(mp->cputype); 1047 mp->cpusubtype = swal(mp->cpusubtype); 1048 mp->filetype = swal(mp->filetype); 1049 mp->ncmds = swal(mp->ncmds); 1050 mp->sizeofcmds = swal(mp->sizeofcmds); 1051 mp->flags = swal(mp->flags); 1052 mp->reserved = swal(mp->reserved); 1053 1054 switch(mp->magic) { 1055 case 0xFEEDFACE: // 32-bit mach 1056 if (mp->cputype != MACH_CPU_TYPE_X86) { 1057 werrstr("bad MACH cpu type - not 386"); 1058 return 0; 1059 } 1060 if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) { 1061 werrstr("bad MACH cpu subtype - not 386"); 1062 return 0; 1063 } 1064 if (mp->filetype != MACH_EXECUTABLE_TYPE) { 1065 werrstr("bad MACH executable type"); 1066 return 0; 1067 } 1068 mach = &mi386; 1069 fp->type = FI386; 1070 hdrsize = 28; 1071 break; 1072 1073 case 0xFEEDFACF: // 64-bit mach 1074 if (mp->cputype != MACH_CPU_TYPE_X86_64) { 1075 werrstr("bad MACH cpu type - not amd64"); 1076 return 0; 1077 } 1078 1079 if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) { 1080 werrstr("bad MACH cpu subtype - not amd64"); 1081 return 0; 1082 } 1083 mach = &mamd64; 1084 fp->type = FAMD64; 1085 hdrsize = 32; 1086 break; 1087 1088 default: 1089 werrstr("not mach %#ux", mp->magic); 1090 return 0; 1091 } 1092 1093 cmdbuf = malloc(mp->sizeofcmds); 1094 if(!cmdbuf) { 1095 werrstr("out of memory"); 1096 return 0; 1097 } 1098 seek(fd, hdrsize, 0); 1099 if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) { 1100 free(cmdbuf); 1101 return 0; 1102 } 1103 cmd = malloc(mp->ncmds * sizeof(MachCmd*)); 1104 if(!cmd) { 1105 free(cmdbuf); 1106 werrstr("out of memory"); 1107 return 0; 1108 } 1109 cmdp = cmdbuf; 1110 textva = 0; 1111 textoff = 0; 1112 dataoff = 0; 1113 datava = 0; 1114 symtab = 0; 1115 pclntab = 0; 1116 textsize = 0; 1117 datasize = 0; 1118 bsssize = 0; 1119 symoff = 0; 1120 symsize = 0; 1121 pclnoff = 0; 1122 pclnsize = 0; 1123 for (i = 0; i < mp->ncmds; i++) { 1124 MachCmd *c; 1125 1126 cmd[i] = (MachCmd*)cmdp; 1127 c = cmd[i]; 1128 c->type = swal(c->type); 1129 c->size = swal(c->size); 1130 switch(c->type) { 1131 case MACH_SEGMENT_32: 1132 if(mp->magic != 0xFEEDFACE) { 1133 werrstr("segment 32 in mach 64"); 1134 goto bad; 1135 } 1136 seg32 = (MachSeg32*)c; 1137 seg32->vmaddr = swav(seg32->vmaddr); 1138 seg32->vmsize = swav(seg32->vmsize); 1139 seg32->fileoff = swav(seg32->fileoff); 1140 seg32->filesize = swav(seg32->filesize); 1141 seg32->maxprot = swal(seg32->maxprot); 1142 seg32->initprot = swal(seg32->initprot); 1143 seg32->nsects = swal(seg32->nsects); 1144 seg32->flags = swal(seg32->flags); 1145 if (strcmp(seg32->segname, "__TEXT") == 0) { 1146 textva = seg32->vmaddr; 1147 textoff = seg32->fileoff; 1148 textsize = seg32->vmsize; 1149 sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); 1150 for(j = 0; j < seg32->nsects; j++, sect32++) { 1151 if (strcmp(sect32->sectname, "__gosymtab") == 0) { 1152 symoff = swal(sect32->offset); 1153 symsize = swal(sect32->size); 1154 } 1155 if (strcmp(sect32->sectname, "__gopclntab") == 0) { 1156 pclnoff = swal(sect32->offset); 1157 pclnsize = swal(sect32->size); 1158 } 1159 } 1160 } 1161 if (strcmp(seg32->segname, "__DATA") == 0) { 1162 datava = seg32->vmaddr; 1163 dataoff = seg32->fileoff; 1164 datasize = seg32->filesize; 1165 bsssize = seg32->vmsize - seg32->filesize; 1166 } 1167 break; 1168 1169 case MACH_SEGMENT_64: 1170 if(mp->magic != 0xFEEDFACF) { 1171 werrstr("segment 32 in mach 64"); 1172 goto bad; 1173 } 1174 seg = (MachSeg64*)c; 1175 seg->vmaddr = swav(seg->vmaddr); 1176 seg->vmsize = swav(seg->vmsize); 1177 seg->fileoff = swav(seg->fileoff); 1178 seg->filesize = swav(seg->filesize); 1179 seg->maxprot = swal(seg->maxprot); 1180 seg->initprot = swal(seg->initprot); 1181 seg->nsects = swal(seg->nsects); 1182 seg->flags = swal(seg->flags); 1183 if (strcmp(seg->segname, "__TEXT") == 0) { 1184 textva = seg->vmaddr; 1185 textoff = seg->fileoff; 1186 textsize = seg->vmsize; 1187 sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); 1188 for(j = 0; j < seg->nsects; j++, sect++) { 1189 if (strcmp(sect->sectname, "__gosymtab") == 0) { 1190 symoff = swal(sect->offset); 1191 symsize = swal(sect->size); 1192 } 1193 if (strcmp(sect->sectname, "__gopclntab") == 0) { 1194 pclnoff = swal(sect->offset); 1195 pclnsize = swal(sect->size); 1196 } 1197 } 1198 } 1199 if (strcmp(seg->segname, "__DATA") == 0) { 1200 datava = seg->vmaddr; 1201 dataoff = seg->fileoff; 1202 datasize = seg->filesize; 1203 bsssize = seg->vmsize - seg->filesize; 1204 } 1205 break; 1206 case MACH_UNIXTHREAD: 1207 break; 1208 case MACH_SYMSEG: 1209 if (symtab == 0) { 1210 symtab = (MachSymSeg*)c; 1211 symoff = swal(symtab->fileoff); 1212 symsize = swal(symtab->filesize); 1213 } else if (pclntab == 0) { 1214 pclntab = (MachSymSeg*)c; 1215 pclnoff = swal(pclntab->fileoff); 1216 pclnsize = swal(pclntab->filesize); 1217 } 1218 break; 1219 } 1220 cmdp += c->size; 1221 } 1222 if (textva == 0 || datava == 0) { 1223 free(cmd); 1224 free(cmdbuf); 1225 return 0; 1226 } 1227 /* compute entry by taking address after header - weird - BUG? */ 1228 settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff); 1229 setdata(fp, datava, datasize, dataoff, bsssize); 1230 if(symoff > 0) 1231 setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize); 1232 free(cmd); 1233 free(cmdbuf); 1234 return 1; 1235 bad: 1236 free(cmd); 1237 free(cmdbuf); 1238 return 0; 1239 } 1240 1241 /* 1242 * (Free|Net)BSD ARM header. 1243 */ 1244 static int 1245 armdotout(int fd, Fhdr *fp, ExecHdr *hp) 1246 { 1247 uvlong kbase; 1248 1249 USED(fd); 1250 settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec)); 1251 setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss); 1252 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz); 1253 1254 kbase = 0xF0000000; 1255 if ((fp->entry & kbase) == kbase) { /* Boot image */ 1256 fp->txtaddr = kbase+sizeof(Exec); 1257 fp->name = "ARM *BSD boot image"; 1258 fp->hdrsz = 0; /* header stripped */ 1259 fp->dataddr = kbase+fp->txtsz; 1260 } 1261 return 1; 1262 } 1263 1264 /* 1265 * Structures needed to parse PE image. 1266 */ 1267 typedef struct { 1268 uint16 Machine; 1269 uint16 NumberOfSections; 1270 uint32 TimeDateStamp; 1271 uint32 PointerToSymbolTable; 1272 uint32 NumberOfSymbols; 1273 uint16 SizeOfOptionalHeader; 1274 uint16 Characteristics; 1275 } IMAGE_FILE_HEADER; 1276 1277 typedef struct { 1278 uint8 Name[8]; 1279 uint32 VirtualSize; 1280 uint32 VirtualAddress; 1281 uint32 SizeOfRawData; 1282 uint32 PointerToRawData; 1283 uint32 PointerToRelocations; 1284 uint32 PointerToLineNumbers; 1285 uint16 NumberOfRelocations; 1286 uint16 NumberOfLineNumbers; 1287 uint32 Characteristics; 1288 } IMAGE_SECTION_HEADER; 1289 1290 typedef struct { 1291 uint32 VirtualAddress; 1292 uint32 Size; 1293 } IMAGE_DATA_DIRECTORY; 1294 1295 typedef struct { 1296 uint16 Magic; 1297 uint8 MajorLinkerVersion; 1298 uint8 MinorLinkerVersion; 1299 uint32 SizeOfCode; 1300 uint32 SizeOfInitializedData; 1301 uint32 SizeOfUninitializedData; 1302 uint32 AddressOfEntryPoint; 1303 uint32 BaseOfCode; 1304 uint32 BaseOfData; 1305 uint32 ImageBase; 1306 uint32 SectionAlignment; 1307 uint32 FileAlignment; 1308 uint16 MajorOperatingSystemVersion; 1309 uint16 MinorOperatingSystemVersion; 1310 uint16 MajorImageVersion; 1311 uint16 MinorImageVersion; 1312 uint16 MajorSubsystemVersion; 1313 uint16 MinorSubsystemVersion; 1314 uint32 Win32VersionValue; 1315 uint32 SizeOfImage; 1316 uint32 SizeOfHeaders; 1317 uint32 CheckSum; 1318 uint16 Subsystem; 1319 uint16 DllCharacteristics; 1320 uint32 SizeOfStackReserve; 1321 uint32 SizeOfStackCommit; 1322 uint32 SizeOfHeapReserve; 1323 uint32 SizeOfHeapCommit; 1324 uint32 LoaderFlags; 1325 uint32 NumberOfRvaAndSizes; 1326 IMAGE_DATA_DIRECTORY DataDirectory[16]; 1327 } IMAGE_OPTIONAL_HEADER; 1328 1329 typedef struct { 1330 uint16 Magic; 1331 uint8 MajorLinkerVersion; 1332 uint8 MinorLinkerVersion; 1333 uint32 SizeOfCode; 1334 uint32 SizeOfInitializedData; 1335 uint32 SizeOfUninitializedData; 1336 uint32 AddressOfEntryPoint; 1337 uint32 BaseOfCode; 1338 uint64 ImageBase; 1339 uint32 SectionAlignment; 1340 uint32 FileAlignment; 1341 uint16 MajorOperatingSystemVersion; 1342 uint16 MinorOperatingSystemVersion; 1343 uint16 MajorImageVersion; 1344 uint16 MinorImageVersion; 1345 uint16 MajorSubsystemVersion; 1346 uint16 MinorSubsystemVersion; 1347 uint32 Win32VersionValue; 1348 uint32 SizeOfImage; 1349 uint32 SizeOfHeaders; 1350 uint32 CheckSum; 1351 uint16 Subsystem; 1352 uint16 DllCharacteristics; 1353 uint64 SizeOfStackReserve; 1354 uint64 SizeOfStackCommit; 1355 uint64 SizeOfHeapReserve; 1356 uint64 SizeOfHeapCommit; 1357 uint32 LoaderFlags; 1358 uint32 NumberOfRvaAndSizes; 1359 IMAGE_DATA_DIRECTORY DataDirectory[16]; 1360 } PE64_IMAGE_OPTIONAL_HEADER; 1361 1362 static int 1363 match8(void *buf, char *cmp) 1364 { 1365 return strncmp((char*)buf, cmp, 8) == 0; 1366 } 1367 1368 /* 1369 * Read from Windows PE/COFF .exe file image. 1370 */ 1371 static int 1372 pedotout(int fd, Fhdr *fp, ExecHdr *hp) 1373 { 1374 uint32 start, magic; 1375 uint32 symtab, esymtab, pclntab, epclntab; 1376 IMAGE_FILE_HEADER fh; 1377 IMAGE_SECTION_HEADER sh; 1378 IMAGE_OPTIONAL_HEADER oh; 1379 PE64_IMAGE_OPTIONAL_HEADER oh64; 1380 uint8 sym[18]; 1381 uint32 *valp, ib, entry; 1382 int i, ohoffset; 1383 1384 USED(hp); 1385 seek(fd, 0x3c, 0); 1386 if (readn(fd, &start, sizeof(start)) != sizeof(start)) { 1387 werrstr("crippled PE MSDOS header"); 1388 return 0; 1389 } 1390 start = leswal(start); 1391 1392 seek(fd, start, 0); 1393 if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) { 1394 werrstr("no PE magic number found"); 1395 return 0; 1396 } 1397 if (beswal(magic) != 0x50450000) { /* "PE\0\0" */ 1398 werrstr("incorrect PE magic number"); 1399 return 0; 1400 } 1401 1402 if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) { 1403 werrstr("crippled PE File Header"); 1404 return 0; 1405 } 1406 if (fh.PointerToSymbolTable == 0) { 1407 werrstr("zero pointer to COFF symbol table"); 1408 return 0; 1409 } 1410 1411 ohoffset = seek(fd, 0, 1); 1412 if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) { 1413 werrstr("crippled PE Optional Header"); 1414 return 0; 1415 } 1416 1417 switch(oh.Magic) { 1418 case 0x10b: // PE32 1419 fp->type = FI386; 1420 ib = leswal(oh.ImageBase); 1421 entry = leswal(oh.AddressOfEntryPoint); 1422 break; 1423 case 0x20b: // PE32+ 1424 fp->type = FAMD64; 1425 seek(fd, ohoffset, 0); 1426 if (readn(fd, &oh64, sizeof(oh64)) != sizeof(oh64)) { 1427 werrstr("crippled PE32+ Optional Header"); 1428 return 0; 1429 } 1430 ib = leswal(oh64.ImageBase); 1431 entry = leswal(oh64.AddressOfEntryPoint); 1432 break; 1433 default: 1434 werrstr("invalid PE Optional Header magic number"); 1435 return 0; 1436 } 1437 1438 fp->txtaddr = 0; 1439 fp->dataddr = 0; 1440 for (i=0; i<leswab(fh.NumberOfSections); i++) { 1441 if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) { 1442 werrstr("could not read Section Header %d", i+1); 1443 return 0; 1444 } 1445 if (match8(sh.Name, ".text")) 1446 settext(fp, ib+entry, ib+leswal(sh.VirtualAddress), leswal(sh.VirtualSize), leswal(sh.PointerToRawData)); 1447 if (match8(sh.Name, ".data")) 1448 setdata(fp, ib+leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData)); 1449 } 1450 if (fp->txtaddr==0 || fp->dataddr==0) { 1451 werrstr("no .text or .data"); 1452 return 0; 1453 } 1454 1455 seek(fd, leswal(fh.PointerToSymbolTable), 0); 1456 symtab = esymtab = pclntab = epclntab = 0; 1457 for (i=0; i<leswal(fh.NumberOfSymbols); i++) { 1458 if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) { 1459 werrstr("crippled COFF symbol %d", i); 1460 return 0; 1461 } 1462 valp = (uint32 *)&sym[8]; 1463 if (match8(sym, "symtab")) 1464 symtab = leswal(*valp); 1465 if (match8(sym, "esymtab")) 1466 esymtab = leswal(*valp); 1467 if (match8(sym, "pclntab")) 1468 pclntab = leswal(*valp); 1469 if (match8(sym, "epclntab")) 1470 epclntab = leswal(*valp); 1471 } 1472 if (symtab==0 || esymtab==0 || pclntab==0 || epclntab==0) { 1473 werrstr("no symtab or esymtab or pclntab or epclntab in COFF symbol table"); 1474 return 0; 1475 } 1476 setsym(fp, symtab, esymtab-symtab, 0, 0, pclntab, epclntab-pclntab); 1477 1478 return 1; 1479 } 1480 1481 static void 1482 settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off) 1483 { 1484 fp->txtaddr = a; 1485 fp->entry = e; 1486 fp->txtsz = s; 1487 fp->txtoff = off; 1488 } 1489 1490 static void 1491 setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss) 1492 { 1493 fp->dataddr = a; 1494 fp->datsz = s; 1495 fp->datoff = off; 1496 fp->bsssz = bss; 1497 } 1498 1499 static void 1500 setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz) 1501 { 1502 fp->symoff = symoff; 1503 fp->symsz = symsz; 1504 1505 if(sppcoff == 0) 1506 sppcoff = symoff+symsz; 1507 fp->sppcoff = symoff; 1508 fp->sppcsz = sppcsz; 1509 1510 if(lnpcoff == 0) 1511 lnpcoff = sppcoff + sppcsz; 1512 fp->lnpcoff = lnpcoff; 1513 fp->lnpcsz = lnpcsz; 1514 } 1515 1516 static uvlong 1517 _round(uvlong a, uint32 b) 1518 { 1519 uvlong w; 1520 1521 w = (a/b)*b; 1522 if (a!=w) 1523 w += b; 1524 return(w); 1525 }