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