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