|
|
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.