]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/8l/span.c
kbdfs: simplfy
[plan9front.git] / sys / src / cmd / 8l / span.c
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['L'])
240                                 Bprint(&bso, "%6lux %P\n",
241                                         p->pc, p);
242                         continue;
243                 }
244                 if(debug['L'])
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['L'])
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['L']) {
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['L']) {
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['L']) {
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['L'])
302                 Bprint(&bso, "lcsize = %ld\n", lcsize);
303         Bflush(&bso);
304 }
305
306 int
307 oclass(Adr *a)
308 {
309         long v;
310
311         if(a->type >= D_INDIR || a->index != D_NONE) {
312                 if(a->index != D_NONE && a->scale == 0) {
313                         if(a->type == D_ADDR) {
314                                 switch(a->index) {
315                                 case D_EXTERN:
316                                 case D_STATIC:
317                                         return Yi32;
318                                 case D_AUTO:
319                                 case D_PARAM:
320                                         return Yiauto;
321                                 }
322                                 return Yxxx;
323                         }
324                         return Ycol;
325                 }
326                 return Ym;
327         }
328         switch(a->type)
329         {
330         case D_AL:
331                 return Yal;
332
333         case D_AX:
334                 return Yax;
335
336         case D_CL:
337         case D_DL:
338         case D_BL:
339         case D_AH:
340         case D_CH:
341         case D_DH:
342         case D_BH:
343                 return Yrb;
344
345         case D_CX:
346                 return Ycx;
347
348         case D_DX:
349         case D_BX:
350                 return Yrx;
351
352         case D_SP:
353         case D_BP:
354         case D_SI:
355         case D_DI:
356                 return Yrl;
357
358         case D_F0+0:
359                 return  Yf0;
360
361         case D_F0+1:
362         case D_F0+2:
363         case D_F0+3:
364         case D_F0+4:
365         case D_F0+5:
366         case D_F0+6:
367         case D_F0+7:
368                 return  Yrf;
369
370         case D_NONE:
371                 return Ynone;
372
373         case D_CS:      return  Ycs;
374         case D_SS:      return  Yss;
375         case D_DS:      return  Yds;
376         case D_ES:      return  Yes;
377         case D_FS:      return  Yfs;
378         case D_GS:      return  Ygs;
379
380         case D_GDTR:    return  Ygdtr;
381         case D_IDTR:    return  Yidtr;
382         case D_LDTR:    return  Yldtr;
383         case D_MSW:     return  Ymsw;
384         case D_TASK:    return  Ytask;
385
386         case D_CR+0:    return  Ycr0;
387         case D_CR+1:    return  Ycr1;
388         case D_CR+2:    return  Ycr2;
389         case D_CR+3:    return  Ycr3;
390         case D_CR+4:    return  Ycr4;
391         case D_CR+5:    return  Ycr5;
392         case D_CR+6:    return  Ycr6;
393         case D_CR+7:    return  Ycr7;
394
395         case D_DR+0:    return  Ydr0;
396         case D_DR+1:    return  Ydr1;
397         case D_DR+2:    return  Ydr2;
398         case D_DR+3:    return  Ydr3;
399         case D_DR+4:    return  Ydr4;
400         case D_DR+5:    return  Ydr5;
401         case D_DR+6:    return  Ydr6;
402         case D_DR+7:    return  Ydr7;
403
404         case D_TR+0:    return  Ytr0;
405         case D_TR+1:    return  Ytr1;
406         case D_TR+2:    return  Ytr2;
407         case D_TR+3:    return  Ytr3;
408         case D_TR+4:    return  Ytr4;
409         case D_TR+5:    return  Ytr5;
410         case D_TR+6:    return  Ytr6;
411         case D_TR+7:    return  Ytr7;
412
413         case D_EXTERN:
414         case D_STATIC:
415         case D_AUTO:
416         case D_PARAM:
417                 return Ym;
418
419         case D_CONST:
420         case D_ADDR:
421                 if(a->sym == S) {
422                         v = a->offset;
423                         if(v == 0)
424                                 return Yi0;
425                         if(v == 1)
426                                 return Yi1;
427                         if(v >= -128 && v <= 127)
428                                 return Yi8;
429                 }
430                 return Yi32;
431
432         case D_BRANCH:
433                 return Ybr;
434         }
435         return Yxxx;
436 }
437
438 void
439 asmidx(Adr *a, int base)
440 {
441         int i;
442
443         switch(a->index) {
444         default:
445                 goto bad;
446
447         case D_NONE:
448                 i = 4 << 3;
449                 goto bas;
450
451         case D_AX:
452         case D_CX:
453         case D_DX:
454         case D_BX:
455         case D_BP:
456         case D_SI:
457         case D_DI:
458                 i = reg[a->index] << 3;
459                 break;
460         }
461         switch(a->scale) {
462         default:
463                 goto bad;
464         case 1:
465                 break;
466         case 2:
467                 i |= (1<<6);
468                 break;
469         case 4:
470                 i |= (2<<6);
471                 break;
472         case 8:
473                 i |= (3<<6);
474                 break;
475         }
476 bas:
477         switch(base) {
478         default:
479                 goto bad;
480         case D_NONE:    /* must be mod=00 */
481                 i |= 5;
482                 break;
483         case D_AX:
484         case D_CX:
485         case D_DX:
486         case D_BX:
487         case D_SP:
488         case D_BP:
489         case D_SI:
490         case D_DI:
491                 i |= reg[base];
492                 break;
493         }
494         *andptr++ = i;
495         return;
496 bad:
497         diag("asmidx: bad address %D", a);
498         *andptr++ = 0;
499         return;
500 }
501
502 static void
503 put4(long v)
504 {
505         if(dlm && curp != P && reloca != nil){
506                 dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
507                 reloca = nil;
508         }
509         andptr[0] = v;
510         andptr[1] = v>>8;
511         andptr[2] = v>>16;
512         andptr[3] = v>>24;
513         andptr += 4;
514 }
515
516 long
517 vaddr(Adr *a)
518 {
519         int t;
520         long v;
521         Sym *s;
522
523         t = a->type;
524         v = a->offset;
525         if(t == D_ADDR)
526                 t = a->index;
527         switch(t) {
528         case D_STATIC:
529         case D_EXTERN:
530                 s = a->sym;
531                 if(s != nil) {
532                         if(dlm && curp != P)
533                                 reloca = a;
534                         switch(s->type) {
535                         case SUNDEF:
536                                 ckoff(s, v);
537                         case STEXT:
538                         case SCONST:
539                                 v += s->value;
540                                 break;
541                         default:
542                                 v += INITDAT + s->value;
543                         }
544                 }
545         }
546         return v;
547 }
548
549 void
550 asmand(Adr *a, int r)
551 {
552         long v;
553         int t;
554         Adr aa;
555
556         v = a->offset;
557         t = a->type;
558         if(a->index != D_NONE) {
559                 if(t >= D_INDIR) {
560                         t -= D_INDIR;
561                         if(t == D_NONE) {
562                                 *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
563                                 asmidx(a, t);
564                                 put4(v);
565                                 return;
566                         }
567                         if(v == 0 && t != D_BP) {
568                                 *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
569                                 asmidx(a, t);
570                                 return;
571                         }
572                         if(v >= -128 && v < 128) {
573                                 *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
574                                 asmidx(a, t);
575                                 *andptr++ = v;
576                                 return;
577                         }
578                         *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
579                         asmidx(a, t);
580                         put4(v);
581                         return;
582                 }
583                 switch(t) {
584                 default:
585                         goto bad;
586                 case D_STATIC:
587                 case D_EXTERN:
588                         aa.type = D_NONE+D_INDIR;
589                         break;
590                 case D_AUTO:
591                 case D_PARAM:
592                         aa.type = D_SP+D_INDIR;
593                         break;
594                 }
595                 aa.offset = vaddr(a);
596                 aa.index = a->index;
597                 aa.scale = a->scale;
598                 asmand(&aa, r);
599                 return;
600         }
601         if(t >= D_AL && t <= D_F0+7) {
602                 if(v)
603                         goto bad;
604                 *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
605                 return;
606         }
607         if(t >= D_INDIR) {
608                 t -= D_INDIR;
609                 if(t == D_NONE) {
610                         *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
611                         put4(v);
612                         return;
613                 }
614                 if(t == D_SP) {
615                         if(v == 0) {
616                                 *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
617                                 asmidx(a, D_SP);
618                                 return;
619                         }
620                         if(v >= -128 && v < 128) {
621                                 *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
622                                 asmidx(a, D_SP);
623                                 *andptr++ = v;
624                                 return;
625                         }
626                         *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
627                         asmidx(a, D_SP);
628                         put4(v);
629                         return;
630                 }
631                 if(t >= D_AX && t <= D_DI) {
632                         if(v == 0 && t != D_BP) {
633                                 *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
634                                 return;
635                         }
636                         if(v >= -128 && v < 128) {
637                                 andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
638                                 andptr[1] = v;
639                                 andptr += 2;
640                                 return;
641                         }
642                         *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
643                         put4(v);
644                         return;
645                 }
646                 goto bad;
647         }
648         switch(a->type) {
649         default:
650                 goto bad;
651         case D_STATIC:
652         case D_EXTERN:
653                 aa.type = D_NONE+D_INDIR;
654                 break;
655         case D_AUTO:
656         case D_PARAM:
657                 aa.type = D_SP+D_INDIR;
658                 break;
659         }
660         aa.index = D_NONE;
661         aa.scale = 1;
662         aa.offset = vaddr(a);
663         asmand(&aa, r);
664         return;
665 bad:
666         diag("asmand: bad address %D", a);
667         return;
668 }
669
670 #define E       0xff
671 uchar   ymovtab[] =
672 {
673 /* push */
674         APUSHL, Ycs,    Ynone,  0,      0x0e,E,0,0,
675         APUSHL, Yss,    Ynone,  0,      0x16,E,0,0,
676         APUSHL, Yds,    Ynone,  0,      0x1e,E,0,0,
677         APUSHL, Yes,    Ynone,  0,      0x06,E,0,0,
678         APUSHL, Yfs,    Ynone,  0,      0x0f,0xa0,E,0,
679         APUSHL, Ygs,    Ynone,  0,      0x0f,0xa8,E,0,
680
681         APUSHW, Ycs,    Ynone,  0,      Pe,0x0e,E,0,
682         APUSHW, Yss,    Ynone,  0,      Pe,0x16,E,0,
683         APUSHW, Yds,    Ynone,  0,      Pe,0x1e,E,0,
684         APUSHW, Yes,    Ynone,  0,      Pe,0x06,E,0,
685         APUSHW, Yfs,    Ynone,  0,      Pe,0x0f,0xa0,E,
686         APUSHW, Ygs,    Ynone,  0,      Pe,0x0f,0xa8,E,
687
688 /* pop */
689         APOPL,  Ynone,  Yds,    0,      0x1f,E,0,0,
690         APOPL,  Ynone,  Yes,    0,      0x07,E,0,0,
691         APOPL,  Ynone,  Yss,    0,      0x17,E,0,0,
692         APOPL,  Ynone,  Yfs,    0,      0x0f,0xa1,E,0,
693         APOPL,  Ynone,  Ygs,    0,      0x0f,0xa9,E,0,
694
695         APOPW,  Ynone,  Yds,    0,      Pe,0x1f,E,0,
696         APOPW,  Ynone,  Yes,    0,      Pe,0x07,E,0,
697         APOPW,  Ynone,  Yss,    0,      Pe,0x17,E,0,
698         APOPW,  Ynone,  Yfs,    0,      Pe,0x0f,0xa1,E,
699         APOPW,  Ynone,  Ygs,    0,      Pe,0x0f,0xa9,E,
700
701 /* mov seg */
702         AMOVW,  Yes,    Yml,    1,      0x8c,0,0,0,
703         AMOVW,  Ycs,    Yml,    1,      0x8c,1,0,0,
704         AMOVW,  Yss,    Yml,    1,      0x8c,2,0,0,
705         AMOVW,  Yds,    Yml,    1,      0x8c,3,0,0,
706         AMOVW,  Yfs,    Yml,    1,      0x8c,4,0,0,
707         AMOVW,  Ygs,    Yml,    1,      0x8c,5,0,0,
708
709         AMOVW,  Yml,    Yes,    2,      0x8e,0,0,0,
710         AMOVW,  Yml,    Ycs,    2,      0x8e,1,0,0,
711         AMOVW,  Yml,    Yss,    2,      0x8e,2,0,0,
712         AMOVW,  Yml,    Yds,    2,      0x8e,3,0,0,
713         AMOVW,  Yml,    Yfs,    2,      0x8e,4,0,0,
714         AMOVW,  Yml,    Ygs,    2,      0x8e,5,0,0,
715
716 /* mov cr */
717         AMOVL,  Ycr0,   Yml,    3,      0x0f,0x20,0,0,
718         AMOVL,  Ycr2,   Yml,    3,      0x0f,0x20,2,0,
719         AMOVL,  Ycr3,   Yml,    3,      0x0f,0x20,3,0,
720         AMOVL,  Ycr4,   Yml,    3,      0x0f,0x20,4,0,
721
722         AMOVL,  Yml,    Ycr0,   4,      0x0f,0x22,0,0,
723         AMOVL,  Yml,    Ycr2,   4,      0x0f,0x22,2,0,
724         AMOVL,  Yml,    Ycr3,   4,      0x0f,0x22,3,0,
725         AMOVL,  Yml,    Ycr4,   4,      0x0f,0x22,4,0,
726
727 /* mov dr */
728         AMOVL,  Ydr0,   Yml,    3,      0x0f,0x21,0,0,
729         AMOVL,  Ydr6,   Yml,    3,      0x0f,0x21,6,0,
730         AMOVL,  Ydr7,   Yml,    3,      0x0f,0x21,7,0,
731
732         AMOVL,  Yml,    Ydr0,   4,      0x0f,0x23,0,0,
733         AMOVL,  Yml,    Ydr6,   4,      0x0f,0x23,6,0,
734         AMOVL,  Yml,    Ydr7,   4,      0x0f,0x23,7,0,
735
736 /* mov tr */
737         AMOVL,  Ytr6,   Yml,    3,      0x0f,0x24,6,0,
738         AMOVL,  Ytr7,   Yml,    3,      0x0f,0x24,7,0,
739
740         AMOVL,  Yml,    Ytr6,   4,      0x0f,0x26,6,E,
741         AMOVL,  Yml,    Ytr7,   4,      0x0f,0x26,7,E,
742
743 /* lgdt, sgdt, lidt, sidt */
744         AMOVL,  Ym,     Ygdtr,  4,      0x0f,0x01,2,0,
745         AMOVL,  Ygdtr,  Ym,     3,      0x0f,0x01,0,0,
746         AMOVL,  Ym,     Yidtr,  4,      0x0f,0x01,3,0,
747         AMOVL,  Yidtr,  Ym,     3,      0x0f,0x01,1,0,
748
749 /* lldt, sldt */
750         AMOVW,  Yml,    Yldtr,  4,      0x0f,0x00,2,0,
751         AMOVW,  Yldtr,  Yml,    3,      0x0f,0x00,0,0,
752
753 /* lmsw, smsw */
754         AMOVW,  Yml,    Ymsw,   4,      0x0f,0x01,6,0,
755         AMOVW,  Ymsw,   Yml,    3,      0x0f,0x01,4,0,
756
757 /* ltr, str */
758         AMOVW,  Yml,    Ytask,  4,      0x0f,0x00,3,0,
759         AMOVW,  Ytask,  Yml,    3,      0x0f,0x00,1,0,
760
761 /* load full pointer */
762         AMOVL,  Yml,    Ycol,   5,      0,0,0,0,
763         AMOVW,  Yml,    Ycol,   5,      Pe,0,0,0,
764
765 /* double shift */
766         ASHLL,  Ycol,   Yml,    6,      0xa4,0xa5,0,0,
767         ASHRL,  Ycol,   Yml,    6,      0xac,0xad,0,0,
768
769 /* extra imul */
770         AIMULL, Yml,    Yrl,    7,      Pm,0xaf,0,0,
771         0
772 };
773
774 int
775 isax(Adr *a)
776 {
777
778         switch(a->type) {
779         case D_AX:
780         case D_AL:
781         case D_AH:
782         case D_INDIR+D_AX:
783                 return 1;
784         }
785         if(a->index == D_AX)
786                 return 1;
787         return 0;
788 }
789
790 void
791 subreg(Prog *p, int from, int to)
792 {
793
794         if(debug['Q'])
795                 print("\n%P     s/%R/%R/\n", p, from, to);
796
797         if(p->from.type == from)
798                 p->from.type = to;
799         if(p->to.type == from)
800                 p->to.type = to;
801
802         if(p->from.index == from)
803                 p->from.index = to;
804         if(p->to.index == from)
805                 p->to.index = to;
806
807         from += D_INDIR;
808         if(p->from.type == from)
809                 p->from.type = to+D_INDIR;
810         if(p->to.type == from)
811                 p->to.type = to+D_INDIR;
812
813         if(debug['Q'])
814                 print("%P\n", p);
815 }
816
817 void
818 doasm(Prog *p)
819 {
820         Optab *o;
821         Prog *q, pp;
822         uchar *t;
823         int z, op, ft, tt;
824         long v;
825
826         o = &optab[p->as];
827         ft = oclass(&p->from) * Ymax;
828         tt = oclass(&p->to) * Ymax;
829         t = o->ytab;
830         if(t == 0) {
831                 diag("asmins: noproto %P", p);
832                 return;
833         }
834         for(z=0; *t; z+=t[3],t+=4)
835                 if(ycover[ft+t[0]])
836                 if(ycover[tt+t[1]])
837                         goto found;
838         goto domov;
839
840 found:
841         switch(o->prefix) {
842         case Pq:        /* 16 bit escape and opcode escape */
843                 *andptr++ = Pe;
844                 *andptr++ = Pm;
845                 break;
846
847         case Pm:        /* opcode escape */
848                 *andptr++ = Pm;
849                 break;
850
851         case Pe:        /* 16 bit escape */
852                 *andptr++ = Pe;
853                 break;
854
855         case Pb:        /* botch */
856                 break;
857         }
858         v = vaddr(&p->from);
859         op = o->op[z];
860         switch(t[2]) {
861         default:
862                 diag("asmins: unknown z %d %P", t[2], p);
863                 return;
864
865         case Zpseudo:
866                 break;
867
868         case Zlit:
869                 for(; op = o->op[z]; z++)
870                         *andptr++ = op;
871                 break;
872
873         case Zm_r:
874                 *andptr++ = op;
875                 asmand(&p->from, reg[p->to.type]);
876                 break;
877
878         case Zaut_r:
879                 *andptr++ = 0x8d;       /* leal */
880                 if(p->from.type != D_ADDR)
881                         diag("asmins: Zaut sb type ADDR");
882                 p->from.type = p->from.index;
883                 p->from.index = D_NONE;
884                 asmand(&p->from, reg[p->to.type]);
885                 p->from.index = p->from.type;
886                 p->from.type = D_ADDR;
887                 break;
888
889         case Zm_o:
890                 *andptr++ = op;
891                 asmand(&p->from, o->op[z+1]);
892                 break;
893
894         case Zr_m:
895                 *andptr++ = op;
896                 asmand(&p->to, reg[p->from.type]);
897                 break;
898
899         case Zo_m:
900                 *andptr++ = op;
901                 asmand(&p->to, o->op[z+1]);
902                 break;
903
904         case Zm_ibo:
905                 v = vaddr(&p->to);
906                 *andptr++ = op;
907                 asmand(&p->from, o->op[z+1]);
908                 *andptr++ = v;
909                 break;
910
911         case Zibo_m:
912                 *andptr++ = op;
913                 asmand(&p->to, o->op[z+1]);
914                 *andptr++ = v;
915                 break;
916
917         case Z_ib:
918                 v = vaddr(&p->to);
919         case Zib_:
920                 *andptr++ = op;
921                 *andptr++ = v;
922                 break;
923
924         case Zib_rp:
925                 *andptr++ = op + reg[p->to.type];
926                 *andptr++ = v;
927                 break;
928
929         case Zil_rp:
930                 *andptr++ = op + reg[p->to.type];
931                 if(o->prefix == Pe) {
932                         *andptr++ = v;
933                         *andptr++ = v>>8;
934                 }
935                 else
936                         put4(v);
937                 break;
938
939         case Zib_rr:
940                 *andptr++ = op;
941                 asmand(&p->to, reg[p->to.type]);
942                 *andptr++ = v;
943                 break;
944
945         case Z_il:
946                 v = vaddr(&p->to);
947         case Zil_:
948                 *andptr++ = op;
949                 if(o->prefix == Pe) {
950                         *andptr++ = v;
951                         *andptr++ = v>>8;
952                 }
953                 else
954                         put4(v);
955                 break;
956
957         case Zm_ilo:
958                 v = vaddr(&p->to);
959                 *andptr++ = op;
960                 asmand(&p->from, o->op[z+1]);
961                 if(o->prefix == Pe) {
962                         *andptr++ = v;
963                         *andptr++ = v>>8;
964                 }
965                 else
966                         put4(v);
967                 break;
968
969         case Zilo_m:
970                 *andptr++ = op;
971                 asmand(&p->to, o->op[z+1]);
972                 if(o->prefix == Pe) {
973                         *andptr++ = v;
974                         *andptr++ = v>>8;
975                 }
976                 else
977                         put4(v);
978                 break;
979
980         case Zil_rr:
981                 *andptr++ = op;
982                 asmand(&p->to, reg[p->to.type]);
983                 if(o->prefix == Pe) {
984                         *andptr++ = v;
985                         *andptr++ = v>>8;
986                 }
987                 else
988                         put4(v);
989                 break;
990
991         case Z_rp:
992                 *andptr++ = op + reg[p->to.type];
993                 break;
994
995         case Zrp_:
996                 *andptr++ = op + reg[p->from.type];
997                 break;
998
999         case Zclr:
1000                 *andptr++ = op;
1001                 asmand(&p->to, reg[p->to.type]);
1002                 break;
1003
1004         case Zbr:
1005                 q = p->pcond;
1006                 if(q) {
1007                         v = q->pc - p->pc - 2;
1008                         if(v >= -128 && v <= 127) {
1009                                 *andptr++ = op;
1010                                 *andptr++ = v;
1011                         } else {
1012                                 v -= 6-2;
1013                                 *andptr++ = 0x0f;
1014                                 *andptr++ = o->op[z+1];
1015                                 *andptr++ = v;
1016                                 *andptr++ = v>>8;
1017                                 *andptr++ = v>>16;
1018                                 *andptr++ = v>>24;
1019                         }
1020                 }
1021                 break;
1022
1023         case Zcall:
1024                 q = p->pcond;
1025                 if(q) {
1026                         v = q->pc - p->pc - 5;
1027                         if(dlm && curp != P && p->to.sym->type == SUNDEF){
1028                                 /* v = 0 - p->pc - 5; */
1029                                 v = 0;
1030                                 ckoff(p->to.sym, v);
1031                                 v += p->to.sym->value;
1032                                 dynreloc(p->to.sym, p->pc+1, 0);
1033                         }
1034                         *andptr++ = op;
1035                         *andptr++ = v;
1036                         *andptr++ = v>>8;
1037                         *andptr++ = v>>16;
1038                         *andptr++ = v>>24;
1039                 }
1040                 break;
1041
1042         case Zjmp:
1043                 q = p->pcond;
1044                 if(q) {
1045                         v = q->pc - p->pc - 2;
1046                         if(v >= -128 && v <= 127) {
1047                                 *andptr++ = op;
1048                                 *andptr++ = v;
1049                         } else {
1050                                 v -= 5-2;
1051                                 *andptr++ = o->op[z+1];
1052                                 *andptr++ = v;
1053                                 *andptr++ = v>>8;
1054                                 *andptr++ = v>>16;
1055                                 *andptr++ = v>>24;
1056                         }
1057                 }
1058                 break;
1059
1060         case Zloop:
1061                 q = p->pcond;
1062                 if(q) {
1063                         v = q->pc - p->pc - 2;
1064                         if(v < -128 && v > 127)
1065                                 diag("loop too far: %P", p);
1066                         *andptr++ = op;
1067                         *andptr++ = v;
1068                 }
1069                 break;
1070
1071         case Zbyte:
1072                 *andptr++ = v;
1073                 if(op > 1) {
1074                         *andptr++ = v>>8;
1075                         if(op > 2) {
1076                                 *andptr++ = v>>16;
1077                                 *andptr++ = v>>24;
1078                         }
1079                 }
1080                 break;
1081
1082         case Zmov:
1083                 goto domov;
1084         }
1085         return;
1086
1087 domov:
1088         for(t=ymovtab; *t; t+=8)
1089                 if(p->as == t[0])
1090                 if(ycover[ft+t[1]])
1091                 if(ycover[tt+t[2]])
1092                         goto mfound;
1093 bad:
1094         /*
1095          * here, the assembly has failed.
1096          * if its a byte instruction that has
1097          * unaddressable registers, try to
1098          * exchange registers and reissue the
1099          * instruction with the operands renamed.
1100          */
1101         pp = *p;
1102         z = p->from.type;
1103         if(z >= D_BP && z <= D_DI) {
1104                 if(isax(&p->to)) {
1105                         *andptr++ = 0x87;                       /* xchg lhs,bx */
1106                         asmand(&p->from, reg[D_BX]);
1107                         subreg(&pp, z, D_BX);
1108                         doasm(&pp);
1109                         *andptr++ = 0x87;                       /* xchg lhs,bx */
1110                         asmand(&p->from, reg[D_BX]);
1111                 } else {
1112                         *andptr++ = 0x90 + reg[z];              /* xchg lsh,ax */
1113                         subreg(&pp, z, D_AX);
1114                         doasm(&pp);
1115                         *andptr++ = 0x90 + reg[z];              /* xchg lsh,ax */
1116                 }
1117                 return;
1118         }
1119         z = p->to.type;
1120         if(z >= D_BP && z <= D_DI) {
1121                 if(isax(&p->from)) {
1122                         *andptr++ = 0x87;                       /* xchg rhs,bx */
1123                         asmand(&p->to, reg[D_BX]);
1124                         subreg(&pp, z, D_BX);
1125                         doasm(&pp);
1126                         *andptr++ = 0x87;                       /* xchg rhs,bx */
1127                         asmand(&p->to, reg[D_BX]);
1128                 } else {
1129                         *andptr++ = 0x90 + reg[z];              /* xchg rsh,ax */
1130                         subreg(&pp, z, D_AX);
1131                         doasm(&pp);
1132                         *andptr++ = 0x90 + reg[z];              /* xchg rsh,ax */
1133                 }
1134                 return;
1135         }
1136         diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
1137         return;
1138
1139 mfound:
1140         switch(t[3]) {
1141         default:
1142                 diag("asmins: unknown mov %d %P", t[3], p);
1143                 break;
1144
1145         case 0: /* lit */
1146                 for(z=4; t[z]!=E; z++)
1147                         *andptr++ = t[z];
1148                 break;
1149
1150         case 1: /* r,m */
1151                 *andptr++ = t[4];
1152                 asmand(&p->to, t[5]);
1153                 break;
1154
1155         case 2: /* m,r */
1156                 *andptr++ = t[4];
1157                 asmand(&p->from, t[5]);
1158                 break;
1159
1160         case 3: /* r,m - 2op */
1161                 *andptr++ = t[4];
1162                 *andptr++ = t[5];
1163                 asmand(&p->to, t[6]);
1164                 break;
1165
1166         case 4: /* m,r - 2op */
1167                 *andptr++ = t[4];
1168                 *andptr++ = t[5];
1169                 asmand(&p->from, t[6]);
1170                 break;
1171
1172         case 5: /* load full pointer, trash heap */
1173                 if(t[4])
1174                         *andptr++ = t[4];
1175                 switch(p->to.index) {
1176                 default:
1177                         goto bad;
1178                 case D_DS:
1179                         *andptr++ = 0xc5;
1180                         break;
1181                 case D_SS:
1182                         *andptr++ = 0x0f;
1183                         *andptr++ = 0xb2;
1184                         break;
1185                 case D_ES:
1186                         *andptr++ = 0xc4;
1187                         break;
1188                 case D_FS:
1189                         *andptr++ = 0x0f;
1190                         *andptr++ = 0xb4;
1191                         break;
1192                 case D_GS:
1193                         *andptr++ = 0x0f;
1194                         *andptr++ = 0xb5;
1195                         break;
1196                 }
1197                 asmand(&p->from, reg[p->to.type]);
1198                 break;
1199
1200         case 6: /* double shift */
1201                 z = p->from.type;
1202                 switch(z) {
1203                 default:
1204                         goto bad;
1205                 case D_CONST:
1206                         *andptr++ = 0x0f;
1207                         *andptr++ = t[4];
1208                         asmand(&p->to, reg[p->from.index]);
1209                         *andptr++ = p->from.offset;
1210                         break;
1211                 case D_CL:
1212                 case D_CX:
1213                         *andptr++ = 0x0f;
1214                         *andptr++ = t[5];
1215                         asmand(&p->to, reg[p->from.index]);
1216                         break;
1217                 }
1218                 break;
1219
1220         case 7: /* imul rm,r */
1221                 *andptr++ = t[4];
1222                 *andptr++ = t[5];
1223                 asmand(&p->from, reg[p->to.type]);
1224                 break;
1225         }
1226 }
1227
1228 void
1229 asmins(Prog *p)
1230 {
1231
1232         andptr = and;
1233         doasm(p);
1234 }
1235
1236 enum{
1237         ABSD = 0,
1238         ABSU = 1,
1239         RELD = 2,
1240         RELU = 3,
1241 };
1242
1243 int modemap[4] = { 0, 1, -1, 2, };
1244
1245 typedef struct Reloc Reloc;
1246
1247 struct Reloc
1248 {
1249         int n;
1250         int t;
1251         uchar *m;
1252         ulong *a;
1253 };
1254
1255 Reloc rels;
1256
1257 static void
1258 grow(Reloc *r)
1259 {
1260         int t;
1261         uchar *m, *nm;
1262         ulong *a, *na;
1263
1264         t = r->t;
1265         r->t += 64;
1266         m = r->m;
1267         a = r->a;
1268         r->m = nm = malloc(r->t*sizeof(uchar));
1269         r->a = na = malloc(r->t*sizeof(ulong));
1270         memmove(nm, m, t*sizeof(uchar));
1271         memmove(na, a, t*sizeof(ulong));
1272         free(m);
1273         free(a);
1274 }
1275
1276 void
1277 dynreloc(Sym *s, ulong v, int abs)
1278 {
1279         int i, k, n;
1280         uchar *m;
1281         ulong *a;
1282         Reloc *r;
1283
1284         if(s->type == SUNDEF)
1285                 k = abs ? ABSU : RELU;
1286         else
1287                 k = abs ? ABSD : RELD;
1288         /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
1289         k = modemap[k];
1290         r = &rels;
1291         n = r->n;
1292         if(n >= r->t)
1293                 grow(r);
1294         m = r->m;
1295         a = r->a;
1296         for(i = n; i > 0; i--){
1297                 if(v < a[i-1]){ /* happens occasionally for data */
1298                         m[i] = m[i-1];
1299                         a[i] = a[i-1];
1300                 }
1301                 else
1302                         break;
1303         }
1304         m[i] = k;
1305         a[i] = v;
1306         r->n++;
1307 }
1308
1309 static int
1310 sput(char *s)
1311 {
1312         char *p;
1313
1314         p = s;
1315         while(*s)
1316                 cput(*s++);
1317         cput(0);
1318         return s-p+1;
1319 }
1320
1321 void
1322 asmdyn()
1323 {
1324         int i, n, t, c;
1325         Sym *s;
1326         ulong la, ra, *a;
1327         vlong off;
1328         uchar *m;
1329         Reloc *r;
1330
1331         cflush();
1332         off = seek(cout, 0, 1);
1333         lput(0);
1334         t = 0;
1335         lput(imports);
1336         t += 4;
1337         for(i = 0; i < NHASH; i++)
1338                 for(s = hash[i]; s != S; s = s->link)
1339                         if(s->type == SUNDEF){
1340                                 lput(s->sig);
1341                                 t += 4;
1342                                 t += sput(s->name);
1343                         }
1344
1345         la = 0;
1346         r = &rels;
1347         n = r->n;
1348         m = r->m;
1349         a = r->a;
1350         lput(n);
1351         t += 4;
1352         for(i = 0; i < n; i++){
1353                 ra = *a-la;
1354                 if(*a < la)
1355                         diag("bad relocation order");
1356                 if(ra < 256)
1357                         c = 0;
1358                 else if(ra < 65536)
1359                         c = 1;
1360                 else
1361                         c = 2;
1362                 cput((c<<6)|*m++);
1363                 t++;
1364                 if(c == 0){
1365                         cput(ra);
1366                         t++;
1367                 }
1368                 else if(c == 1){
1369                         wput(ra);
1370                         t += 2;
1371                 }
1372                 else{
1373                         lput(ra);
1374                         t += 4;
1375                 }
1376                 la = *a++;
1377         }
1378
1379         cflush();
1380         seek(cout, off, 0);
1381         lput(t);
1382
1383         if(debug['v']){
1384                 Bprint(&bso, "import table entries = %d\n", imports);
1385                 Bprint(&bso, "export table entries = %d\n", exports);
1386         }
1387 }