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