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