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