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
main(int argc,char * argv[])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
loadlib(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
errorexit(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
objfile(char * file)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
zaddr(uchar * p,Adr * a,Sym * h[])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
addlib(char * obj)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
addhist(long line,int type)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
histtoauto(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
collapsefrog(Sym * s)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
nopout(Prog * p)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*
readsome(int f,uchar * buf,uchar * good,uchar * stop,int max)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
ldobj(int f,long c,char * pn)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*
lookup(char * symb,int v)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*
prg(void)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
gethunk(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
doprof1(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
doprof2(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
nuxiinit(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
find1(long l,int c)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
ieeedtof(Ieee * ieeep)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
ieeedtod(Ieee * ieeep)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