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