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