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