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