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