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