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