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