|
|
1.1 root 1: /*
2: * 80386 Assembler Build output code.
3: */
4: #include <asm.h>
5: #include <asflags.h>
6: #include <y_tab.h>
7: #include <symtab.h>
8:
9: static symt *st;
10: static struct expr *opList[3];
11: static int ct;
12:
13: /* as checkop runs it sets the following fields */
14: static expr *addr, *displ, *immed, *immedx;
15: static char mod, rm, reg, scale, index, base, immed8;
16:
17: static unsigned long uflags;
18: #define U_REL8 1 /* relative 8 bit operand */
19: #define U_REL16 2 /* relative 16 bit operand */
20: #define U_RELI 3 /* we get to choose 8 0r 16 bit */
21: #define U_REL_MASK 3
22:
23: #define U_RMS 0x04 /* mod/rm .16 */
24: #define U_RML 0x08 /* mod/rm .32 */
25: #define U_IMM8 0x10 /* 8 bit immediate field */
26: #define U_IMM16 0x20 /* 16 bit immediate field */
27: #define U_IMM16X 0x40 /* 16 bit second immediate field */
28: #define U_IMM32 0x80 /* 32 bit immediate field */
29: #define U_IMM32X 0x100 /* 32 bit second immediate field */
30: #define U_ADR16 0x200 /* 16 bit direct address */
31: #define U_ADR32 0x400 /* 32 bit direct address */
32: #define U_DSP8 0x800 /* 8 bit displacment with mod/rm */
33: #define U_DSP 0x1000 /* 16 or 32 bit displacment with mod/rm */
34: #define U_CTL 0x2000 /* control register */
35:
36: /*
37: * Build indefinate opcode. On 80386 thats everything.
38: * First try all instrs not in the wrong mode.
39: * Then try the instrs in the wrong mode.
40: */
41: buildind(label, op, oper)
42: parm *label;
43: register opc *op;
44: register expr *oper;
45: {
46: int i;
47: unsigned short wrongMode;
48:
49: buildlab(label);
50:
51: ct = countList((parm *)oper);
52:
53: if (ct > 3) {
54: yyerror("Too many operands");
55: /* No 386 opcode has more than three operands. */
56: return (1);
57: }
58:
59: if (fswitch) /* reverse operand order */
60: for (i = ct; i--; oper = oper->next)
61: opList[i] = oper;
62: else /* normal operand order */
63: for (i = 0; i < ct; i++, oper = oper->next)
64: opList[i] = oper;
65:
66: /* try the stuff not in the wrong mode */
67: wrongMode = longMode ? WORD_MODE : LONG_MODE;
68: for (i = 0; i < choices; i++) {
69: st = typTab + op[i].kind;
70: if (!(st->bldr & wrongMode) && !buildop(op + i))
71: return(0);
72: }
73:
74: /* now try the wrong mode choices */
75: for (i = 0; i < choices; i++) {
76: st = typTab + op[i].kind;
77: if ((st->bldr & wrongMode) && !buildop(op + i))
78: return(0);
79: }
80:
81: yyerror("Illegal combination of opcode and operands");
82: /* Although the opcode is valid and the operands are valid,
83: * there is no form of this opcode which takes this combination
84: * of operands in this order. */
85: return(1);
86: }
87:
88: /*
89: * Check if operator validly fits mode.
90: * return 1 for false zero for true.
91: */
92: static
93: checkop(this, type)
94: register expr *this;
95: unsigned short type;
96: {
97: register sym *r1;
98: long d;
99: int regsz;
100:
101: r1 = this->r1;
102:
103: switch (type) {
104: case m8:
105: case m16:
106: case m32:
107: case m64:
108: case m80:
109: regsz = -1; /* can't be a register */
110: break;
111:
112: case rm8:
113: regsz = 1; /* reg must be 1 long */
114: break;
115:
116: case rm16:
117: regsz = 2; /* reg must be 2 long */
118: break;
119:
120: case rm32:
121: regsz = 4; /* reg must be 4 long */
122: break;
123:
124: case reli: /* near branch */
125: if (!(lflags & A_INDIR)) {
126: uflags = U_RELI;
127: return (T_D != this->mode);
128: }
129: regsz = longMode ? 4 : 2;
130: break;
131:
132: case rel8: /* near branch */
133: uflags = U_REL8;
134: return (T_D != this->mode);
135:
136: case rel16: /* medium or long branch */
137: uflags = U_REL16;
138: return (T_D != this->mode);
139:
140: case mem32: /* 32 bit simple address */
141: uflags |= U_ADR32;
142: rm = 5;
143: return (T_D != (addr = this)->mode);
144:
145: case mem16: /* 16 bit simple address */
146: uflags |= U_ADR16;
147: rm = 6;
148: return (T_D != (addr = this)->mode);
149:
150:
151: case imm8:
152: uflags |= U_IMM8;
153: immed8 = this->exp;
154: return (this->ref != NULL ||
155: this->mode != T_IMM ||
156: this->exp < -128 ||
157: this->exp > 255);
158:
159: case imm8s:
160: uflags |= U_IMM8;
161: immed8 = this->exp;
162: return (this->ref != NULL ||
163: this->mode != T_IMM ||
164: this->exp < -128 ||
165: this->exp > 127);
166:
167: case imm16x:
168: uflags |= U_IMM16X;
169: d = (immedx = this)->exp;
170: return (this->mode != T_IMM ||
171: d < -32768L ||
172: d > 65535L);
173:
174: case imm16:
175: uflags |= U_IMM16;
176: d = (immed = this)->exp;
177: return (this->mode != T_IMM ||
178: d < -32768L ||
179: d > 65535L);
180:
181: case imm32x:
182: uflags |= U_IMM32X;
183: immedx = this;
184: return (this->mode != T_IMM);
185:
186: case moffs:
187: uflags |= U_IMM32;
188: immed = this;
189: return (this->mode != T_D);
190:
191: case imm32:
192: uflags |= U_IMM32;
193: immed = this;
194: return (this->mode != T_IMM);
195:
196: case con1:
197: return (this->mode != T_IMM ||
198: this->exp != 1);
199:
200: case con3:
201: return (this->mode != T_IMM ||
202: this->exp != 3);
203:
204: case al:
205: return (this->mode != T_R ||
206: r1->flag != ORD_REG ||
207: r1->size != 1 ||
208: r1->loc != 0);
209:
210: case ax:
211: return (this->mode != T_R ||
212: r1->flag != ORD_REG ||
213: r1->size != 2 ||
214: r1->loc != 0);
215:
216: case eax:
217: return (this->mode != T_R ||
218: r1->flag != ORD_REG ||
219: r1->size != 4 ||
220: r1->loc != 0);
221:
222: case r16:
223: if (this->mode != T_R || r1->flag != ORD_REG || r1->size != 2)
224: return (1);
225: reg = r1->loc;
226: return (0);
227:
228: case atdx:
229: if (this->mode != T_RI || r1->flag != ORD_REG ||
230: r1->size != 2 || r1->loc != 2)
231: return(1);
232: lflags &= ~A_SHORT;
233: return(0);
234:
235: case cl:
236: return (this->mode != T_R ||
237: r1->flag != ORD_REG ||
238: r1->size != 1 ||
239: r1->loc != 1);
240:
241: case ds:
242: return (this->mode != T_R ||
243: r1->flag != SEG_REG ||
244: r1->loc != 3);
245:
246: case es:
247: return (this->mode != T_R ||
248: r1->flag != SEG_REG ||
249: r1->loc != 0);
250:
251: case ss:
252: return (this->mode != T_R ||
253: r1->flag != SEG_REG ||
254: r1->loc != 2);
255:
256: case fs:
257: return (this->mode != T_R ||
258: r1->flag != SEG_REG ||
259: r1->loc != 4);
260:
261: case gs:
262: return (this->mode != T_R ||
263: r1->flag != SEG_REG ||
264: r1->loc != 5);
265:
266: case cs:
267: return (this->mode != T_R ||
268: r1->flag != SEG_REG ||
269: r1->loc != 1);
270:
271: case sreg:
272: if (this->mode != T_R || r1->flag != SEG_REG)
273: return (1);
274: reg = r1->loc;
275: return (0);
276:
277: case st0:
278: if (this->mode != T_FP || this->exp)
279: return (1);
280: return (0);
281:
282: case fpreg:
283: if (this->mode != T_FP)
284: return (1);
285: reg = this->exp;
286: return (0);
287:
288: case ctlreg:
289: if (this->mode != T_R || r1->flag != CTL_REG)
290: return (1);
291: uflags |= U_CTL;
292: rm = r1->loc;
293: return (0);
294:
295: case dbreg:
296: if (this->mode != T_R || r1->flag != DEB_REG)
297: return (1);
298: uflags |= U_CTL;
299: rm = r1->loc;
300: return (0);
301:
302: case treg:
303: if (this->mode != T_R || r1->flag != TST_REG)
304: return (1);
305: uflags |= U_CTL;
306: rm = r1->loc;
307: return (0);
308:
309: case r32:
310: if (this->mode != T_R || r1->flag != ORD_REG || r1->size != 4)
311: return (1);
312: reg = r1->loc;
313: return (0);
314:
315: case r8:
316: if (this->mode != T_R || r1->flag != ORD_REG || r1->size != 1)
317: return (1);
318: reg = r1->loc;
319: return (0);
320: }
321:
322: /*
323: * If we get to here the mode must be rm16 or rm32.
324: * The table mode has been used to decide the proper
325: * size for registers. Decide which is the real mode.
326: */
327: if (longMode)
328: if (lflags & A_SHORT)
329: type = rm16;
330: else
331: type = rm32;
332: else
333: if (lflags & A_LONG)
334: type = rm32;
335: else
336: type = rm16;
337:
338: switch(type) {
339: case rm32: /* r/m 32 See Tables 17-3 and 17-4 */
340: uflags |= U_RML;
341: switch (this->mode) {
342: case T_D: /* all 32 bit disp must be good */
343: mod = 0;
344: rm = 5;
345: uflags |= U_DSP;
346: displ = this;
347: return (0);
348:
349: case T_RID:
350: if ((NULL != this->ref) ||
351: (d = this->exp) < -128 || d > 127) {
352: uflags |= U_DSP;
353: mod = 2;
354: }
355: else {
356: uflags |= U_DSP8;
357: mod = 1;
358: }
359:
360: if (4 == (rm = r1->loc)) { /* disp (%esp) */
361: base = 4; /* base = %esp */
362: index = 4; /* no index */
363: }
364: displ = this;
365: return (0);
366:
367: case T_R: /* eax | ecx || edx || ebx || esi || edi */
368: if ((r1->size != regsz) || (r1->flag != ORD_REG))
369: return (1);
370: rm = r1->loc;
371: mod = 3;
372: return(0);
373:
374: case T_RI:
375: switch (rm = r1->loc) {
376: case 5: /* ( %ebp ) */
377: mod = 1; /* 0 ( %ebp ) */
378: uflags |= U_DSP8; /* force displacment 0 */
379: displ = this;
380: break;
381: case 4: /* ( %esp ) */
382: base = 4; /* %sp */
383: index = 4; /* no index */
384: default: /* (eax | ecx | edx | ebx | esi | edi) */
385: mod = 0;
386: }
387:
388: return (0);
389:
390: case T_RIS:
391: if (4 == (index = r1->loc)) /* can't index %esp */
392: return (1);
393:
394: rm = 4; /* use sib */
395: mod = 0; /* no disp */
396: base = 5; /* no base */
397: uflags |= U_DSP;
398: scale = this->scale;
399: index = r1->loc;
400: displ = this;
401: return (0);
402:
403: case T_RIX:
404: case T_RIXS:
405: /* can't index esp */
406: if (4 == (index = this->r2->loc))
407: return(1);
408:
409: if (5 != (base = r1->loc)) {
410: mod = 0;
411: rm = 4;
412: scale = this->scale;
413: return (0);
414: } /* if base %ebp use T_RIXDS */
415:
416: case T_RIXD:
417: case T_RIXDS:
418: /* can't index esp */
419: if (4 == (index = this->r2->loc))
420: return (1);
421:
422: base = r1->loc;
423: if ((NULL != this->ref) ||
424: (d = this->exp) < -128 || d > 127) {
425: uflags |= U_DSP;
426: mod = 2;
427: }
428: else {
429: uflags |= U_DSP8;
430: mod = 1;
431: }
432:
433: rm = 4;
434: scale = this->scale;
435: displ = this;
436: return (0);
437:
438: case T_RIDS:
439: if (4 == (index = r1->loc)) /* can't index sp */
440: return (1);
441:
442: mod = 0;
443: uflags |= U_DSP;
444: scale = this->scale;
445: rm = 4;
446: base = 5;
447: displ = this;
448: return (0);
449: }
450: return (1);
451:
452: case rm16: /* r/m 16 */
453: uflags |= U_RMS;
454: switch (this->mode) {
455: case T_RI: /* register indirect */
456: switch ((int)r1->loc) {
457: case 6: /* (%si) */
458: rm = 4; break;
459: case 7: /* (%di) */
460: rm = 5; break;
461: case 3: /* (%bx) */
462: rm = 7; break;
463: default:
464: return (1);
465: }
466: mod = 0;
467: return (0);
468:
469: case T_R: /* register */
470: if ((r1->size != regsz) || (r1->flag != ORD_REG))
471: return (1);
472: rm = r1->loc;
473: mod = 3;
474: return (0);
475:
476: case T_D: /* displacment */
477: if (this->exp < -32768L || this->exp > 65535L)
478: return(1);
479:
480: mod = 0;
481: rm = 6;
482: uflags |= U_DSP;
483: displ = this;
484: return (0);
485:
486: case T_RID: /* register indirect displacment */
487: if (this->exp < -32768L || this->exp > 65535L)
488: return(1);
489:
490: switch ((int)r1->loc) {
491: case 6: /* (%si) */
492: rm = 4; break;
493: case 7: /* (%di) */
494: rm = 5; break;
495: case 5: /* (%bp) */
496: rm = 6; break;
497: case 3: /* (%bx) */
498: rm = 7; break;
499: default:
500: return (1);
501: }
502:
503: if ((NULL != this->ref) ||
504: (d = this->exp) < -128 || d > 127) {
505: uflags |= U_DSP;
506: mod = 2;
507: }
508: else {
509: uflags |= U_DSP8;
510: mod = 1;
511: }
512: displ = this;
513: return (0);
514:
515: case T_RIXD: /* register index displacment */
516: if ((NULL != this->ref) ||
517: (d = this->exp) < -128 || d > 127) {
518: uflags |= U_DSP;
519: mod = 2;
520: }
521: else {
522: uflags |= U_DSP8;
523: mod = 1;
524: }
525: /* fall through */
526: displ = this;
527:
528: case T_RIX: /* register index */
529: if (T_RIX == this->mode)
530: mod = 0;
531:
532: switch ((int)r1->loc) {
533: case 3: /* %bx */
534: switch ((int)this->r2->loc) {
535: case 6: /* %si */
536: rm = 0; break;
537: case 7: /* %di */
538: rm = 1; break;
539: default:
540: return (1);
541: }
542: break;
543: case 5: /* bp */
544: switch ((int)this->r2->loc) {
545: case 6: /* %si */
546: rm = 2; break;
547: case 7: /* %di */
548: rm = 3; break;
549: default:
550: return (1);
551: }
552: break;
553: default:
554: return (1);
555: }
556: return (0);
557: }
558: return (1);
559: }
560: }
561:
562: /*
563: * Chip errata message.
564: */
565: errata(opcode)
566: {
567: if (opcode && !nswitch)
568: outab(opcode);
569: else
570: yywarn("This code may not work the same way on all chips");
571: /* Some chips may not execute this code as expected. */
572: }
573:
574: /*
575: * Try to build an opcode.
576: */
577: static
578: buildop(op)
579: opc *op;
580: {
581: register unsigned short i, j;
582: static short postSw = 0;
583: static short lastOp = 0;
584: static short lastFlags = 0;
585:
586: /* First check if everything is ok */
587: if (st->operands != ct)
588: return(1);
589:
590: uflags = base = mod = rm = reg = scale = index = 0;
591: for (i = 0; i < ct; i++)
592: if (checkop(opList[i], (unsigned short)(st->ap[i])))
593: return(1);
594:
595: /* deal with unusual stuff */
596: if (st->bldr & (AMBIG_MATCH | TWO_OP_MULT | XTENDS)) {
597: if (st->bldr & AMBIG_MATCH)
598: yywarn("Ambiguous operand length, %d bytes selected",
599: (MOV_BYTE == op->code) ? 1 : (longMode ? 4 : 2));
600: /* The assembler cannot tell the operand length by
601: * looking at the opcode and the operands.
602: * You may want to do something like change
603: * \fBmov\fR to \fBmovl\fR. */
604:
605: /* 2 operand form of 3 operand multiply */
606: if (st->bldr & TWO_OP_MULT) {
607: mod = 3;
608: rm = opList[1]->r1->loc;
609: }
610:
611: /* movsx and movzx have mixed 16 and 32 bit stuff */
612: if (st->bldr & XTENDS)
613: lflags &= ~(O_LONG|O_SHORT);
614: }
615:
616: /*
617: * Only a few instructions are defined after a rep or lock
618: * Instructions valid after lock are marked but are
619: * only valid if a memory location is accessed. This is
620: * checked by excluding (mod == 3) which is rm is register.
621: */
622: if (postSw) {
623: if (postSw & REP_INSTR)
624: if (!(st->bldr & AFTER_REP))
625: yywarn("Improper instruction following rep");
626: /* Only a few instructions
627: * are valid after a rep instruction.
628: * See your machine documentation for details.*/
629: else if (op->code == INSB || op->code == INSW)
630: errata(0);
631:
632: if ((postSw & LOCK_OP) &&
633: (!(st->bldr & AFTER_LOCK) || (3 == mod)))
634: yywarn("Improper instruction following lock");
635: /* Only a few instructions
636: * are valid after a lock instruction.
637: * See your machine documentation for details. */
638: }
639: postSw = st->bldr & (LOCK_OP | REP_INSTR);
640:
641: /*
642: * check for various chip errata
643: * sometimes wave a dead chicken over your head to make things work
644: */
645: #if 0
646: /* See Intel chip errata for 80386-B1 17.
647: * Coprocessor instruction crossing segment boundaries may hang chip.
648: * Assume any 4's boundary is a potential boundary. */
649: if ((st->bldr & FLOAT_ESC) &&
650: (((st->bldr & FLOAT_PFX) ? 2 : 3) == (dot.loc % 4)))
651: errata(NOP);
652: #endif
653:
654: /* See Intel chip errata for 80386-B1 23. */
655: if (((lastOp == POPA) && (uflags & U_RML) && (mod != 3)) &&
656: /* determine longmode of popa */
657: ((longMode ? !(lastFlags & 2) : (lastFlags & 4)) ?
658: /* longmode then if base index and either not %eax */
659: ((rm == 4) && (index || base)) :
660: /* not longmode any index was %eax */
661: (!rm || ((rm == 4) && (!index || !base)))))
662: errata(NOP);
663:
664: if (POP_MEM == op->code) {
665: /* pop %cs:mem */
666: if (opList[0]->sg == 1)
667: errata(0);
668:
669: /* pop n(%esp) */
670: if ((uflags & U_RML) && base == 4 && rm == 4 && mod)
671: errata(0);
672: }
673:
674: /*
675: * aam must be preceeded with special stuff on 80486
676: * The idea is that there must be an xchg with a non 1 value.
677: */
678: if (op->code == AAM) {
679: static char seq[8] = {
680: 0x51, /* push %ecx */
681: 0x33, 0xC9, /* xor %ecx, %ecx */
682: 0x87, 0xC9, /* xchg %ecx, %ecx */
683: 0xD4, 0x0A, /* aam */
684: 0x59 /* pop %ecx */
685: };
686:
687: if (nswitch)
688: errata(0);
689: else {
690: for (i = 0; i < 8; i++)
691: outab(seq[i]);
692: return (0);
693: }
694: }
695:
696: lastFlags = st->bldr;
697: lastOp = op->code;
698:
699: if (lflags & A_INDIR) {
700: lastFlags = (longMode ? LONG_MODE : WORD_MODE) | MODRM_BYTE;
701: switch (lastOp) {
702: case JMP_NEAR:
703: lastOp = JMP_INDIR; break;
704: case CALL_NEAR:
705: lastOp = CALL_INDIR; break;
706: default:
707: yyerror("Indirect mode on invalid instruction");
708: /* Indirection is only allowed on call and jump near
709: * instructions. */
710: }
711: }
712:
713: if (longMode) {
714: if (lflags & A_SHORT) {
715: yywarn("16 bit addressing mode used in 32 bit code");
716: /* You probably don't want to do this.
717: * For example, you may want to say \fB(%esi)\fR, not
718: * \fB(%si)\fR. */
719: outab(PREFIX_AD); /* address size prefix */
720: }
721: else
722: lflags |= A_LONG;
723:
724: if (lastFlags & WORD_MODE)
725: outab(PREFIX_OP); /* operand size prefix */
726: }
727: else {
728: if (lflags & A_LONG) {
729: yywarn("32 bit addressing mode used in 16 bit code");
730: /* You probably don't want to do this.
731: * For example, you may want to say \fB(%si)\fR, not
732: * \fB(%esi)\fR. */
733: outab(PREFIX_AD); /* address size prefix */
734: }
735: else
736: lflags |= A_SHORT;
737:
738: if (lastFlags & LONG_MODE)
739: outab(PREFIX_OP); /* operand size prefix */
740: }
741:
742: #define ck(x, y) if (j & x) break; j |= x; outab(y); break;
743:
744: /* Put out nessisary prefix bytes */
745: for (j = i = 0; i < ct; i++) {
746: switch (opList[i]->sg) {
747: case 0: /* es: */
748: ck(1, PREFIX_ES);
749: case 1: /* cs: */
750: ck(2, PREFIX_CS);
751: case 2: /* ss: */
752: ck(4, PREFIX_SS);
753: case 3: /* ds: */
754: ck(8, PREFIX_DS);
755: case 4: /* fs: */
756: ck(16, PREFIX_FS);
757: case 5: /* gs: */
758: ck(32, PREFIX_GS);
759: }
760: }
761:
762: #undef ck
763:
764: /* Then build the op code */
765:
766: /* Test for relative jump first */
767: switch ((int)(uflags & U_REL_MASK)) {
768: case U_REL16: /* 16 or 32 bit branch */
769: indBra(lastOp, NON_OP, opList[0]);
770: return(0);
771:
772: case U_REL8: /* 8 bit branch */
773: indBra(NON_OP, lastOp, opList[0]);
774: return(0);
775:
776: case U_RELI: /* may become 8, 16 or 32 bit branch */
777: switch (lastOp) {
778: case JMP_NEAR:
779: indBra(lastOp, JMP_SHORT, opList[0]);
780: break;
781: case CALL_NEAR:
782: indBra(lastOp, NON_OP, opList[0]);
783: break;
784: default: /* conditional jump */
785: indBra(lastOp + JCC_NEAR,
786: lastOp + JCC_SHORT, opList[0]);
787: }
788: return(0);
789: }
790:
791: if (lastFlags & PFX_0F)
792: outab(0x0F);
793:
794: if (lastFlags & FLOAT_PFX)
795: outab(0x9B);
796:
797: if (lastFlags & MODRM_BYTE ||
798: lastOp & 0xFF00)
799: outab(lastOp >> 8);
800:
801: j = lastOp & 0xFF;
802:
803: if (lastFlags & ADD_REG)
804: j += reg;
805:
806: if (lastFlags & MODRM_BYTE)
807: reg = j;
808: else
809: outab(j);
810:
811: if (uflags & (U_RML|U_CTL))
812: outrm32();
813: else if (uflags & U_RMS)
814: outrm16();
815:
816: if (uflags & U_IMM16)
817: outrw(immed, 0);
818:
819: if (uflags & U_IMM32)
820: outrl(immed, 0);
821:
822: if (uflags & U_IMM8)
823: outab(immed8);
824:
825: if (uflags & U_IMM16X)
826: outrw(immedx, 0);
827:
828: if (uflags & U_IMM32X)
829: outrl(immedx, 0);
830:
831: if (uflags & U_ADR16)
832: outrw(addr, 0);
833:
834: if (uflags & U_ADR32)
835: outrl(addr, 0);
836:
837: return(0);
838: }
839:
840: /*
841: * Output mod/rm byte and maybe sib
842: */
843: static
844: outrm32()
845: {
846: short modrm, sib;
847:
848: if (uflags & U_CTL) /* Special register used */
849: modrm = (3 << 6) | (rm << 3) | reg;
850: else
851: modrm = (mod << 6) | (reg << 3) | rm;
852:
853: outab(modrm);
854: if (4 == rm && 3 != mod) {
855: sib = (scale << 6) | (index << 3) | base;
856: outab(sib);
857: }
858:
859: if (uflags & U_DSP8)
860: outrb(displ, 0);
861:
862: else if (uflags & U_DSP)
863: outrl(displ, 0);
864: }
865:
866: /*
867: * Output mod/rm byte
868: */
869: static
870: outrm16()
871: {
872: short modrm;
873:
874: modrm = (mod << 6) | (reg << 3) | rm;
875: outab(modrm);
876:
877: if (uflags & U_DSP8)
878: outrb(displ, 0);
879:
880: else if (uflags & U_DSP)
881: outrw(displ, 0);
882: }
883:
884: /*
885: * Code for relative branches.
886: * Save type of all branch operators on a list assuming shortest feasable.
887: * If a type changes set xpass = 1.
888: *
889: * Pass logic in newPass goes to 2 only if xpass == 0 else it goes to 1
890: *
891: * There is an elegant algorithm for fixing up jumps between passes by
892: * tree manipulation, this would reduce this to a two pass assembler.
893: * Sadly it won't work. It assumes smooth code, that is if I change a
894: * byte jump to a near jump the following addresses will change by addition.
895: * In assembly language people can insert things like .align or .org which
896: * break that assumption, the GNU compiler does this every few lines.
897: *
898: * Once the smooth code assumption is broken we no longer know that the
899: * tree algorithm terminates at all, a byte jump can go to a longer jump
900: * and back again in the next pass. To guarantee termination we start at
901: * byte jumps and only go to longer jumps when we know it is forced. Once
902: * we go to longer jump we never go back. This speeds the assembly of GNU
903: * output by about 10 times.
904: */
905: static unsigned braCt; /* count of branches */
906:
907: #define BYTE_J 0 /* byte jump length */
908: #define NEAR_J 1 /* int jump length */
909: #define EXT_J 2 /* jump around sequence */
910:
911: /*
912: * Called at new pass or init. Returns 1 if another pass required.
913: */
914: indPass()
915: {
916: braCt = 0; /* so far no branches */
917: if (xpass) {
918: xpass = 0;
919: return (1);
920: }
921: return (0);
922: }
923:
924: /*
925: * Put out op code.
926: */
927: static void
928: putOp(opCode)
929: register unsigned short opCode;
930: {
931: if (opCode & 0xFF00) {
932: outab(opCode >> 8);
933: outab(opCode & 0xff);
934: }
935: else
936: outab(opCode);
937: }
938:
939: /*
940: * Called for each relative branch.
941: * Calculates branch size. Forces another pass if a branch expands.
942: */
943: void
944: indBra(nearOp, byteOp, op)
945: unsigned short nearOp, byteOp;
946: register expr *op;
947: {
948: static char *list; /* one for each relative branch */
949: static unsigned max; /* size of list */
950: char size; /* BYTE_J NEAR_J EXT_J */
951: long d; /* displacment */
952: short flag, exref;
953: char *old;
954:
955: /* insure space for branch data */
956: if (max <= ++braCt)
957: expand(&list, &max, 64, sizeof(char));
958:
959: old = list + (braCt - 1);
960: /* assume size from last pass or shortest size for this jump. */
961: size = pass ? *old : ((byteOp == NON_OP) ? NEAR_J : BYTE_J);
962:
963: if (NULL == op->ref)
964: fatal("NULL address in relative branch"); /* TECH */
965:
966: flag = op->ref->flag;
967: exref = 0;
968:
969: if (flag & S_UNDEF) { /* undefined symbol */
970: if (pass)
971: size = NEAR_J; /* known near */
972: else if (BYTE_J == size)
973: xpass = 1;
974:
975: if (gswitch) /* -g turns undefined to global */
976: exref = 1;
977: }
978:
979: else if ((flag & S_EXREF) || (dot.sg != op->ref->sg)) {
980: exref = 1;
981: size = NEAR_J; /* known near */
982: }
983:
984: else if (BYTE_J == size) {
985: /* Calculate displacment from end of byte instr */
986: d = op->exp - (dot.loc + ((byteOp & 0xFF00) ? 3 : 2));
987:
988: if ((d < -128) || (d > 127)) /* near limits */
989: size = NEAR_J;
990: }
991:
992: /* near branch and none available build jumpover */
993: if ((NEAR_J == size) && (NON_OP == nearOp))
994: size = EXT_J;
995:
996: /* How does this compare to the last time? */
997: if (*old != size) {
998: switch(pass) {
999: case 1:
1000: if (*old > size) /* never shrink */
1001: break;
1002: xpass = 1; /* take one more pass */
1003: case 0:
1004: *old = size; /* take new size */
1005: break;
1006: default:
1007: if (*old < size) /* too late for changes */
1008: fatal("Internal error relative branch logic");
1009: /* TECH */
1010: }
1011: }
1012:
1013: /* output code */
1014: switch(*old) {
1015: case BYTE_J: /* short op */
1016: putOp(byteOp);
1017: if (exref)
1018: outrb(op, 1);
1019: else
1020: outab((int)d);
1021: break;
1022:
1023: case EXT_J: /* jump around sequence */
1024: putOp(byteOp); /* caller's jump over byte jump */
1025: outab(2);
1026:
1027: outab(JMP_SHORT); /* byte jump over near jump */
1028: outab(longMode ? 0x05 : 0x03);
1029:
1030: nearOp = JMP_NEAR; /* near jump to caller's destination */
1031:
1032: case NEAR_J: /* near jumps */
1033: putOp(nearOp);
1034: if (longMode)
1035: if (exref)
1036: outrl(op, 1);
1037: else /* displacement from end of address */
1038: outal(op->exp - (dot.loc + 4));
1039: else
1040: if (exref)
1041: outrw(op, 1);
1042: else /* displacement from end of address */
1043: outaw((int)(op->exp - (dot.loc + 2)));
1044: }
1045: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.