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