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