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