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