xref: /inferno-os/limbo/dis.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include "limbo.h"
2 
3 static	void	disbig(long, Long);
4 static	void	disbyte(long, int);
5 static	void	disbytes(long, void*, int);
6 static	void	disdatum(long, Node*);
7 static	void	disflush(int, long, long);
8 static	void	disint(long, long);
9 static	void	disreal(long, Real);
10 static	void	disstring(long, Sym*);
11 
12 static	uchar	*cache;
13 static	int	ncached;
14 static	int	ndatum;
15 static	int	startoff;
16 static	int	lastoff;
17 static	int	lastkind;
18 static	int	lencache;
19 
20 void
21 discon(long val)
22 {
23 	if(val >= -64 && val <= 63) {
24 		Bputc(bout, val & ~0x80);
25 		return;
26 	}
27 	if(val >= -8192 && val <= 8191) {
28 		Bputc(bout, ((val>>8) & ~0xC0) | 0x80);
29 		Bputc(bout, val);
30 		return;
31 	}
32 	if(val < 0 && ((val >> 29) & 0x7) != 7
33 	|| val > 0 && (val >> 29) != 0)
34 		fatal("overflow in constant 0x%lux\n", val);
35 	Bputc(bout, (val>>24) | 0xC0);
36 	Bputc(bout, val>>16);
37 	Bputc(bout, val>>8);
38 	Bputc(bout, val);
39 }
40 
41 void
42 disword(long w)
43 {
44 	Bputc(bout, w >> 24);
45 	Bputc(bout, w >> 16);
46 	Bputc(bout, w >> 8);
47 	Bputc(bout, w);
48 }
49 
50 void
51 disdata(int kind, long n)
52 {
53 	if(n < DMAX && n != 0)
54 		Bputc(bout, DBYTE(kind, n));
55 	else{
56 		Bputc(bout, DBYTE(kind, 0));
57 		discon(n);
58 	}
59 }
60 
61 #define	NAMELEN	64
62 
63 void
64 dismod(Decl *m)
65 {
66 	char name[8*NAMELEN];
67 	vlong fileoff;
68 
69 	fileoff = Boffset(bout);
70 	strncpy(name, m->sym->name, NAMELEN);
71 	name[NAMELEN-1] = '\0';
72 	Bwrite(bout, name, strlen(name)+1);
73 	for(m = m->ty->tof->ids; m != nil; m = m->next){
74 		switch(m->store){
75 		case Dglobal:
76 			discon(-1);
77 			discon(-1);
78 			disword(sign(m));
79 			Bprint(bout, ".mp");
80 			Bputc(bout, '\0');
81 			break;
82 		case Dfn:
83 if(debug['v']) print("Dfn: %s %d %p\n", m->sym->name, m->refs, m);
84 			discon(m->pc->pc);
85 			discon(m->desc->id);
86 			disword(sign(m));
87 			if(m->dot->ty->kind == Tadt)
88 				Bprint(bout, "%s.", m->dot->sym->name);
89 			Bprint(bout, "%s", m->sym->name);
90 			Bputc(bout, '\0');
91 			break;
92 		default:
93 			fatal("unknown kind %K in dismod", m);
94 			break;
95 		}
96 	}
97 	if(debug['s'])
98 		print("%lld linkage bytes start %lld\n", Boffset(bout) - fileoff, fileoff);
99 }
100 
101 void
102 dispath(void)
103 {
104 	char name[8*NAMELEN], *sp;
105 
106 	sp = srcpath(name, 8*NAMELEN);
107 	Bwrite(bout, sp, strlen(sp)+1);
108 }
109 
110 void
111 disentry(Decl *e)
112 {
113 	if(e == nil){
114 		discon(-1);
115 		discon(-1);
116 		return;
117 	}
118 	discon(e->pc->pc);
119 	discon(e->desc->id);
120 }
121 
122 void
123 disdesc(Desc *d)
124 {
125 	vlong fileoff;
126 
127 	fileoff = Boffset(bout);
128 	for(; d != nil; d = d->next){
129 		discon(d->id);
130 		discon(d->size);
131 		discon(d->nmap);
132 		Bwrite(bout, d->map, d->nmap);
133 	}
134 	if(debug['s'])
135 		print("%lld type descriptor bytes start %lld\n", Boffset(bout) - fileoff, fileoff);
136 }
137 
138 void
139 disvar(long size, Decl *d)
140 {
141 	vlong fileoff;
142 
143 	fileoff = Boffset(bout);
144 	USED(size);
145 
146 	lastkind = -1;
147 	ncached = 0;
148 	ndatum = 0;
149 
150 	for(; d != nil; d = d->next)
151 		if(d->store == Dglobal && d->init != nil)
152 			disdatum(d->offset, d->init);
153 
154 	disflush(-1, -1, 0);
155 
156 	Bputc(bout, 0);
157 
158 	if(debug['s'])
159 		print("%lld data bytes start %lld\n", Boffset(bout) - fileoff, fileoff);
160 }
161 
162 void
163 disldt(long size, Decl *ds)
164 {
165 	int m;
166 	Decl *d, *id;
167 	Sym *s;
168 	Node *n;
169 
170 	if(0){
171 		discon(size);
172 		disvar(size, ds);
173 		return;
174 	}
175 
176 	m = 0;
177 	for(d = ds; d != nil; d = d->next)
178 		if(d->store == Dglobal && d->init != nil)
179 			m++;
180 	discon(m);
181 	for(d = ds; d != nil; d = d->next){
182 		if(d->store == Dglobal && d->init != nil){
183 			n = d->init;
184 			if(n->ty->kind != Tiface)
185 				nerror(n, "disldt: not Tiface");
186 			discon(n->val);
187 			for(id = n->decl->ty->ids; id != nil; id = id->next){
188 				disword(sign(id));
189 				if(id->dot->ty->kind == Tadt){
190 					s = id->dot->sym;
191 					Bprint(bout, "%s", s->name);
192 					Bputc(bout, '.');
193 				}
194 				s = id->sym;
195 				Bprint(bout, "%s", s->name);
196 				Bputc(bout, 0);
197 			}
198 		}
199 	}
200 	discon(0);
201 }
202 
203 static void
204 disdatum(long offset, Node *n)
205 {
206 	Node *elem, *wild;
207 	Case *c;
208 	Label *lab;
209 	Decl *id;
210 	Sym *s;
211 	long e, last, esz;
212 	int i;
213 
214 	switch(n->ty->kind){
215 	case Tbyte:
216 		disbyte(offset, n->val);
217 		break;
218 	case Tint:
219 	case Tfix:
220 		disint(offset, n->val);
221 		break;
222 	case Tbig:
223 		disbig(offset, n->val);
224 		break;
225 	case Tstring:
226 		disstring(offset, n->decl->sym);
227 		break;
228 	case Treal:
229 		disreal(offset, n->rval);
230 		break;
231 	case Tadt:
232 	case Tadtpick:
233 	case Ttuple:
234 		id = n->ty->ids;
235 		for(n = n->left; n != nil; n = n->right){
236 			disdatum(offset + id->offset, n->left);
237 			id = id->next;
238 		}
239 		break;
240 	case Tany:
241 		break;
242 	case Tcase:
243 		c = n->ty->cse;
244 		disint(offset, c->nlab);
245 		offset += IBY2WD;
246 		for(i = 0; i < c->nlab; i++){
247 			lab = &c->labs[i];
248 			disint(offset, lab->start->val);
249 			offset += IBY2WD;
250 			disint(offset, lab->stop->val+1);
251 			offset += IBY2WD;
252 			disint(offset, lab->inst->pc);
253 			offset += IBY2WD;
254 		}
255 		disint(offset, c->iwild ? c->iwild->pc : -1);
256 		break;
257 	case Tcasel:
258 		c = n->ty->cse;
259 		disint(offset, c->nlab);
260 		offset += 2*IBY2WD;
261 		for(i = 0; i < c->nlab; i++){
262 			lab = &c->labs[i];
263 			disbig(offset, lab->start->val);
264 			offset += IBY2LG;
265 			disbig(offset, lab->stop->val+1);
266 			offset += IBY2LG;
267 			disint(offset, lab->inst->pc);
268 			offset += 2*IBY2WD;
269 		}
270 		disint(offset, c->iwild ? c->iwild->pc : -1);
271 		break;
272 	case Tcasec:
273 		c = n->ty->cse;
274 		disint(offset, c->nlab);
275 		offset += IBY2WD;
276 		for(i = 0; i < c->nlab; i++){
277 			lab = &c->labs[i];
278 			disstring(offset, lab->start->decl->sym);
279 			offset += IBY2WD;
280 			if(lab->stop != lab->start)
281 				disstring(offset, lab->stop->decl->sym);
282 			offset += IBY2WD;
283 			disint(offset, lab->inst->pc);
284 			offset += IBY2WD;
285 		}
286 		disint(offset, c->iwild ? c->iwild->pc : -1);
287 		break;
288 	case Tgoto:
289 		c = n->ty->cse;
290 		disint(offset, n->ty->size/IBY2WD-1);
291 		offset += IBY2WD;
292 		for(i = 0; i < c->nlab; i++){
293 			disint(offset, c->labs[i].inst->pc);
294 			offset += IBY2WD;
295 		}
296 		if(c->iwild != nil)
297 			disint(offset, c->iwild->pc);
298 		break;
299 	case Tarray:
300 		disflush(-1, -1, 0);
301 		disdata(DEFA, 1);		/* 1 is ignored */
302 		discon(offset);
303 		disword(n->ty->tof->decl->desc->id);
304 		disword(n->left->val);
305 
306 		if(n->right == nil)
307 			break;
308 
309 		disdata(DIND, 1);		/* 1 is ignored */
310 		discon(offset);
311 		disword(0);
312 
313 		c = n->right->ty->cse;
314 		wild = nil;
315 		if(c->wild != nil)
316 			wild = c->wild->right;
317 		last = 0;
318 		esz = n->ty->tof->size;
319 		for(i = 0; i < c->nlab; i++){
320 			e = c->labs[i].start->val;
321 			if(wild != nil){
322 				for(; last < e; last++)
323 					disdatum(esz * last, wild);
324 			}
325 			last = e;
326 			e = c->labs[i].stop->val;
327 			elem = c->labs[i].node->right;
328 			for(; last <= e; last++)
329 				disdatum(esz * last, elem);
330 		}
331 		if(wild != nil)
332 			for(e = n->left->val; last < e; last++)
333 				disdatum(esz * last, wild);
334 
335 		disflush(-1, -1, 0);
336 		disdata(DAPOP, 1);		/* 1 is ignored */
337 		discon(0);
338 
339 		break;
340 	case Tiface:
341 		disint(offset, n->val);
342 		offset += IBY2WD;
343 		for(id = n->decl->ty->ids; id != nil; id = id->next){
344 			offset = align(offset, IBY2WD);
345 			disint(offset, sign(id));
346 			offset += IBY2WD;
347 
348 			if(id->dot->ty->kind == Tadt){
349 				s = id->dot->sym;
350 				disbytes(offset, s->name, s->len);
351 				offset += s->len;
352 				disbyte(offset, '.');
353 				offset++;
354 			}
355 			s = id->sym;
356 			disbytes(offset, s->name, s->len);
357 			offset += s->len;
358 			disbyte(offset, 0);
359 			offset++;
360 		}
361 		break;
362 	default:
363 		nerror(n, "can't dis global %n", n);
364 		break;
365 	}
366 }
367 
368 void
369 disexc(Except *es)
370 {
371 	int i, n;
372 	Decl *d;
373 	Except *e;
374 	Case *c;
375 	Label *lab;
376 
377 	n = 0;
378 	for(e = es; e != nil; e = e->next)
379 		if(e->p1->reach || e->p2->reach)
380 			n++;
381 	discon(n);
382 	for(e = es; e != nil; e = e->next){
383 		if(!e->p1->reach && !e->p2->reach)
384 			continue;
385 		c = e->c;
386 		discon(e->d->offset);
387 		discon(getpc(e->p1));
388 		discon(getpc(e->p2));
389 		if(e->desc)
390 			discon(e->desc->id);
391 		else
392 			discon(-1);
393 		discon(c->nlab|(e->ne<<16));
394 		for(i = 0; i < c->nlab; i++){
395 			lab = &c->labs[i];
396 			d = lab->start->decl;
397 			if(lab->start->ty->kind == Texception)
398 				d = d->init->decl;
399 			Bprint(bout, "%s", d->sym->name);
400 			Bputc(bout, '\0');
401 			discon(lab->inst->pc);
402 		}
403 		if(c->iwild == nil)
404 			discon(-1);
405 		else
406 			discon(c->iwild->pc);
407 	}
408 	discon(0);
409 }
410 
411 static void
412 disbyte(long off, int v)
413 {
414 	disflush(DEFB, off, 1);
415 	cache[ncached++] = v;
416 	ndatum++;
417 }
418 
419 static void
420 disbytes(long off, void *v, int n)
421 {
422 	disflush(DEFB, off, n);
423 	memmove(&cache[ncached], v, n);
424 	ncached += n;
425 	ndatum += n;
426 }
427 
428 static void
429 disint(long off, long v)
430 {
431 	disflush(DEFW, off, IBY2WD);
432 	cache[ncached++] = v >> 24;
433 	cache[ncached++] = v >> 16;
434 	cache[ncached++] = v >> 8;
435 	cache[ncached++] = v;
436 	ndatum++;
437 }
438 
439 static void
440 disbig(long off, Long v)
441 {
442 	ulong iv;
443 
444 	disflush(DEFL, off, IBY2LG);
445 	iv = v >> 32;
446 	cache[ncached++] = iv >> 24;
447 	cache[ncached++] = iv >> 16;
448 	cache[ncached++] = iv >> 8;
449 	cache[ncached++] = iv;
450 	iv = v;
451 	cache[ncached++] = iv >> 24;
452 	cache[ncached++] = iv >> 16;
453 	cache[ncached++] = iv >> 8;
454 	cache[ncached++] = iv;
455 	ndatum++;
456 }
457 
458 static void
459 disreal(long off, Real v)
460 {
461 	ulong bv[2];
462 	ulong iv;
463 
464 	disflush(DEFF, off, IBY2LG);
465 	dtocanon(v, bv);
466 	iv = bv[0];
467 	cache[ncached++] = iv >> 24;
468 	cache[ncached++] = iv >> 16;
469 	cache[ncached++] = iv >> 8;
470 	cache[ncached++] = iv;
471 	iv = bv[1];
472 	cache[ncached++] = iv >> 24;
473 	cache[ncached++] = iv >> 16;
474 	cache[ncached++] = iv >> 8;
475 	cache[ncached++] = iv;
476 	ndatum++;
477 }
478 
479 static void
480 disstring(long offset, Sym *sym)
481 {
482 	disflush(-1, -1, 0);
483 	disdata(DEFS, sym->len);
484 	discon(offset);
485 	Bwrite(bout, sym->name, sym->len);
486 }
487 
488 static void
489 disflush(int kind, long off, long size)
490 {
491 	if(kind != lastkind || off != lastoff){
492 		if(lastkind != -1 && ncached){
493 			disdata(lastkind, ndatum);
494 			discon(startoff);
495 			Bwrite(bout, cache, ncached);
496 		}
497 		startoff = off;
498 		lastkind = kind;
499 		ncached = 0;
500 		ndatum = 0;
501 	}
502 	lastoff = off + size;
503 	while(kind >= 0 && ncached + size >= lencache){
504 		lencache = ncached+1024;
505 		cache = reallocmem(cache, lencache);
506 	}
507 }
508 
509 static int dismode[Aend] = {
510 	/* Aimm */	AIMM,
511 	/* Amp */	AMP,
512 	/* Ampind */	AMP|AIND,
513 	/* Afp */	AFP,
514 	/* Afpind */	AFP|AIND,
515 	/* Apc */	AIMM,
516 	/* Adesc */	AIMM,
517 	/* Aoff */	AIMM,
518 	/* Anoff */	AIMM,
519 	/* Aerr */	AXXX,
520 	/* Anone */	AXXX,
521 	/* Aldt */	AIMM,
522 };
523 
524 static int disregmode[Aend] = {
525 	/* Aimm */	AXIMM,
526 	/* Amp */	AXINM,
527 	/* Ampind */	AXNON,
528 	/* Afp */	AXINF,
529 	/* Afpind */	AXNON,
530 	/* Apc */	AXIMM,
531 	/* Adesc */	AXIMM,
532 	/* Aoff */	AXIMM,
533 	/* Anoff */	AXIMM,
534 	/* Aerr */	AXNON,
535 	/* Anone */	AXNON,
536 	/* Aldt */	AXIMM,
537 };
538 
539 enum
540 {
541 	MAXCON	= 4,
542 	MAXADDR	= 2*MAXCON,
543 	MAXINST	= 3*MAXADDR+2,
544 	NIBUF	= 1024
545 };
546 
547 static	uchar	*ibuf;
548 static	int	nibuf;
549 
550 void
551 disinst(Inst *in)
552 {
553 	vlong fileoff;
554 
555 	fileoff = Boffset(bout);
556 	ibuf = allocmem(NIBUF);
557 	nibuf = 0;
558 	for(; in != nil; in = in->next){
559 		if(in->op == INOOP)
560 			continue;
561 		if(nibuf >= NIBUF-MAXINST){
562 			Bwrite(bout, ibuf, nibuf);
563 			nibuf = 0;
564 		}
565 		ibuf[nibuf++] = in->op;
566 		ibuf[nibuf++] = SRC(dismode[in->sm]) | DST(dismode[in->dm]) | disregmode[in->mm];
567 		if(in->mm != Anone)
568 			disaddr(in->mm, &in->m);
569 		if(in->sm != Anone)
570 			disaddr(in->sm, &in->s);
571 		if(in->dm != Anone)
572 			disaddr(in->dm, &in->d);
573 	}
574 	if(nibuf > 0)
575 		Bwrite(bout, ibuf, nibuf);
576 	free(ibuf);
577 	ibuf = nil;
578 
579 	if(debug['s'])
580 		print("%lld instruction bytes start %lld\n", Boffset(bout) - fileoff, fileoff);
581 }
582 
583 void
584 disaddr(int m, Addr *a)
585 {
586 	long val;
587 
588 	val = 0;
589 	switch(m){
590 	case Anone:
591 	case Aerr:
592 	default:
593 		break;
594 	case Aimm:
595 	case Apc:
596 	case Adesc:
597 		val = a->offset;
598 		break;
599 	case Aoff:
600 		val = a->decl->iface->offset;
601 		break;
602 	case Anoff:
603 		val = -(a->decl->iface->offset+1);
604 		break;
605 	case Afp:
606 	case Amp:
607 	case Aldt:
608 		val = a->reg;
609 		break;
610 	case Afpind:
611 	case Ampind:
612 		disbcon(a->reg);
613 		val = a->offset;
614 		break;
615 	}
616 	disbcon(val);
617 }
618 
619 void
620 disbcon(long val)
621 {
622 	if(val >= -64 && val <= 63){
623 		ibuf[nibuf++] = val & ~0x80;
624 		return;
625 	}
626 	if(val >= -8192 && val <= 8191){
627 		ibuf[nibuf++] = val>>8 & ~0xC0 | 0x80;
628 		ibuf[nibuf++] = val;
629 		return;
630 	}
631 	if(val < 0 && ((val >> 29) & 7) != 7
632 	|| val > 0 && (val >> 29) != 0)
633 		fatal("overflow in constant 16r%lux", val);
634 	ibuf[nibuf++] = val>>24 | 0xC0;
635 	ibuf[nibuf++] = val>>16;
636 	ibuf[nibuf++] = val>>8;
637 	ibuf[nibuf++] = val;
638 }
639