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