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