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