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