xref: /inferno-os/utils/8l/span.c (revision ddf161d27871e47d85fd56e8403c715af8ce43c8)
1 #include	"l.h"
2 
3 void
4 span(void)
5 {
6 	Prog *p, *q;
7 	long v, c, idat;
8 	int m, n, again;
9 
10 	xdefine("etext", STEXT, 0L);
11 	idat = INITDAT;
12 	for(p = firstp; p != P; p = p->link) {
13 		if(p->as == ATEXT)
14 			curtext = p;
15 		n = 0;
16 		if(p->to.type == D_BRANCH)
17 			if(p->pcond == P)
18 				p->pcond = p;
19 		if((q = p->pcond) != P)
20 			if(q->back != 2)
21 				n = 1;
22 		p->back = n;
23 		if(p->as == AADJSP) {
24 			p->to.type = D_SP;
25 			v = -p->from.offset;
26 			p->from.offset = v;
27 			p->as = AADDL;
28 			if(v < 0) {
29 				p->as = ASUBL;
30 				v = -v;
31 				p->from.offset = v;
32 			}
33 			if(v == 0)
34 				p->as = ANOP;
35 		}
36 	}
37 	n = 0;
38 
39 start:
40 	if(debug['v'])
41 		Bprint(&bso, "%5.2f span\n", cputime());
42 	Bflush(&bso);
43 	c = INITTEXT;
44 	for(p = firstp; p != P; p = p->link) {
45 		if(p->as == ATEXT)
46 			curtext = p;
47 		if(p->to.type == D_BRANCH)
48 			if(p->back)
49 				p->pc = c;
50 		asmins(p);
51 		p->pc = c;
52 		m = andptr-and;
53 		p->mark = m;
54 		c += m;
55 	}
56 
57 loop:
58 	n++;
59 	if(debug['v'])
60 		Bprint(&bso, "%5.2f span %d\n", cputime(), n);
61 	Bflush(&bso);
62 	if(n > 50) {
63 		print("span must be looping\n");
64 		errorexit();
65 	}
66 	again = 0;
67 	c = INITTEXT;
68 	for(p = firstp; p != P; p = p->link) {
69 		if(p->as == ATEXT)
70 			curtext = p;
71 		if(p->to.type == D_BRANCH) {
72 			if(p->back)
73 				p->pc = c;
74 			asmins(p);
75 			m = andptr-and;
76 			if(m != p->mark) {
77 				p->mark = m;
78 				again++;
79 			}
80 		}
81 		p->pc = c;
82 		c += p->mark;
83 	}
84 	if(again) {
85 		textsize = c;
86 		goto loop;
87 	}
88 	if(INITRND) {
89 		INITDAT = rnd(c, INITRND);
90 		if(INITDAT != idat) {
91 			idat = INITDAT;
92 			goto start;
93 		}
94 	}
95 	xdefine("etext", STEXT, c);
96 	if(debug['v'])
97 		Bprint(&bso, "etext = %lux\n", c);
98 	Bflush(&bso);
99 	for(p = textp; p != P; p = p->pcond)
100 		p->from.sym->value = p->pc;
101 	textsize = c - INITTEXT;
102 }
103 
104 void
105 xdefine(char *p, int t, long v)
106 {
107 	Sym *s;
108 
109 	s = lookup(p, 0);
110 	if(s->type == 0 || s->type == SXREF) {
111 		s->type = t;
112 		s->value = v;
113 	}
114 	if(s->type == STEXT && s->value == 0)
115 		s->value = v;
116 }
117 
118 void
119 putsymb(char *s, int t, long v, int ver)
120 {
121 	int i, f;
122 
123 	if(t == 'f')
124 		s++;
125 	lput(v);
126 	if(ver)
127 		t += 'a' - 'A';
128 	cput(t+0x80);			/* 0x80 is variable length */
129 
130 	if(t == 'Z' || t == 'z') {
131 		cput(s[0]);
132 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
133 			cput(s[i]);
134 			cput(s[i+1]);
135 		}
136 		cput(0);
137 		cput(0);
138 		i++;
139 	}
140 	else {
141 		for(i=0; s[i]; i++)
142 			cput(s[i]);
143 		cput(0);
144 	}
145 	symsize += 4 + 1 + i + 1;
146 
147 	if(debug['n']) {
148 		if(t == 'z' || t == 'Z') {
149 			Bprint(&bso, "%c %.8lux ", t, v);
150 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
151 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
152 				Bprint(&bso, "/%x", f);
153 			}
154 			Bprint(&bso, "\n");
155 			return;
156 		}
157 		if(ver)
158 			Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
159 		else
160 			Bprint(&bso, "%c %.8lux %s\n", t, v, s);
161 	}
162 }
163 
164 void
165 asmsym(void)
166 {
167 	Prog *p;
168 	Auto *a;
169 	Sym *s;
170 	int h;
171 
172 	s = lookup("etext", 0);
173 	if(s->type == STEXT)
174 		putsymb(s->name, 'T', s->value, s->version);
175 
176 	for(h=0; h<NHASH; h++)
177 		for(s=hash[h]; s!=S; s=s->link)
178 			switch(s->type) {
179 			case SCONST:
180 				putsymb(s->name, 'D', s->value, s->version);
181 				continue;
182 
183 			case SDATA:
184 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
185 				continue;
186 
187 			case SBSS:
188 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
189 				continue;
190 
191 			case SFILE:
192 				putsymb(s->name, 'f', s->value, s->version);
193 				continue;
194 			}
195 
196 	for(p=textp; p!=P; p=p->pcond) {
197 		s = p->from.sym;
198 		if(s->type != STEXT)
199 			continue;
200 
201 		/* filenames first */
202 		for(a=p->to.autom; a; a=a->link)
203 			if(a->type == D_FILE)
204 				putsymb(a->asym->name, 'z', a->aoffset, 0);
205 			else
206 			if(a->type == D_FILE1)
207 				putsymb(a->asym->name, 'Z', a->aoffset, 0);
208 
209 		putsymb(s->name, 'T', s->value, s->version);
210 
211 		/* frame, auto and param after */
212 		putsymb(".frame", 'm', p->to.offset+4, 0);
213 
214 		for(a=p->to.autom; a; a=a->link)
215 			if(a->type == D_AUTO)
216 				putsymb(a->asym->name, 'a', -a->aoffset, 0);
217 			else
218 			if(a->type == D_PARAM)
219 				putsymb(a->asym->name, 'p', a->aoffset, 0);
220 	}
221 	if(debug['v'] || debug['n'])
222 		Bprint(&bso, "symsize = %lud\n", symsize);
223 	Bflush(&bso);
224 }
225 
226 void
227 asmlc(void)
228 {
229 	long oldpc, oldlc;
230 	Prog *p;
231 	long v, s;
232 
233 	oldpc = INITTEXT;
234 	oldlc = 0;
235 	for(p = firstp; p != P; p = p->link) {
236 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
237 			if(p->as == ATEXT)
238 				curtext = p;
239 			if(debug['V'])
240 				Bprint(&bso, "%6lux %P\n",
241 					p->pc, p);
242 			continue;
243 		}
244 		if(debug['V'])
245 			Bprint(&bso, "\t\t%6ld", lcsize);
246 		v = (p->pc - oldpc) / MINLC;
247 		while(v) {
248 			s = 127;
249 			if(v < 127)
250 				s = v;
251 			cput(s+128);	/* 129-255 +pc */
252 			if(debug['V'])
253 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
254 			v -= s;
255 			lcsize++;
256 		}
257 		s = p->line - oldlc;
258 		oldlc = p->line;
259 		oldpc = p->pc + MINLC;
260 		if(s > 64 || s < -64) {
261 			cput(0);	/* 0 vv +lc */
262 			cput(s>>24);
263 			cput(s>>16);
264 			cput(s>>8);
265 			cput(s);
266 			if(debug['V']) {
267 				if(s > 0)
268 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
269 						s, 0, s);
270 				else
271 					Bprint(&bso, " lc%ld(%d,%ld)\n",
272 						s, 0, s);
273 				Bprint(&bso, "%6lux %P\n",
274 					p->pc, p);
275 			}
276 			lcsize += 5;
277 			continue;
278 		}
279 		if(s > 0) {
280 			cput(0+s);	/* 1-64 +lc */
281 			if(debug['V']) {
282 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
283 				Bprint(&bso, "%6lux %P\n",
284 					p->pc, p);
285 			}
286 		} else {
287 			cput(64-s);	/* 65-128 -lc */
288 			if(debug['V']) {
289 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
290 				Bprint(&bso, "%6lux %P\n",
291 					p->pc, p);
292 			}
293 		}
294 		lcsize++;
295 	}
296 	while(lcsize & 1) {
297 		s = 129;
298 		cput(s);
299 		lcsize++;
300 	}
301 	if(debug['v'] || debug['V'])
302 		Bprint(&bso, "lcsize = %ld\n", lcsize);
303 	Bflush(&bso);
304 }
305 
306 int
307 prefixof(Adr *a)
308 {
309 	switch(a->type) {
310 	case D_INDIR+D_CS:
311 		return 0x2e;
312 	case D_INDIR+D_DS:
313 		return 0x3e;
314 	case D_INDIR+D_ES:
315 		return 0x26;
316 	case D_INDIR+D_FS:
317 		return 0x64;
318 	case D_INDIR+D_GS:
319 		return 0x65;
320 	}
321 	return 0;
322 }
323 
324 int
325 oclass(Adr *a)
326 {
327 	long v;
328 
329 	if(a->type >= D_INDIR || a->index != D_NONE) {
330 		if(a->index != D_NONE && a->scale == 0) {
331 			if(a->type == D_ADDR) {
332 				switch(a->index) {
333 				case D_EXTERN:
334 				case D_STATIC:
335 					return Yi32;
336 				case D_AUTO:
337 				case D_PARAM:
338 					return Yiauto;
339 				}
340 				return Yxxx;
341 			}
342 			return Ycol;
343 		}
344 		return Ym;
345 	}
346 	switch(a->type)
347 	{
348 	case D_AL:
349 		return Yal;
350 
351 	case D_AX:
352 		return Yax;
353 
354 	case D_CL:
355 		return Ycl;
356 
357 	case D_DL:
358 	case D_BL:
359 	case D_AH:
360 	case D_CH:
361 	case D_DH:
362 	case D_BH:
363 		return Yrb;
364 
365 	case D_CX:
366 		return Ycx;
367 
368 	case D_DX:
369 	case D_BX:
370 		return Yrx;
371 
372 	case D_SP:
373 	case D_BP:
374 	case D_SI:
375 	case D_DI:
376 		return Yrl;
377 
378 	case D_F0+0:
379 		return	Yf0;
380 
381 	case D_F0+1:
382 	case D_F0+2:
383 	case D_F0+3:
384 	case D_F0+4:
385 	case D_F0+5:
386 	case D_F0+6:
387 	case D_F0+7:
388 		return	Yrf;
389 
390 	case D_NONE:
391 		return Ynone;
392 
393 	case D_CS:	return	Ycs;
394 	case D_SS:	return	Yss;
395 	case D_DS:	return	Yds;
396 	case D_ES:	return	Yes;
397 	case D_FS:	return	Yfs;
398 	case D_GS:	return	Ygs;
399 
400 	case D_GDTR:	return	Ygdtr;
401 	case D_IDTR:	return	Yidtr;
402 	case D_LDTR:	return	Yldtr;
403 	case D_MSW:	return	Ymsw;
404 	case D_TASK:	return	Ytask;
405 
406 	case D_CR+0:	return	Ycr0;
407 	case D_CR+1:	return	Ycr1;
408 	case D_CR+2:	return	Ycr2;
409 	case D_CR+3:	return	Ycr3;
410 	case D_CR+4:	return	Ycr4;
411 	case D_CR+5:	return	Ycr5;
412 	case D_CR+6:	return	Ycr6;
413 	case D_CR+7:	return	Ycr7;
414 
415 	case D_DR+0:	return	Ydr0;
416 	case D_DR+1:	return	Ydr1;
417 	case D_DR+2:	return	Ydr2;
418 	case D_DR+3:	return	Ydr3;
419 	case D_DR+4:	return	Ydr4;
420 	case D_DR+5:	return	Ydr5;
421 	case D_DR+6:	return	Ydr6;
422 	case D_DR+7:	return	Ydr7;
423 
424 	case D_TR+0:	return	Ytr0;
425 	case D_TR+1:	return	Ytr1;
426 	case D_TR+2:	return	Ytr2;
427 	case D_TR+3:	return	Ytr3;
428 	case D_TR+4:	return	Ytr4;
429 	case D_TR+5:	return	Ytr5;
430 	case D_TR+6:	return	Ytr6;
431 	case D_TR+7:	return	Ytr7;
432 
433 	case D_EXTERN:
434 	case D_STATIC:
435 	case D_AUTO:
436 	case D_PARAM:
437 		return Ym;
438 
439 	case D_CONST:
440 	case D_ADDR:
441 		if(a->sym == S) {
442 			v = a->offset;
443 			if(v == 0)
444 				return Yi0;
445 			if(v == 1)
446 				return Yi1;
447 			if(v >= -128 && v <= 127)
448 				return Yi8;
449 		}
450 		return Yi32;
451 
452 	case D_BRANCH:
453 		return Ybr;
454 	}
455 	return Yxxx;
456 }
457 
458 void
459 asmidx(Adr *a, int base)
460 {
461 	int i;
462 
463 	switch(a->index) {
464 	default:
465 		goto bad;
466 
467 	case D_NONE:
468 		i = 4 << 3;
469 		goto bas;
470 
471 	case D_AX:
472 	case D_CX:
473 	case D_DX:
474 	case D_BX:
475 	case D_BP:
476 	case D_SI:
477 	case D_DI:
478 		i = reg[a->index] << 3;
479 		break;
480 	}
481 	switch(a->scale) {
482 	default:
483 		goto bad;
484 	case 1:
485 		break;
486 	case 2:
487 		i |= (1<<6);
488 		break;
489 	case 4:
490 		i |= (2<<6);
491 		break;
492 	case 8:
493 		i |= (3<<6);
494 		break;
495 	}
496 bas:
497 	switch(base) {
498 	default:
499 		goto bad;
500 	case D_NONE:	/* must be mod=00 */
501 		i |= 5;
502 		break;
503 	case D_AX:
504 	case D_CX:
505 	case D_DX:
506 	case D_BX:
507 	case D_SP:
508 	case D_BP:
509 	case D_SI:
510 	case D_DI:
511 		i |= reg[base];
512 		break;
513 	}
514 	*andptr++ = i;
515 	return;
516 bad:
517 	diag("asmidx: bad address %D", a);
518 	*andptr++ = 0;
519 	return;
520 }
521 
522 static void
523 put4(long v)
524 {
525 	if(dlm && curp != P && reloca != nil){
526 		dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
527 		reloca = nil;
528 	}
529 	andptr[0] = v;
530 	andptr[1] = v>>8;
531 	andptr[2] = v>>16;
532 	andptr[3] = v>>24;
533 	andptr += 4;
534 }
535 
536 long
537 vaddr(Adr *a)
538 {
539 	int t;
540 	long v;
541 	Sym *s;
542 
543 	t = a->type;
544 	v = a->offset;
545 	if(t == D_ADDR)
546 		t = a->index;
547 	switch(t) {
548 	case D_STATIC:
549 	case D_EXTERN:
550 		s = a->sym;
551 		if(s != nil) {
552 			if(dlm && curp != P)
553 				reloca = a;
554 			switch(s->type) {
555 			case SUNDEF:
556 				ckoff(s, v);
557 			case STEXT:
558 			case SCONST:
559 				v += s->value;
560 				break;
561 			default:
562 				v += INITDAT + s->value;
563 			}
564 		}
565 	}
566 	return v;
567 }
568 
569 void
570 asmand(Adr *a, int r)
571 {
572 	long v;
573 	int t;
574 	Adr aa;
575 
576 	v = a->offset;
577 	t = a->type;
578 	if(a->index != D_NONE) {
579 		if(t >= D_INDIR) {
580 			t -= D_INDIR;
581 			if(t == D_NONE) {
582 				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
583 				asmidx(a, t);
584 				put4(v);
585 				return;
586 			}
587 			if(v == 0 && t != D_BP) {
588 				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
589 				asmidx(a, t);
590 				return;
591 			}
592 			if(v >= -128 && v < 128) {
593 				*andptr++ = (1 << 6) | (4 << 0) | (r << 3);
594 				asmidx(a, t);
595 				*andptr++ = v;
596 				return;
597 			}
598 			*andptr++ = (2 << 6) | (4 << 0) | (r << 3);
599 			asmidx(a, t);
600 			put4(v);
601 			return;
602 		}
603 		switch(t) {
604 		default:
605 			goto bad;
606 		case D_STATIC:
607 		case D_EXTERN:
608 			aa.type = D_NONE+D_INDIR;
609 			break;
610 		case D_AUTO:
611 		case D_PARAM:
612 			aa.type = D_SP+D_INDIR;
613 			break;
614 		}
615 		aa.offset = vaddr(a);
616 		aa.index = a->index;
617 		aa.scale = a->scale;
618 		asmand(&aa, r);
619 		return;
620 	}
621 	if(t >= D_AL && t <= D_F0+7) {
622 		if(v)
623 			goto bad;
624 		*andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
625 		return;
626 	}
627 	if(t >= D_INDIR) {
628 		t -= D_INDIR;
629 		if(t == D_NONE || D_CS <= t && t <= D_GS) {
630 			*andptr++ = (0 << 6) | (5 << 0) | (r << 3);
631 			put4(v);
632 			return;
633 		}
634 		if(t == D_SP) {
635 			if(v == 0) {
636 				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
637 				asmidx(a, D_SP);
638 				return;
639 			}
640 			if(v >= -128 && v < 128) {
641 				*andptr++ = (1 << 6) | (4 << 0) | (r << 3);
642 				asmidx(a, D_SP);
643 				*andptr++ = v;
644 				return;
645 			}
646 			*andptr++ = (2 << 6) | (4 << 0) | (r << 3);
647 			asmidx(a, D_SP);
648 			put4(v);
649 			return;
650 		}
651 		if(t >= D_AX && t <= D_DI) {
652 			if(v == 0 && t != D_BP) {
653 				*andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
654 				return;
655 			}
656 			if(v >= -128 && v < 128) {
657 				andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
658 				andptr[1] = v;
659 				andptr += 2;
660 				return;
661 			}
662 			*andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
663 			put4(v);
664 			return;
665 		}
666 		goto bad;
667 	}
668 	switch(a->type) {
669 	default:
670 		goto bad;
671 	case D_STATIC:
672 	case D_EXTERN:
673 		aa.type = D_NONE+D_INDIR;
674 		break;
675 	case D_AUTO:
676 	case D_PARAM:
677 		aa.type = D_SP+D_INDIR;
678 		break;
679 	}
680 	aa.index = D_NONE;
681 	aa.scale = 1;
682 	aa.offset = vaddr(a);
683 	asmand(&aa, r);
684 	return;
685 bad:
686 	diag("asmand: bad address %D", a);
687 	return;
688 }
689 
690 #define	E	0xff
691 uchar	ymovtab[] =
692 {
693 /* push */
694 	APUSHL,	Ycs,	Ynone,	0,	0x0e,E,0,0,
695 	APUSHL,	Yss,	Ynone,	0,	0x16,E,0,0,
696 	APUSHL,	Yds,	Ynone,	0,	0x1e,E,0,0,
697 	APUSHL,	Yes,	Ynone,	0,	0x06,E,0,0,
698 	APUSHL,	Yfs,	Ynone,	0,	0x0f,0xa0,E,0,
699 	APUSHL,	Ygs,	Ynone,	0,	0x0f,0xa8,E,0,
700 
701 	APUSHW,	Ycs,	Ynone,	0,	Pe,0x0e,E,0,
702 	APUSHW,	Yss,	Ynone,	0,	Pe,0x16,E,0,
703 	APUSHW,	Yds,	Ynone,	0,	Pe,0x1e,E,0,
704 	APUSHW,	Yes,	Ynone,	0,	Pe,0x06,E,0,
705 	APUSHW,	Yfs,	Ynone,	0,	Pe,0x0f,0xa0,E,
706 	APUSHW,	Ygs,	Ynone,	0,	Pe,0x0f,0xa8,E,
707 
708 /* pop */
709 	APOPL,	Ynone,	Yds,	0,	0x1f,E,0,0,
710 	APOPL,	Ynone,	Yes,	0,	0x07,E,0,0,
711 	APOPL,	Ynone,	Yss,	0,	0x17,E,0,0,
712 	APOPL,	Ynone,	Yfs,	0,	0x0f,0xa1,E,0,
713 	APOPL,	Ynone,	Ygs,	0,	0x0f,0xa9,E,0,
714 
715 	APOPW,	Ynone,	Yds,	0,	Pe,0x1f,E,0,
716 	APOPW,	Ynone,	Yes,	0,	Pe,0x07,E,0,
717 	APOPW,	Ynone,	Yss,	0,	Pe,0x17,E,0,
718 	APOPW,	Ynone,	Yfs,	0,	Pe,0x0f,0xa1,E,
719 	APOPW,	Ynone,	Ygs,	0,	Pe,0x0f,0xa9,E,
720 
721 /* mov seg */
722 	AMOVW,	Yes,	Yml,	1,	0x8c,0,0,0,
723 	AMOVW,	Ycs,	Yml,	1,	0x8c,1,0,0,
724 	AMOVW,	Yss,	Yml,	1,	0x8c,2,0,0,
725 	AMOVW,	Yds,	Yml,	1,	0x8c,3,0,0,
726 	AMOVW,	Yfs,	Yml,	1,	0x8c,4,0,0,
727 	AMOVW,	Ygs,	Yml,	1,	0x8c,5,0,0,
728 
729 	AMOVW,	Yml,	Yes,	2,	0x8e,0,0,0,
730 	AMOVW,	Yml,	Ycs,	2,	0x8e,1,0,0,
731 	AMOVW,	Yml,	Yss,	2,	0x8e,2,0,0,
732 	AMOVW,	Yml,	Yds,	2,	0x8e,3,0,0,
733 	AMOVW,	Yml,	Yfs,	2,	0x8e,4,0,0,
734 	AMOVW,	Yml,	Ygs,	2,	0x8e,5,0,0,
735 
736 /* mov cr */
737 	AMOVL,	Ycr0,	Yml,	3,	0x0f,0x20,0,0,
738 	AMOVL,	Ycr2,	Yml,	3,	0x0f,0x20,2,0,
739 	AMOVL,	Ycr3,	Yml,	3,	0x0f,0x20,3,0,
740 	AMOVL,	Ycr4,	Yml,	3,	0x0f,0x20,4,0,
741 
742 	AMOVL,	Yml,	Ycr0,	4,	0x0f,0x22,0,0,
743 	AMOVL,	Yml,	Ycr2,	4,	0x0f,0x22,2,0,
744 	AMOVL,	Yml,	Ycr3,	4,	0x0f,0x22,3,0,
745 	AMOVL,	Yml,	Ycr4,	4,	0x0f,0x22,4,0,
746 
747 /* mov dr */
748 	AMOVL,	Ydr0,	Yml,	3,	0x0f,0x21,0,0,
749 	AMOVL,	Ydr6,	Yml,	3,	0x0f,0x21,6,0,
750 	AMOVL,	Ydr7,	Yml,	3,	0x0f,0x21,7,0,
751 
752 	AMOVL,	Yml,	Ydr0,	4,	0x0f,0x23,0,0,
753 	AMOVL,	Yml,	Ydr6,	4,	0x0f,0x23,6,0,
754 	AMOVL,	Yml,	Ydr7,	4,	0x0f,0x23,7,0,
755 
756 /* mov tr */
757 	AMOVL,	Ytr6,	Yml,	3,	0x0f,0x24,6,0,
758 	AMOVL,	Ytr7,	Yml,	3,	0x0f,0x24,7,0,
759 
760 	AMOVL,	Yml,	Ytr6,	4,	0x0f,0x26,6,E,
761 	AMOVL,	Yml,	Ytr7,	4,	0x0f,0x26,7,E,
762 
763 /* lgdt, sgdt, lidt, sidt */
764 	AMOVL,	Ym,	Ygdtr,	4,	0x0f,0x01,2,0,
765 	AMOVL,	Ygdtr,	Ym,	3,	0x0f,0x01,0,0,
766 	AMOVL,	Ym,	Yidtr,	4,	0x0f,0x01,3,0,
767 	AMOVL,	Yidtr,	Ym,	3,	0x0f,0x01,1,0,
768 
769 /* lldt, sldt */
770 	AMOVW,	Yml,	Yldtr,	4,	0x0f,0x00,2,0,
771 	AMOVW,	Yldtr,	Yml,	3,	0x0f,0x00,0,0,
772 
773 /* lmsw, smsw */
774 	AMOVW,	Yml,	Ymsw,	4,	0x0f,0x01,6,0,
775 	AMOVW,	Ymsw,	Yml,	3,	0x0f,0x01,4,0,
776 
777 /* ltr, str */
778 	AMOVW,	Yml,	Ytask,	4,	0x0f,0x00,3,0,
779 	AMOVW,	Ytask,	Yml,	3,	0x0f,0x00,1,0,
780 
781 /* load full pointer */
782 	AMOVL,	Yml,	Ycol,	5,	0,0,0,0,
783 	AMOVW,	Yml,	Ycol,	5,	Pe,0,0,0,
784 
785 /* double shift */
786 	ASHLL,	Ycol,	Yml,	6,	0xa4,0xa5,0,0,
787 	ASHRL,	Ycol,	Yml,	6,	0xac,0xad,0,0,
788 
789 /* extra imul */
790 	AIMULW,	Yml,	Yrl,	7,	Pq,0xaf,0,0,
791 	AIMULL,	Yml,	Yrl,	7,	Pm,0xaf,0,0,
792 	0
793 };
794 
795 int
796 isax(Adr *a)
797 {
798 
799 	switch(a->type) {
800 	case D_AX:
801 	case D_AL:
802 	case D_AH:
803 	case D_INDIR+D_AX:
804 		return 1;
805 	}
806 	if(a->index == D_AX)
807 		return 1;
808 	return 0;
809 }
810 
811 void
812 subreg(Prog *p, int from, int to)
813 {
814 
815 	if(debug['Q'])
816 		print("\n%P	s/%R/%R/\n", p, from, to);
817 
818 	if(p->from.type == from)
819 		p->from.type = to;
820 	if(p->to.type == from)
821 		p->to.type = to;
822 
823 	if(p->from.index == from)
824 		p->from.index = to;
825 	if(p->to.index == from)
826 		p->to.index = to;
827 
828 	from += D_INDIR;
829 	if(p->from.type == from)
830 		p->from.type = to+D_INDIR;
831 	if(p->to.type == from)
832 		p->to.type = to+D_INDIR;
833 
834 	if(debug['Q'])
835 		print("%P\n", p);
836 }
837 
838 void
839 doasm(Prog *p)
840 {
841 	Optab *o;
842 	Prog *q, pp;
843 	uchar *t;
844 	int z, op, ft, tt;
845 	long v, pre;
846 
847 	pre = prefixof(&p->from);
848 	if(pre)
849 		*andptr++ = pre;
850 	pre = prefixof(&p->to);
851 	if(pre)
852 		*andptr++ = pre;
853 
854 	o = &optab[p->as];
855 	ft = oclass(&p->from) * Ymax;
856 	tt = oclass(&p->to) * Ymax;
857 	t = o->ytab;
858 	if(t == 0) {
859 		diag("asmins: noproto %P", p);
860 		return;
861 	}
862 	for(z=0; *t; z+=t[3],t+=4)
863 		if(ycover[ft+t[0]])
864 		if(ycover[tt+t[1]])
865 			goto found;
866 	goto domov;
867 
868 found:
869 	switch(o->prefix) {
870 	case Pq:	/* 16 bit escape and opcode escape */
871 		*andptr++ = Pe;
872 		*andptr++ = Pm;
873 		break;
874 
875 	case Pm:	/* opcode escape */
876 		*andptr++ = Pm;
877 		break;
878 
879 	case Pe:	/* 16 bit escape */
880 		*andptr++ = Pe;
881 		break;
882 
883 	case Pb:	/* botch */
884 		break;
885 	}
886 	v = vaddr(&p->from);
887 	op = o->op[z];
888 	switch(t[2]) {
889 	default:
890 		diag("asmins: unknown z %d %P", t[2], p);
891 		return;
892 
893 	case Zpseudo:
894 		break;
895 
896 	case Zlit:
897 		for(; op = o->op[z]; z++)
898 			*andptr++ = op;
899 		break;
900 
901 	case Zm_r:
902 		*andptr++ = op;
903 		asmand(&p->from, reg[p->to.type]);
904 		break;
905 
906 	case Zaut_r:
907 		*andptr++ = 0x8d;	/* leal */
908 		if(p->from.type != D_ADDR)
909 			diag("asmins: Zaut sb type ADDR");
910 		p->from.type = p->from.index;
911 		p->from.index = D_NONE;
912 		asmand(&p->from, reg[p->to.type]);
913 		p->from.index = p->from.type;
914 		p->from.type = D_ADDR;
915 		break;
916 
917 	case Zm_o:
918 		*andptr++ = op;
919 		asmand(&p->from, o->op[z+1]);
920 		break;
921 
922 	case Zr_m:
923 		*andptr++ = op;
924 		asmand(&p->to, reg[p->from.type]);
925 		break;
926 
927 	case Zo_m:
928 		*andptr++ = op;
929 		asmand(&p->to, o->op[z+1]);
930 		break;
931 
932 	case Zm_ibo:
933 		v = vaddr(&p->to);
934 		*andptr++ = op;
935 		asmand(&p->from, o->op[z+1]);
936 		*andptr++ = v;
937 		break;
938 
939 	case Zibo_m:
940 		*andptr++ = op;
941 		asmand(&p->to, o->op[z+1]);
942 		*andptr++ = v;
943 		break;
944 
945 	case Z_ib:
946 		v = vaddr(&p->to);
947 	case Zib_:
948 		*andptr++ = op;
949 		*andptr++ = v;
950 		break;
951 
952 	case Zib_rp:
953 		*andptr++ = op + reg[p->to.type];
954 		*andptr++ = v;
955 		break;
956 
957 	case Zil_rp:
958 		*andptr++ = op + reg[p->to.type];
959 		if(o->prefix == Pe) {
960 			*andptr++ = v;
961 			*andptr++ = v>>8;
962 		}
963 		else
964 			put4(v);
965 		break;
966 
967 	case Zib_rr:
968 		*andptr++ = op;
969 		asmand(&p->to, reg[p->to.type]);
970 		*andptr++ = v;
971 		break;
972 
973 	case Z_il:
974 		v = vaddr(&p->to);
975 	case Zil_:
976 		*andptr++ = op;
977 		if(o->prefix == Pe) {
978 			*andptr++ = v;
979 			*andptr++ = v>>8;
980 		}
981 		else
982 			put4(v);
983 		break;
984 
985 	case Zm_ilo:
986 		v = vaddr(&p->to);
987 		*andptr++ = op;
988 		asmand(&p->from, o->op[z+1]);
989 		if(o->prefix == Pe) {
990 			*andptr++ = v;
991 			*andptr++ = v>>8;
992 		}
993 		else
994 			put4(v);
995 		break;
996 
997 	case Zilo_m:
998 		*andptr++ = op;
999 		asmand(&p->to, o->op[z+1]);
1000 		if(o->prefix == Pe) {
1001 			*andptr++ = v;
1002 			*andptr++ = v>>8;
1003 		}
1004 		else
1005 			put4(v);
1006 		break;
1007 
1008 	case Zil_rr:
1009 		*andptr++ = op;
1010 		asmand(&p->to, reg[p->to.type]);
1011 		if(o->prefix == Pe) {
1012 			*andptr++ = v;
1013 			*andptr++ = v>>8;
1014 		}
1015 		else
1016 			put4(v);
1017 		break;
1018 
1019 	case Z_rp:
1020 		*andptr++ = op + reg[p->to.type];
1021 		break;
1022 
1023 	case Zrp_:
1024 		*andptr++ = op + reg[p->from.type];
1025 		break;
1026 
1027 	case Zclr:
1028 		*andptr++ = op;
1029 		asmand(&p->to, reg[p->to.type]);
1030 		break;
1031 
1032 	case Zbr:
1033 		q = p->pcond;
1034 		if(q) {
1035 			v = q->pc - p->pc - 2;
1036 			if(v >= -128 && v <= 127) {
1037 				*andptr++ = op;
1038 				*andptr++ = v;
1039 			} else {
1040 				v -= 6-2;
1041 				*andptr++ = 0x0f;
1042 				*andptr++ = o->op[z+1];
1043 				*andptr++ = v;
1044 				*andptr++ = v>>8;
1045 				*andptr++ = v>>16;
1046 				*andptr++ = v>>24;
1047 			}
1048 		}
1049 		break;
1050 
1051 	case Zcall:
1052 		q = p->pcond;
1053 		if(q) {
1054 			v = q->pc - p->pc - 5;
1055 			if(dlm && curp != P && p->to.sym->type == SUNDEF){
1056 				/* v = 0 - p->pc - 5; */
1057 				v = 0;
1058 				ckoff(p->to.sym, v);
1059 				v += p->to.sym->value;
1060 				dynreloc(p->to.sym, p->pc+1, 0);
1061 			}
1062 			*andptr++ = op;
1063 			*andptr++ = v;
1064 			*andptr++ = v>>8;
1065 			*andptr++ = v>>16;
1066 			*andptr++ = v>>24;
1067 		}
1068 		break;
1069 
1070 	case Zjmp:
1071 		q = p->pcond;
1072 		if(q) {
1073 			v = q->pc - p->pc - 2;
1074 			if(v >= -128 && v <= 127) {
1075 				*andptr++ = op;
1076 				*andptr++ = v;
1077 			} else {
1078 				v -= 5-2;
1079 				*andptr++ = o->op[z+1];
1080 				*andptr++ = v;
1081 				*andptr++ = v>>8;
1082 				*andptr++ = v>>16;
1083 				*andptr++ = v>>24;
1084 			}
1085 		}
1086 		break;
1087 
1088 	case Zloop:
1089 		q = p->pcond;
1090 		if(q) {
1091 			v = q->pc - p->pc - 2;
1092 			if(v < -128 || v > 127)
1093 				diag("loop too far: %P", p);
1094 			*andptr++ = op;
1095 			*andptr++ = v;
1096 		}
1097 		break;
1098 
1099 	case Zbyte:
1100 		*andptr++ = v;
1101 		if(op > 1) {
1102 			*andptr++ = v>>8;
1103 			if(op > 2) {
1104 				*andptr++ = v>>16;
1105 				*andptr++ = v>>24;
1106 			}
1107 		}
1108 		break;
1109 
1110 	case Zmov:
1111 		goto domov;
1112 	}
1113 	return;
1114 
1115 domov:
1116 	for(t=ymovtab; *t; t+=8)
1117 		if(p->as == t[0])
1118 		if(ycover[ft+t[1]])
1119 		if(ycover[tt+t[2]])
1120 			goto mfound;
1121 bad:
1122 	/*
1123 	 * here, the assembly has failed.
1124 	 * if its a byte instruction that has
1125 	 * unaddressable registers, try to
1126 	 * exchange registers and reissue the
1127 	 * instruction with the operands renamed.
1128 	 */
1129 	pp = *p;
1130 	z = p->from.type;
1131 	if(z >= D_BP && z <= D_DI) {
1132 		if(isax(&p->to)) {
1133 			*andptr++ = 0x87;			/* xchg lhs,bx */
1134 			asmand(&p->from, reg[D_BX]);
1135 			subreg(&pp, z, D_BX);
1136 			doasm(&pp);
1137 			*andptr++ = 0x87;			/* xchg lhs,bx */
1138 			asmand(&p->from, reg[D_BX]);
1139 		} else {
1140 			*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
1141 			subreg(&pp, z, D_AX);
1142 			doasm(&pp);
1143 			*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
1144 		}
1145 		return;
1146 	}
1147 	z = p->to.type;
1148 	if(z >= D_BP && z <= D_DI) {
1149 		if(isax(&p->from)) {
1150 			*andptr++ = 0x87;			/* xchg rhs,bx */
1151 			asmand(&p->to, reg[D_BX]);
1152 			subreg(&pp, z, D_BX);
1153 			doasm(&pp);
1154 			*andptr++ = 0x87;			/* xchg rhs,bx */
1155 			asmand(&p->to, reg[D_BX]);
1156 		} else {
1157 			*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
1158 			subreg(&pp, z, D_AX);
1159 			doasm(&pp);
1160 			*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
1161 		}
1162 		return;
1163 	}
1164 	diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
1165 	return;
1166 
1167 mfound:
1168 	switch(t[3]) {
1169 	default:
1170 		diag("asmins: unknown mov %d %P", t[3], p);
1171 		break;
1172 
1173 	case 0:	/* lit */
1174 		for(z=4; t[z]!=E; z++)
1175 			*andptr++ = t[z];
1176 		break;
1177 
1178 	case 1:	/* r,m */
1179 		*andptr++ = t[4];
1180 		asmand(&p->to, t[5]);
1181 		break;
1182 
1183 	case 2:	/* m,r */
1184 		*andptr++ = t[4];
1185 		asmand(&p->from, t[5]);
1186 		break;
1187 
1188 	case 3:	/* r,m - 2op */
1189 		*andptr++ = t[4];
1190 		*andptr++ = t[5];
1191 		asmand(&p->to, t[6]);
1192 		break;
1193 
1194 	case 4:	/* m,r - 2op */
1195 		*andptr++ = t[4];
1196 		*andptr++ = t[5];
1197 		asmand(&p->from, t[6]);
1198 		break;
1199 
1200 	case 5:	/* load full pointer, trash heap */
1201 		if(t[4])
1202 			*andptr++ = t[4];
1203 		switch(p->to.index) {
1204 		default:
1205 			goto bad;
1206 		case D_DS:
1207 			*andptr++ = 0xc5;
1208 			break;
1209 		case D_SS:
1210 			*andptr++ = 0x0f;
1211 			*andptr++ = 0xb2;
1212 			break;
1213 		case D_ES:
1214 			*andptr++ = 0xc4;
1215 			break;
1216 		case D_FS:
1217 			*andptr++ = 0x0f;
1218 			*andptr++ = 0xb4;
1219 			break;
1220 		case D_GS:
1221 			*andptr++ = 0x0f;
1222 			*andptr++ = 0xb5;
1223 			break;
1224 		}
1225 		asmand(&p->from, reg[p->to.type]);
1226 		break;
1227 
1228 	case 6:	/* double shift */
1229 		z = p->from.type;
1230 		switch(z) {
1231 		default:
1232 			goto bad;
1233 		case D_CONST:
1234 			*andptr++ = 0x0f;
1235 			*andptr++ = t[4];
1236 			asmand(&p->to, reg[p->from.index]);
1237 			*andptr++ = p->from.offset;
1238 			break;
1239 		case D_CL:
1240 		case D_CX:
1241 			*andptr++ = 0x0f;
1242 			*andptr++ = t[5];
1243 			asmand(&p->to, reg[p->from.index]);
1244 			break;
1245 		}
1246 		break;
1247 
1248 	case 7: /* imul rm,r */
1249 		*andptr++ = t[4];
1250 		*andptr++ = t[5];
1251 		asmand(&p->from, reg[p->to.type]);
1252 		break;
1253 	}
1254 }
1255 
1256 void
1257 asmins(Prog *p)
1258 {
1259 
1260 	andptr = and;
1261 	doasm(p);
1262 }
1263 
1264 enum{
1265 	ABSD = 0,
1266 	ABSU = 1,
1267 	RELD = 2,
1268 	RELU = 3,
1269 };
1270 
1271 int modemap[4] = { 0, 1, -1, 2, };
1272 
1273 typedef struct Reloc Reloc;
1274 
1275 struct Reloc
1276 {
1277 	int n;
1278 	int t;
1279 	uchar *m;
1280 	ulong *a;
1281 };
1282 
1283 Reloc rels;
1284 
1285 static void
1286 grow(Reloc *r)
1287 {
1288 	int t;
1289 	uchar *m, *nm;
1290 	ulong *a, *na;
1291 
1292 	t = r->t;
1293 	r->t += 64;
1294 	m = r->m;
1295 	a = r->a;
1296 	r->m = nm = malloc(r->t*sizeof(uchar));
1297 	r->a = na = malloc(r->t*sizeof(ulong));
1298 	memmove(nm, m, t*sizeof(uchar));
1299 	memmove(na, a, t*sizeof(ulong));
1300 	free(m);
1301 	free(a);
1302 }
1303 
1304 void
1305 dynreloc(Sym *s, ulong v, int abs)
1306 {
1307 	int i, k, n;
1308 	uchar *m;
1309 	ulong *a;
1310 	Reloc *r;
1311 
1312 	if(s->type == SUNDEF)
1313 		k = abs ? ABSU : RELU;
1314 	else
1315 		k = abs ? ABSD : RELD;
1316 	/* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
1317 	k = modemap[k];
1318 	r = &rels;
1319 	n = r->n;
1320 	if(n >= r->t)
1321 		grow(r);
1322 	m = r->m;
1323 	a = r->a;
1324 	for(i = n; i > 0; i--){
1325 		if(v < a[i-1]){	/* happens occasionally for data */
1326 			m[i] = m[i-1];
1327 			a[i] = a[i-1];
1328 		}
1329 		else
1330 			break;
1331 	}
1332 	m[i] = k;
1333 	a[i] = v;
1334 	r->n++;
1335 }
1336 
1337 static int
1338 sput(char *s)
1339 {
1340 	char *p;
1341 
1342 	p = s;
1343 	while(*s)
1344 		cput(*s++);
1345 	cput(0);
1346 	return s-p+1;
1347 }
1348 
1349 void
1350 asmdyn()
1351 {
1352 	int i, n, t, c;
1353 	Sym *s;
1354 	ulong la, ra, *a;
1355 	vlong off;
1356 	uchar *m;
1357 	Reloc *r;
1358 
1359 	cflush();
1360 	off = seek(cout, 0, 1);
1361 	lput(0);
1362 	t = 0;
1363 	lput(imports);
1364 	t += 4;
1365 	for(i = 0; i < NHASH; i++)
1366 		for(s = hash[i]; s != S; s = s->link)
1367 			if(s->type == SUNDEF){
1368 				lput(s->sig);
1369 				t += 4;
1370 				t += sput(s->name);
1371 			}
1372 
1373 	la = 0;
1374 	r = &rels;
1375 	n = r->n;
1376 	m = r->m;
1377 	a = r->a;
1378 	lput(n);
1379 	t += 4;
1380 	for(i = 0; i < n; i++){
1381 		ra = *a-la;
1382 		if(*a < la)
1383 			diag("bad relocation order");
1384 		if(ra < 256)
1385 			c = 0;
1386 		else if(ra < 65536)
1387 			c = 1;
1388 		else
1389 			c = 2;
1390 		cput((c<<6)|*m++);
1391 		t++;
1392 		if(c == 0){
1393 			cput(ra);
1394 			t++;
1395 		}
1396 		else if(c == 1){
1397 			wput(ra);
1398 			t += 2;
1399 		}
1400 		else{
1401 			lput(ra);
1402 			t += 4;
1403 		}
1404 		la = *a++;
1405 	}
1406 
1407 	cflush();
1408 	seek(cout, off, 0);
1409 	lput(t);
1410 
1411 	if(debug['v']){
1412 		Bprint(&bso, "import table entries = %d\n", imports);
1413 		Bprint(&bso, "export table entries = %d\n", exports);
1414 	}
1415 }
1416