1 #define EXTERN 2 #include "l.h" 3 #include <ar.h> 4 5 #ifndef DEFAULT 6 #define DEFAULT '9' 7 #endif 8 9 char *noname = "<none>"; 10 char symname[] = SYMDEF; 11 char thechar = '8'; 12 char *thestring = "386"; 13 14 char** libdir; 15 int nlibdir = 0; 16 static int maxlibdir = 0; 17 18 /* 19 * -H0 -T0x40004C -D0x10000000 is garbage unix 20 * -H1 -T0xd0 -R4 is unix coff 21 * -H2 -T4128 -R4096 is plan9 format 22 * -H3 -Tx -Rx is MS-DOS .COM 23 * -H4 -Tx -Rx is fake MS-DOS .EXE 24 * -H5 -T0x80100020 -R4096 is ELF 25 */ 26 27 void 28 usage(void) 29 { 30 diag("usage: %s [-options] objects", argv0); 31 errorexit(); 32 } 33 34 static int 35 isobjfile(char *f) 36 { 37 int n, v; 38 Biobuf *b; 39 char buf1[5], buf2[SARMAG]; 40 41 b = Bopen(f, OREAD); 42 if(b == nil) 43 return 0; 44 n = Bread(b, buf1, 5); 45 if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<')) 46 v = 1; /* good enough for our purposes */ 47 else{ 48 Bseek(b, 0, 0); 49 n = Bread(b, buf2, SARMAG); 50 v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0; 51 } 52 Bterm(b); 53 return v; 54 } 55 56 void 57 main(int argc, char *argv[]) 58 { 59 int i, c; 60 char *a; 61 char name[LIBNAMELEN]; 62 63 Binit(&bso, 1, OWRITE); 64 cout = -1; 65 listinit(); 66 memset(debug, 0, sizeof(debug)); 67 nerrors = 0; 68 outfile = "8.out"; 69 HEADTYPE = -1; 70 INITTEXT = -1; 71 INITTEXTP = -1; 72 INITDAT = -1; 73 INITRND = -1; 74 INITENTRY = 0; 75 ARGBEGIN { 76 default: 77 c = ARGC(); 78 if(c >= 0 && c < sizeof(debug)) 79 debug[c]++; 80 break; 81 case 'o': /* output to (next arg) */ 82 outfile = ARGF(); 83 break; 84 case 'E': 85 a = ARGF(); 86 if(a) 87 INITENTRY = a; 88 break; 89 case 'H': 90 a = ARGF(); 91 if(a) 92 HEADTYPE = atolwhex(a); 93 break; 94 case 'L': 95 addlibpath(EARGF(usage())); 96 break; 97 case 'T': 98 a = ARGF(); 99 if(a) 100 INITTEXT = atolwhex(a); 101 break; 102 case 'P': 103 a = ARGF(); 104 if(a) 105 INITTEXTP = atolwhex(a); 106 break; 107 case 'D': 108 a = ARGF(); 109 if(a) 110 INITDAT = atolwhex(a); 111 break; 112 case 'R': 113 a = ARGF(); 114 if(a) 115 INITRND = atolwhex(a); 116 break; 117 case 'x': /* produce export table */ 118 doexp = 1; 119 if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])){ 120 a = ARGF(); 121 if(strcmp(a, "*") == 0) 122 allexport = 1; 123 else 124 readundefs(a, SEXPORT); 125 } 126 break; 127 case 'u': /* produce dynamically loadable module */ 128 dlm = 1; 129 debug['l']++; 130 if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) 131 readundefs(ARGF(), SIMPORT); 132 break; 133 } ARGEND 134 USED(argc); 135 if(*argv == 0) 136 usage(); 137 if(!debug['9'] && !debug['U'] && !debug['B']) 138 debug[DEFAULT] = 1; 139 a = getenv("ccroot"); 140 if(a != nil && *a != '\0') { 141 if(!fileexists(a)) { 142 diag("nonexistent $ccroot: %s", a); 143 errorexit(); 144 } 145 }else 146 a = ""; 147 snprint(name, sizeof(name), "%s/%s/lib", a, thestring); 148 addlibpath(name); 149 if(HEADTYPE == -1) { 150 if(debug['U']) 151 HEADTYPE = 1; 152 if(debug['B']) 153 HEADTYPE = 2; 154 if(debug['9']) 155 HEADTYPE = 2; 156 } 157 switch(HEADTYPE) { 158 default: 159 diag("unknown -H option"); 160 errorexit(); 161 162 case 0: /* this is garbage */ 163 HEADR = 20L+56L; 164 if(INITTEXT == -1) 165 INITTEXT = 0x40004CL; 166 if(INITDAT == -1) 167 INITDAT = 0x10000000L; 168 if(INITRND == -1) 169 INITRND = 0; 170 break; 171 case 1: /* is unix coff */ 172 HEADR = 0xd0L; 173 if(INITTEXT == -1) 174 INITTEXT = 0xd0; 175 if(INITDAT == -1) 176 INITDAT = 0x400000; 177 if(INITRND == -1) 178 INITRND = 0; 179 break; 180 case 2: /* plan 9 */ 181 HEADR = 32L; 182 if(INITTEXT == -1) 183 INITTEXT = 4096+32; 184 if(INITDAT == -1) 185 INITDAT = 0; 186 if(INITRND == -1) 187 INITRND = 4096; 188 break; 189 case 3: /* MS-DOS .COM */ 190 HEADR = 0; 191 if(INITTEXT == -1) 192 INITTEXT = 0x0100; 193 if(INITDAT == -1) 194 INITDAT = 0; 195 if(INITRND == -1) 196 INITRND = 4; 197 break; 198 case 4: /* fake MS-DOS .EXE */ 199 HEADR = 0x200; 200 if(INITTEXT == -1) 201 INITTEXT = 0x0100; 202 if(INITDAT == -1) 203 INITDAT = 0; 204 if(INITRND == -1) 205 INITRND = 4; 206 HEADR += (INITTEXT & 0xFFFF); 207 if(debug['v']) 208 Bprint(&bso, "HEADR = 0x%ld\n", HEADR); 209 break; 210 case 5: /* elf executable */ 211 HEADR = rnd(Ehdr32sz+3*Phdr32sz, 16); 212 if(INITTEXT == -1) 213 INITTEXT = 0x80100020L; 214 if(INITDAT == -1) 215 INITDAT = 0; 216 if(INITRND == -1) 217 INITRND = 4096; 218 break; 219 } 220 if (INITTEXTP == -1) 221 INITTEXTP = INITTEXT; 222 if(INITDAT != 0 && INITRND != 0) 223 print("warning: -D0x%lux is ignored because of -R0x%lux\n", 224 INITDAT, INITRND); 225 if(debug['v']) 226 Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n", 227 HEADTYPE, INITTEXT, INITDAT, INITRND); 228 Bflush(&bso); 229 for(i=1; optab[i].as; i++) 230 if(i != optab[i].as) { 231 diag("phase error in optab: %d", i); 232 errorexit(); 233 } 234 235 for(i=0; i<Ymax; i++) 236 ycover[i*Ymax + i] = 1; 237 238 ycover[Yi0*Ymax + Yi8] = 1; 239 ycover[Yi1*Ymax + Yi8] = 1; 240 241 ycover[Yi0*Ymax + Yi32] = 1; 242 ycover[Yi1*Ymax + Yi32] = 1; 243 ycover[Yi8*Ymax + Yi32] = 1; 244 245 ycover[Yal*Ymax + Yrb] = 1; 246 ycover[Ycl*Ymax + Yrb] = 1; 247 ycover[Yax*Ymax + Yrb] = 1; 248 ycover[Ycx*Ymax + Yrb] = 1; 249 ycover[Yrx*Ymax + Yrb] = 1; 250 251 ycover[Yax*Ymax + Yrx] = 1; 252 ycover[Ycx*Ymax + Yrx] = 1; 253 254 ycover[Yax*Ymax + Yrl] = 1; 255 ycover[Ycx*Ymax + Yrl] = 1; 256 ycover[Yrx*Ymax + Yrl] = 1; 257 258 ycover[Yf0*Ymax + Yrf] = 1; 259 260 ycover[Yal*Ymax + Ymb] = 1; 261 ycover[Ycl*Ymax + Ymb] = 1; 262 ycover[Yax*Ymax + Ymb] = 1; 263 ycover[Ycx*Ymax + Ymb] = 1; 264 ycover[Yrx*Ymax + Ymb] = 1; 265 ycover[Yrb*Ymax + Ymb] = 1; 266 ycover[Ym*Ymax + Ymb] = 1; 267 268 ycover[Yax*Ymax + Yml] = 1; 269 ycover[Ycx*Ymax + Yml] = 1; 270 ycover[Yrx*Ymax + Yml] = 1; 271 ycover[Yrl*Ymax + Yml] = 1; 272 ycover[Ym*Ymax + Yml] = 1; 273 274 for(i=0; i<D_NONE; i++) { 275 reg[i] = -1; 276 if(i >= D_AL && i <= D_BH) 277 reg[i] = (i-D_AL) & 7; 278 if(i >= D_AX && i <= D_DI) 279 reg[i] = (i-D_AX) & 7; 280 if(i >= D_F0 && i <= D_F0+7) 281 reg[i] = (i-D_F0) & 7; 282 } 283 284 zprg.link = P; 285 zprg.pcond = P; 286 zprg.back = 2; 287 zprg.as = AGOK; 288 zprg.from.type = D_NONE; 289 zprg.from.index = D_NONE; 290 zprg.from.scale = 1; 291 zprg.to = zprg.from; 292 293 pcstr = "%.6lux "; 294 nuxiinit(); 295 histgen = 0; 296 textp = P; 297 datap = P; 298 edatap = P; 299 pc = 0; 300 dtype = 4; 301 cout = create(outfile, 1, 0775); 302 if(cout < 0) { 303 diag("cannot create %s: %r", outfile); 304 errorexit(); 305 } 306 version = 0; 307 cbp = buf.cbuf; 308 cbc = sizeof(buf.cbuf); 309 firstp = prg(); 310 lastp = firstp; 311 312 if(INITENTRY == 0) { 313 INITENTRY = "_main"; 314 if(debug['p']) 315 INITENTRY = "_mainp"; 316 if(!debug['l']) 317 lookup(INITENTRY, 0)->type = SXREF; 318 } else if(!(*INITENTRY >= '0' && *INITENTRY <= '9')) 319 lookup(INITENTRY, 0)->type = SXREF; 320 321 while(*argv) 322 objfile(*argv++); 323 if(!debug['l']) 324 loadlib(); 325 firstp = firstp->link; 326 if(firstp == P) 327 errorexit(); 328 if(doexp || dlm){ 329 EXPTAB = "_exporttab"; 330 zerosig(EXPTAB); 331 zerosig("etext"); 332 zerosig("edata"); 333 zerosig("end"); 334 if(dlm){ 335 import(); 336 HEADTYPE = 2; 337 INITTEXT = INITDAT = 0; 338 INITRND = 8; 339 INITENTRY = EXPTAB; 340 } 341 export(); 342 } 343 patch(); 344 follow(); 345 dodata(); 346 dostkoff(); 347 if(debug['p']) 348 if(debug['1']) 349 doprof1(); 350 else 351 doprof2(); 352 span(); 353 doinit(); 354 asmb(); 355 undef(); 356 if(debug['v']) { 357 Bprint(&bso, "%5.2f cpu time\n", cputime()); 358 Bprint(&bso, "%ld symbols\n", nsymbol); 359 Bprint(&bso, "%ld memory used\n", thunk); 360 Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); 361 Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); 362 } 363 Bflush(&bso); 364 365 errorexit(); 366 } 367 368 void 369 addlibpath(char *arg) 370 { 371 char **p; 372 373 if(nlibdir >= maxlibdir) { 374 if(maxlibdir == 0) 375 maxlibdir = 8; 376 else 377 maxlibdir *= 2; 378 p = malloc(maxlibdir*sizeof(*p)); 379 if(p == nil) { 380 diag("out of memory"); 381 errorexit(); 382 } 383 memmove(p, libdir, nlibdir*sizeof(*p)); 384 free(libdir); 385 libdir = p; 386 } 387 libdir[nlibdir++] = strdup(arg); 388 } 389 390 char* 391 findlib(char *file) 392 { 393 int i; 394 char name[LIBNAMELEN]; 395 396 for(i = 0; i < nlibdir; i++) { 397 snprint(name, sizeof(name), "%s/%s", libdir[i], file); 398 if(fileexists(name)) 399 return libdir[i]; 400 } 401 return nil; 402 } 403 404 void 405 loadlib(void) 406 { 407 int i; 408 long h; 409 Sym *s; 410 411 loop: 412 xrefresolv = 0; 413 for(i=0; i<libraryp; i++) { 414 if(debug['v']) 415 Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]); 416 objfile(library[i]); 417 } 418 if(xrefresolv) 419 for(h=0; h<nelem(hash); h++) 420 for(s = hash[h]; s != S; s = s->link) 421 if(s->type == SXREF) 422 goto loop; 423 } 424 425 void 426 errorexit(void) 427 { 428 429 if(nerrors) { 430 if(cout >= 0) 431 remove(outfile); 432 exits("error"); 433 } 434 exits(0); 435 } 436 437 void 438 objfile(char *file) 439 { 440 long off, esym, cnt, l; 441 int f, work; 442 Sym *s; 443 char magbuf[SARMAG]; 444 char name[LIBNAMELEN], pname[LIBNAMELEN]; 445 struct ar_hdr arhdr; 446 char *e, *start, *stop; 447 448 if(debug['v']) 449 Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); 450 Bflush(&bso); 451 if(file[0] == '-' && file[1] == 'l') { 452 snprint(pname, sizeof(pname), "lib%s.a", file+2); 453 e = findlib(pname); 454 if(e == nil) { 455 diag("cannot find library: %s", file); 456 errorexit(); 457 } 458 snprint(name, sizeof(name), "%s/%s", e, pname); 459 file = name; 460 } 461 f = open(file, 0); 462 if(f < 0) { 463 diag("cannot open %s: %r", file); 464 errorexit(); 465 } 466 l = read(f, magbuf, SARMAG); 467 if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ 468 /* load it as a regular file */ 469 l = seek(f, 0L, 2); 470 seek(f, 0L, 0); 471 ldobj(f, l, file); 472 close(f); 473 return; 474 } 475 476 l = read(f, &arhdr, SAR_HDR); 477 if(l != SAR_HDR) { 478 diag("%s: short read on archive file symbol header", file); 479 goto out; 480 } 481 if(strncmp(arhdr.name, symname, strlen(symname))) { 482 diag("%s: first entry not symbol header", file); 483 goto out; 484 } 485 486 esym = SARMAG + SAR_HDR + atolwhex(arhdr.size); 487 off = SARMAG + SAR_HDR; 488 489 /* 490 * just bang the whole symbol file into memory 491 */ 492 seek(f, off, 0); 493 cnt = esym - off; 494 start = malloc(cnt + 10); 495 cnt = read(f, start, cnt); 496 if(cnt <= 0){ 497 close(f); 498 return; 499 } 500 stop = &start[cnt]; 501 memset(stop, 0, 10); 502 503 work = 1; 504 while(work) { 505 if(debug['v']) 506 Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file); 507 Bflush(&bso); 508 work = 0; 509 for(e = start; e < stop; e = strchr(e+5, 0) + 1) { 510 s = lookup(e+5, 0); 511 if(s->type != SXREF) 512 continue; 513 sprint(pname, "%s(%s)", file, s->name); 514 if(debug['v']) 515 Bprint(&bso, "%5.2f library: %s\n", cputime(), pname); 516 Bflush(&bso); 517 l = e[1] & 0xff; 518 l |= (e[2] & 0xff) << 8; 519 l |= (e[3] & 0xff) << 16; 520 l |= (e[4] & 0xff) << 24; 521 seek(f, l, 0); 522 /* need readn to read the dumps (at least) */ 523 l = readn(f, &arhdr, SAR_HDR); 524 if(l != SAR_HDR) 525 goto bad; 526 if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag))) 527 goto bad; 528 l = atolwhex(arhdr.size); 529 ldobj(f, l, pname); 530 if(s->type == SXREF) { 531 diag("%s: failed to load: %s", file, s->name); 532 errorexit(); 533 } 534 work = 1; 535 xrefresolv = 1; 536 } 537 } 538 return; 539 540 bad: 541 diag("%s: bad or out of date archive", file); 542 out: 543 close(f); 544 } 545 546 int 547 zaddr(uchar *p, Adr *a, Sym *h[]) 548 { 549 int c, t, i; 550 int l; 551 Sym *s; 552 Auto *u; 553 554 t = p[0]; 555 556 c = 1; 557 if(t & T_INDEX) { 558 a->index = p[c]; 559 a->scale = p[c+1]; 560 c += 2; 561 } else { 562 a->index = D_NONE; 563 a->scale = 0; 564 } 565 a->offset = 0; 566 if(t & T_OFFSET) { 567 a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); 568 c += 4; 569 } 570 a->sym = S; 571 if(t & T_SYM) { 572 a->sym = h[p[c]]; 573 c++; 574 } 575 a->type = D_NONE; 576 if(t & T_FCONST) { 577 a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); 578 a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24); 579 c += 8; 580 a->type = D_FCONST; 581 } else 582 if(t & T_SCONST) { 583 for(i=0; i<NSNAME; i++) 584 a->scon[i] = p[c+i]; 585 c += NSNAME; 586 a->type = D_SCONST; 587 } 588 if(t & T_TYPE) { 589 a->type = p[c]; 590 c++; 591 } 592 s = a->sym; 593 if(s == S) 594 return c; 595 596 t = a->type; 597 if(t != D_AUTO && t != D_PARAM) 598 return c; 599 l = a->offset; 600 for(u=curauto; u; u=u->link) { 601 if(u->asym == s) 602 if(u->type == t) { 603 if(u->aoffset > l) 604 u->aoffset = l; 605 return c; 606 } 607 } 608 609 while(nhunk < sizeof(Auto)) 610 gethunk(); 611 u = (Auto*)hunk; 612 nhunk -= sizeof(Auto); 613 hunk += sizeof(Auto); 614 615 u->link = curauto; 616 curauto = u; 617 u->asym = s; 618 u->aoffset = l; 619 u->type = t; 620 return c; 621 } 622 623 void 624 addlib(char *obj) 625 { 626 char fn1[LIBNAMELEN], fn2[LIBNAMELEN], comp[LIBNAMELEN], *p, *name; 627 int i, search; 628 629 if(histfrogp <= 0) 630 return; 631 632 name = fn1; 633 search = 0; 634 if(histfrog[0]->name[1] == '/') { 635 sprint(name, ""); 636 i = 1; 637 } else if(histfrog[0]->name[1] == '.') { 638 sprint(name, "."); 639 i = 0; 640 } else { 641 sprint(name, ""); 642 i = 0; 643 search = 1; 644 } 645 646 for(; i<histfrogp; i++) { 647 snprint(comp, sizeof comp, histfrog[i]->name+1); 648 for(;;) { 649 p = strstr(comp, "$O"); 650 if(p == 0) 651 break; 652 memmove(p+1, p+2, strlen(p+2)+1); 653 p[0] = thechar; 654 } 655 for(;;) { 656 p = strstr(comp, "$M"); 657 if(p == 0) 658 break; 659 if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { 660 diag("library component too long"); 661 return; 662 } 663 memmove(p+strlen(thestring), p+2, strlen(p+2)+1); 664 memmove(p, thestring, strlen(thestring)); 665 } 666 if(strlen(fn1) + strlen(comp) + 3 >= sizeof(fn1)) { 667 diag("library component too long"); 668 return; 669 } 670 if(i > 0 || !search) 671 strcat(fn1, "/"); 672 strcat(fn1, comp); 673 } 674 675 cleanname(name); 676 677 if(search){ 678 p = findlib(name); 679 if(p != nil){ 680 snprint(fn2, sizeof(fn2), "%s/%s", p, name); 681 name = fn2; 682 } 683 } 684 685 for(i=0; i<libraryp; i++) 686 if(strcmp(name, library[i]) == 0) 687 return; 688 if(libraryp == nelem(library)){ 689 diag("too many autolibs; skipping %s", name); 690 return; 691 } 692 693 p = malloc(strlen(name) + 1); 694 strcpy(p, name); 695 library[libraryp] = p; 696 p = malloc(strlen(obj) + 1); 697 strcpy(p, obj); 698 libraryobj[libraryp] = p; 699 libraryp++; 700 } 701 702 void 703 addhist(long line, int type) 704 { 705 Auto *u; 706 Sym *s; 707 int i, j, k; 708 709 u = malloc(sizeof(Auto)); 710 s = malloc(sizeof(Sym)); 711 s->name = malloc(2*(histfrogp+1) + 1); 712 713 u->asym = s; 714 u->type = type; 715 u->aoffset = line; 716 u->link = curhist; 717 curhist = u; 718 719 j = 1; 720 for(i=0; i<histfrogp; i++) { 721 k = histfrog[i]->value; 722 s->name[j+0] = k>>8; 723 s->name[j+1] = k; 724 j += 2; 725 } 726 } 727 728 void 729 histtoauto(void) 730 { 731 Auto *l; 732 733 while(l = curhist) { 734 curhist = l->link; 735 l->link = curauto; 736 curauto = l; 737 } 738 } 739 740 void 741 collapsefrog(Sym *s) 742 { 743 int i; 744 745 /* 746 * bad encoding of path components only allows 747 * MAXHIST components. if there is an overflow, 748 * first try to collapse xxx/.. 749 */ 750 for(i=1; i<histfrogp; i++) 751 if(strcmp(histfrog[i]->name+1, "..") == 0) { 752 memmove(histfrog+i-1, histfrog+i+1, 753 (histfrogp-i-1)*sizeof(histfrog[0])); 754 histfrogp--; 755 goto out; 756 } 757 758 /* 759 * next try to collapse . 760 */ 761 for(i=0; i<histfrogp; i++) 762 if(strcmp(histfrog[i]->name+1, ".") == 0) { 763 memmove(histfrog+i, histfrog+i+1, 764 (histfrogp-i-1)*sizeof(histfrog[0])); 765 goto out; 766 } 767 768 /* 769 * last chance, just truncate from front 770 */ 771 memmove(histfrog+0, histfrog+1, 772 (histfrogp-1)*sizeof(histfrog[0])); 773 774 out: 775 histfrog[histfrogp-1] = s; 776 } 777 778 void 779 nopout(Prog *p) 780 { 781 p->as = ANOP; 782 p->from.type = D_NONE; 783 p->to.type = D_NONE; 784 } 785 786 uchar* 787 readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) 788 { 789 int n; 790 791 n = stop - good; 792 memmove(buf, good, stop - good); 793 stop = buf + n; 794 n = MAXIO - n; 795 if(n > max) 796 n = max; 797 n = read(f, stop, n); 798 if(n <= 0) 799 return 0; 800 return stop + n; 801 } 802 803 void 804 ldobj(int f, long c, char *pn) 805 { 806 long ipc; 807 Prog *p, *t; 808 uchar *bloc, *bsize, *stop; 809 int v, o, r, skip; 810 Sym *h[NSYM], *s, *di; 811 ulong sig; 812 static int files; 813 static char **filen; 814 char **nfilen; 815 816 if((files&15) == 0){ 817 nfilen = malloc((files+16)*sizeof(char*)); 818 memmove(nfilen, filen, files*sizeof(char*)); 819 free(filen); 820 filen = nfilen; 821 } 822 filen[files++] = strdup(pn); 823 824 bsize = buf.xbuf; 825 bloc = buf.xbuf; 826 di = S; 827 828 newloop: 829 memset(h, 0, sizeof(h)); 830 version++; 831 histfrogp = 0; 832 ipc = pc; 833 skip = 0; 834 835 loop: 836 if(c <= 0) 837 goto eof; 838 r = bsize - bloc; 839 if(r < 100 && r < c) { /* enough for largest prog */ 840 bsize = readsome(f, buf.xbuf, bloc, bsize, c); 841 if(bsize == 0) 842 goto eof; 843 bloc = buf.xbuf; 844 goto loop; 845 } 846 o = bloc[0] | (bloc[1] << 8); 847 if(o <= AXXX || o >= ALAST) { 848 if(o < 0) 849 goto eof; 850 diag("%s: opcode out of range %d", pn, o); 851 print(" probably not a .8 file\n"); 852 errorexit(); 853 } 854 855 if(o == ANAME || o == ASIGNAME) { 856 sig = 0; 857 if(o == ASIGNAME) { 858 sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); 859 bloc += 4; 860 c -= 4; 861 } 862 stop = memchr(&bloc[4], 0, bsize-&bloc[4]); 863 if(stop == 0){ 864 bsize = readsome(f, buf.xbuf, bloc, bsize, c); 865 if(bsize == 0) 866 goto eof; 867 bloc = buf.xbuf; 868 stop = memchr(&bloc[4], 0, bsize-&bloc[4]); 869 if(stop == 0){ 870 fprint(2, "%s: name too long\n", pn); 871 errorexit(); 872 } 873 } 874 v = bloc[2]; /* type */ 875 o = bloc[3]; /* sym */ 876 bloc += 4; 877 c -= 4; 878 879 r = 0; 880 if(v == D_STATIC) 881 r = version; 882 s = lookup((char*)bloc, r); 883 c -= &stop[1] - bloc; 884 bloc = stop + 1; 885 886 if(debug['S'] && r == 0) 887 sig = 1729; 888 if(sig != 0){ 889 if(s->sig != 0 && s->sig != sig) 890 diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); 891 s->sig = sig; 892 s->file = files-1; 893 } 894 895 if(debug['W']) 896 print(" ANAME %s\n", s->name); 897 h[o] = s; 898 if((v == D_EXTERN || v == D_STATIC) && s->type == 0) 899 s->type = SXREF; 900 if(v == D_FILE) { 901 if(s->type != SFILE) { 902 histgen++; 903 s->type = SFILE; 904 s->value = histgen; 905 } 906 if(histfrogp < MAXHIST) { 907 histfrog[histfrogp] = s; 908 histfrogp++; 909 } else 910 collapsefrog(s); 911 } 912 goto loop; 913 } 914 915 while(nhunk < sizeof(Prog)) 916 gethunk(); 917 p = (Prog*)hunk; 918 nhunk -= sizeof(Prog); 919 hunk += sizeof(Prog); 920 921 p->as = o; 922 p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24); 923 p->back = 2; 924 r = zaddr(bloc+6, &p->from, h) + 6; 925 r += zaddr(bloc+r, &p->to, h); 926 bloc += r; 927 c -= r; 928 929 if(debug['W']) 930 print("%P\n", p); 931 932 switch(p->as) { 933 case AHISTORY: 934 if(p->to.offset == -1) { 935 addlib(pn); 936 histfrogp = 0; 937 goto loop; 938 } 939 addhist(p->line, D_FILE); /* 'z' */ 940 if(p->to.offset) 941 addhist(p->to.offset, D_FILE1); /* 'Z' */ 942 histfrogp = 0; 943 goto loop; 944 945 case AEND: 946 histtoauto(); 947 if(curtext != P) 948 curtext->to.autom = curauto; 949 curauto = 0; 950 curtext = P; 951 if(c) 952 goto newloop; 953 return; 954 955 case AGLOBL: 956 s = p->from.sym; 957 if(s->type == 0 || s->type == SXREF) { 958 s->type = SBSS; 959 s->value = 0; 960 } 961 if(s->type != SBSS) { 962 diag("%s: redefinition: %s in %s", 963 pn, s->name, TNAME); 964 s->type = SBSS; 965 s->value = 0; 966 } 967 if(p->to.offset > s->value) 968 s->value = p->to.offset; 969 goto loop; 970 971 case ADYNT: 972 if(p->to.sym == S) { 973 diag("DYNT without a sym\n%P", p); 974 break; 975 } 976 di = p->to.sym; 977 p->from.scale = 4; 978 if(di->type == SXREF) { 979 if(debug['z']) 980 Bprint(&bso, "%P set to %d\n", p, dtype); 981 di->type = SCONST; 982 di->value = dtype; 983 dtype += 4; 984 } 985 if(p->from.sym == S) 986 break; 987 988 p->from.offset = di->value; 989 p->from.sym->type = SDATA; 990 if(curtext == P) { 991 diag("DYNT not in text: %P", p); 992 break; 993 } 994 p->to.sym = curtext->from.sym; 995 p->to.type = D_ADDR; 996 p->to.index = D_EXTERN; 997 goto data; 998 999 case AINIT: 1000 if(p->from.sym == S) { 1001 diag("INIT without a sym\n%P", p); 1002 break; 1003 } 1004 if(di == S) { 1005 diag("INIT without previous DYNT\n%P", p); 1006 break; 1007 } 1008 p->from.offset = di->value; 1009 p->from.sym->type = SDATA; 1010 goto data; 1011 1012 case ADATA: 1013 data: 1014 if(edatap == P) 1015 datap = p; 1016 else 1017 edatap->link = p; 1018 edatap = p; 1019 p->link = P; 1020 goto loop; 1021 1022 case AGOK: 1023 diag("%s: GOK opcode in %s", pn, TNAME); 1024 pc++; 1025 goto loop; 1026 1027 case ATEXT: 1028 if(curtext != P) { 1029 histtoauto(); 1030 curtext->to.autom = curauto; 1031 curauto = 0; 1032 } 1033 skip = 0; 1034 curtext = p; 1035 s = p->from.sym; 1036 if(s == S) { 1037 diag("%s: no TEXT symbol: %P", pn, p); 1038 errorexit(); 1039 } 1040 if(s->type != 0 && s->type != SXREF) { 1041 if(p->from.scale & DUPOK) { 1042 skip = 1; 1043 goto casdef; 1044 } 1045 diag("%s: redefinition: %s\n%P", pn, s->name, p); 1046 } 1047 s->type = STEXT; 1048 s->value = pc; 1049 lastp->link = p; 1050 lastp = p; 1051 p->pc = pc; 1052 pc++; 1053 if(textp == P) { 1054 textp = p; 1055 etextp = p; 1056 goto loop; 1057 } 1058 etextp->pcond = p; 1059 etextp = p; 1060 goto loop; 1061 1062 case AFMOVF: 1063 case AFADDF: 1064 case AFSUBF: 1065 case AFSUBRF: 1066 case AFMULF: 1067 case AFDIVF: 1068 case AFDIVRF: 1069 case AFCOMF: 1070 case AFCOMFP: 1071 if(skip) 1072 goto casdef; 1073 if(p->from.type == D_FCONST) { 1074 /* size sb 9 max */ 1075 sprint(literal, "$%lux", ieeedtof(&p->from.ieee)); 1076 s = lookup(literal, 0); 1077 if(s->type == 0) { 1078 s->type = SBSS; 1079 s->value = 4; 1080 t = prg(); 1081 t->as = ADATA; 1082 t->line = p->line; 1083 t->from.type = D_EXTERN; 1084 t->from.sym = s; 1085 t->from.scale = 4; 1086 t->to = p->from; 1087 if(edatap == P) 1088 datap = t; 1089 else 1090 edatap->link = t; 1091 edatap = t; 1092 t->link = P; 1093 } 1094 p->from.type = D_EXTERN; 1095 p->from.sym = s; 1096 p->from.offset = 0; 1097 } 1098 goto casdef; 1099 1100 case AFMOVD: 1101 case AFADDD: 1102 case AFSUBD: 1103 case AFSUBRD: 1104 case AFMULD: 1105 case AFDIVD: 1106 case AFDIVRD: 1107 case AFCOMD: 1108 case AFCOMDP: 1109 if(skip) 1110 goto casdef; 1111 if(p->from.type == D_FCONST) { 1112 /* size sb 18 max */ 1113 sprint(literal, "$%lux.%lux", 1114 p->from.ieee.l, p->from.ieee.h); 1115 s = lookup(literal, 0); 1116 if(s->type == 0) { 1117 s->type = SBSS; 1118 s->value = 8; 1119 t = prg(); 1120 t->as = ADATA; 1121 t->line = p->line; 1122 t->from.type = D_EXTERN; 1123 t->from.sym = s; 1124 t->from.scale = 8; 1125 t->to = p->from; 1126 if(edatap == P) 1127 datap = t; 1128 else 1129 edatap->link = t; 1130 edatap = t; 1131 t->link = P; 1132 } 1133 p->from.type = D_EXTERN; 1134 p->from.sym = s; 1135 p->from.offset = 0; 1136 } 1137 goto casdef; 1138 1139 casdef: 1140 default: 1141 if(skip) 1142 nopout(p); 1143 1144 if(p->to.type == D_BRANCH) 1145 p->to.offset += ipc; 1146 lastp->link = p; 1147 lastp = p; 1148 p->pc = pc; 1149 pc++; 1150 goto loop; 1151 } 1152 goto loop; 1153 1154 eof: 1155 diag("truncated object file: %s", pn); 1156 } 1157 1158 Sym* 1159 lookup(char *symb, int v) 1160 { 1161 Sym *s; 1162 char *p; 1163 long h; 1164 int l, c; 1165 1166 h = v; 1167 for(p=symb; c = *p; p++) 1168 h = h+h+h + c; 1169 l = (p - symb) + 1; 1170 h &= 0xffffff; 1171 h %= NHASH; 1172 for(s = hash[h]; s != S; s = s->link) 1173 if(s->version == v) 1174 if(memcmp(s->name, symb, l) == 0) 1175 return s; 1176 1177 while(nhunk < sizeof(Sym)) 1178 gethunk(); 1179 s = (Sym*)hunk; 1180 nhunk -= sizeof(Sym); 1181 hunk += sizeof(Sym); 1182 1183 s->name = malloc(l + 1); 1184 memmove(s->name, symb, l); 1185 1186 s->link = hash[h]; 1187 s->type = 0; 1188 s->version = v; 1189 s->value = 0; 1190 s->sig = 0; 1191 hash[h] = s; 1192 nsymbol++; 1193 return s; 1194 } 1195 1196 Prog* 1197 prg(void) 1198 { 1199 Prog *p; 1200 1201 while(nhunk < sizeof(Prog)) 1202 gethunk(); 1203 p = (Prog*)hunk; 1204 nhunk -= sizeof(Prog); 1205 hunk += sizeof(Prog); 1206 1207 *p = zprg; 1208 return p; 1209 } 1210 1211 Prog* 1212 copyp(Prog *q) 1213 { 1214 Prog *p; 1215 1216 p = prg(); 1217 *p = *q; 1218 return p; 1219 } 1220 1221 Prog* 1222 appendp(Prog *q) 1223 { 1224 Prog *p; 1225 1226 p = prg(); 1227 p->link = q->link; 1228 q->link = p; 1229 p->line = q->line; 1230 return p; 1231 } 1232 1233 void 1234 gethunk(void) 1235 { 1236 char *h; 1237 long nh; 1238 1239 nh = NHUNK; 1240 if(thunk >= 5L*NHUNK) { 1241 nh = 5L*NHUNK; 1242 if(thunk >= 25L*NHUNK) 1243 nh = 25L*NHUNK; 1244 } 1245 h = mysbrk(nh); 1246 if(h == (char*)-1) { 1247 diag("out of memory"); 1248 errorexit(); 1249 } 1250 hunk = h; 1251 nhunk = nh; 1252 thunk += nh; 1253 } 1254 1255 void 1256 doprof1(void) 1257 { 1258 Sym *s; 1259 long n; 1260 Prog *p, *q; 1261 1262 if(debug['v']) 1263 Bprint(&bso, "%5.2f profile 1\n", cputime()); 1264 Bflush(&bso); 1265 s = lookup("__mcount", 0); 1266 n = 1; 1267 for(p = firstp->link; p != P; p = p->link) { 1268 if(p->as == ATEXT) { 1269 q = prg(); 1270 q->line = p->line; 1271 q->link = datap; 1272 datap = q; 1273 q->as = ADATA; 1274 q->from.type = D_EXTERN; 1275 q->from.offset = n*4; 1276 q->from.sym = s; 1277 q->from.scale = 4; 1278 q->to = p->from; 1279 q->to.type = D_CONST; 1280 1281 q = prg(); 1282 q->line = p->line; 1283 q->pc = p->pc; 1284 q->link = p->link; 1285 p->link = q; 1286 p = q; 1287 p->as = AADDL; 1288 p->from.type = D_CONST; 1289 p->from.offset = 1; 1290 p->to.type = D_EXTERN; 1291 p->to.sym = s; 1292 p->to.offset = n*4 + 4; 1293 1294 n += 2; 1295 continue; 1296 } 1297 } 1298 q = prg(); 1299 q->line = 0; 1300 q->link = datap; 1301 datap = q; 1302 1303 q->as = ADATA; 1304 q->from.type = D_EXTERN; 1305 q->from.sym = s; 1306 q->from.scale = 4; 1307 q->to.type = D_CONST; 1308 q->to.offset = n; 1309 1310 s->type = SBSS; 1311 s->value = n*4; 1312 } 1313 1314 void 1315 doprof2(void) 1316 { 1317 Sym *s2, *s4; 1318 Prog *p, *q, *q2, *ps2, *ps4; 1319 1320 if(debug['v']) 1321 Bprint(&bso, "%5.2f profile 2\n", cputime()); 1322 Bflush(&bso); 1323 1324 if(debug['e']){ 1325 s2 = lookup("_tracein", 0); 1326 s4 = lookup("_traceout", 0); 1327 }else{ 1328 s2 = lookup("_profin", 0); 1329 s4 = lookup("_profout", 0); 1330 } 1331 if(s2->type != STEXT || s4->type != STEXT) { 1332 if(debug['e']) 1333 diag("_tracein/_traceout not defined %d %d", s2->type, s4->type); 1334 else 1335 diag("_profin/_profout not defined"); 1336 return; 1337 } 1338 1339 ps2 = P; 1340 ps4 = P; 1341 for(p = firstp; p != P; p = p->link) { 1342 if(p->as == ATEXT) { 1343 if(p->from.sym == s2) { 1344 p->from.scale = 1; 1345 ps2 = p; 1346 } 1347 if(p->from.sym == s4) { 1348 p->from.scale = 1; 1349 ps4 = p; 1350 } 1351 } 1352 } 1353 for(p = firstp; p != P; p = p->link) { 1354 if(p->as == ATEXT) { 1355 curtext = p; 1356 1357 if(p->from.scale & NOPROF) { /* dont profile */ 1358 for(;;) { 1359 q = p->link; 1360 if(q == P) 1361 break; 1362 if(q->as == ATEXT) 1363 break; 1364 p = q; 1365 } 1366 continue; 1367 } 1368 1369 /* 1370 * JMPL profin 1371 */ 1372 q = prg(); 1373 q->line = p->line; 1374 q->pc = p->pc; 1375 q->link = p->link; 1376 if(debug['e']){ /* embedded tracing */ 1377 q2 = prg(); 1378 p->link = q2; 1379 q2->link = q; 1380 1381 q2->line = p->line; 1382 q2->pc = p->pc; 1383 1384 q2->as = AJMP; 1385 q2->to.type = D_BRANCH; 1386 q2->to.sym = p->to.sym; 1387 q2->pcond = q->link; 1388 }else 1389 p->link = q; 1390 p = q; 1391 p->as = ACALL; 1392 p->to.type = D_BRANCH; 1393 p->pcond = ps2; 1394 p->to.sym = s2; 1395 1396 continue; 1397 } 1398 if(p->as == ARET) { 1399 /* 1400 * RET (default) 1401 */ 1402 if(debug['e']){ /* embedded tracing */ 1403 q = prg(); 1404 q->line = p->line; 1405 q->pc = p->pc; 1406 q->link = p->link; 1407 p->link = q; 1408 p = q; 1409 } 1410 /* 1411 * RET 1412 */ 1413 q = prg(); 1414 q->as = ARET; 1415 q->from = p->from; 1416 q->to = p->to; 1417 q->link = p->link; 1418 p->link = q; 1419 1420 /* 1421 * JAL profout 1422 */ 1423 p->as = ACALL; 1424 p->from = zprg.from; 1425 p->to = zprg.to; 1426 p->to.type = D_BRANCH; 1427 p->pcond = ps4; 1428 p->to.sym = s4; 1429 1430 p = q; 1431 1432 continue; 1433 } 1434 } 1435 } 1436 1437 void 1438 nuxiinit(void) 1439 { 1440 int i, c; 1441 1442 for(i=0; i<4; i++) { 1443 c = find1(0x04030201L, i+1); 1444 if(i < 2) 1445 inuxi2[i] = c; 1446 if(i < 1) 1447 inuxi1[i] = c; 1448 inuxi4[i] = c; 1449 fnuxi4[i] = c; 1450 fnuxi8[i] = c; 1451 fnuxi8[i+4] = c+4; 1452 } 1453 if(debug['v']) { 1454 Bprint(&bso, "inuxi = "); 1455 for(i=0; i<1; i++) 1456 Bprint(&bso, "%d", inuxi1[i]); 1457 Bprint(&bso, " "); 1458 for(i=0; i<2; i++) 1459 Bprint(&bso, "%d", inuxi2[i]); 1460 Bprint(&bso, " "); 1461 for(i=0; i<4; i++) 1462 Bprint(&bso, "%d", inuxi4[i]); 1463 Bprint(&bso, "\nfnuxi = "); 1464 for(i=0; i<4; i++) 1465 Bprint(&bso, "%d", fnuxi4[i]); 1466 Bprint(&bso, " "); 1467 for(i=0; i<8; i++) 1468 Bprint(&bso, "%d", fnuxi8[i]); 1469 Bprint(&bso, "\n"); 1470 } 1471 Bflush(&bso); 1472 } 1473 1474 int 1475 find1(long l, int c) 1476 { 1477 char *p; 1478 int i; 1479 1480 p = (char*)&l; 1481 for(i=0; i<4; i++) 1482 if(*p++ == c) 1483 return i; 1484 return 0; 1485 } 1486 1487 int 1488 find2(long l, int c) 1489 { 1490 short *p; 1491 int i; 1492 1493 p = (short*)&l; 1494 for(i=0; i<4; i+=2) { 1495 if(((*p >> 8) & 0xff) == c) 1496 return i; 1497 if((*p++ & 0xff) == c) 1498 return i+1; 1499 } 1500 return 0; 1501 } 1502 1503 long 1504 ieeedtof(Ieee *e) 1505 { 1506 int exp; 1507 long v; 1508 1509 if(e->h == 0) 1510 return 0; 1511 exp = (e->h>>20) & ((1L<<11)-1L); 1512 exp -= (1L<<10) - 2L; 1513 v = (e->h & 0xfffffL) << 3; 1514 v |= (e->l >> 29) & 0x7L; 1515 if((e->l >> 28) & 1) { 1516 v++; 1517 if(v & 0x800000L) { 1518 v = (v & 0x7fffffL) >> 1; 1519 exp++; 1520 } 1521 } 1522 if(exp <= -126 || exp >= 130) 1523 diag("double fp to single fp overflow"); 1524 v |= ((exp + 126) & 0xffL) << 23; 1525 v |= e->h & 0x80000000L; 1526 return v; 1527 } 1528 1529 double 1530 ieeedtod(Ieee *ieeep) 1531 { 1532 Ieee e; 1533 double fr; 1534 int exp; 1535 1536 if(ieeep->h & (1L<<31)) { 1537 e.h = ieeep->h & ~(1L<<31); 1538 e.l = ieeep->l; 1539 return -ieeedtod(&e); 1540 } 1541 if(ieeep->l == 0 && ieeep->h == 0) 1542 return 0; 1543 fr = ieeep->l & ((1L<<16)-1L); 1544 fr /= 1L<<16; 1545 fr += (ieeep->l>>16) & ((1L<<16)-1L); 1546 fr /= 1L<<16; 1547 fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); 1548 fr /= 1L<<21; 1549 exp = (ieeep->h>>20) & ((1L<<11)-1L); 1550 exp -= (1L<<10) - 2L; 1551 return ldexp(fr, exp); 1552 } 1553 1554 void 1555 undefsym(Sym *s) 1556 { 1557 int n; 1558 1559 n = imports; 1560 if(s->value != 0) 1561 diag("value != 0 on SXREF"); 1562 if(n >= 1<<Rindex) 1563 diag("import index %d out of range", n); 1564 s->value = n<<Roffset; 1565 s->type = SUNDEF; 1566 imports++; 1567 } 1568 1569 void 1570 zerosig(char *sp) 1571 { 1572 Sym *s; 1573 1574 s = lookup(sp, 0); 1575 s->sig = 0; 1576 } 1577 1578 void 1579 readundefs(char *f, int t) 1580 { 1581 int i, n; 1582 Sym *s; 1583 Biobuf *b; 1584 char *l, buf[256], *fields[64]; 1585 1586 if(f == nil) 1587 return; 1588 b = Bopen(f, OREAD); 1589 if(b == nil){ 1590 diag("could not open %s: %r", f); 1591 errorexit(); 1592 } 1593 while((l = Brdline(b, '\n')) != nil){ 1594 n = Blinelen(b); 1595 if(n >= sizeof(buf)){ 1596 diag("%s: line too long", f); 1597 errorexit(); 1598 } 1599 memmove(buf, l, n); 1600 buf[n-1] = '\0'; 1601 n = getfields(buf, fields, nelem(fields), 1, " \t\r\n"); 1602 if(n == nelem(fields)){ 1603 diag("%s: bad format", f); 1604 errorexit(); 1605 } 1606 for(i = 0; i < n; i++){ 1607 s = lookup(fields[i], 0); 1608 s->type = SXREF; 1609 s->subtype = t; 1610 if(t == SIMPORT) 1611 nimports++; 1612 else 1613 nexports++; 1614 } 1615 } 1616 Bterm(b); 1617 } 1618