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