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