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