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