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