Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
34
usage(void)
35
{
36
	diag("usage: %s [-options] objects", argv0);
37
	errorexit();
38
}
39
 
40
static int
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
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
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*
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
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
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
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
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
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
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
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
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
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*
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
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*
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*
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
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
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
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
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
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
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
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
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
1547
zerosig(char *sp)
1548
{
1549
	Sym *s;
1550
 
1551
	s = lookup(sp, 0);
1552
	s->sig = 0;
1553
}
1554
 
1555
void
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
}