changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/7l/obj.c

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