xref: /inferno-os/utils/ql/obj.c (revision dea4b9f1bb02529d02b0389c1f6b0e514ed7deff)
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