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