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