|
|
1.1 ! root 1: /* ! 2: * n2/i386/asm.c ! 3: * The routines in this file assemble buffered code ! 4: * and write the code to the output file. ! 5: * i386. ! 6: */ ! 7: ! 8: #ifdef vax ! 9: #include "INC$LIB:cc2.h" ! 10: #else ! 11: #include "cc2.h" ! 12: #endif ! 13: ! 14: #define W 0x01 /* W (word) bit */ ! 15: #define D 0x02 /* D (direction) bit */ ! 16: #define ESC_2B 0x0F /* Two-byte op escape */ ! 17: #define ESC 0xD8 /* Escape */ ! 18: #define WAIT 0x9B /* Wait */ ! 19: ! 20: static ADDRESS pc; /* Current assembly pc */ ! 21: static ADDRESS pcdot[NSEG]; /* Working copy of seg '.' fields */ ! 22: static int pcseg; /* Current segment */ ! 23: static int pass; /* Pass flag; only 1 emits code */ ! 24: ! 25: extern int hasfloat; /* function uses floating point */ ! 26: ! 27: /* ! 28: * Driving routine. ! 29: * Run pass 0 of the assembly to get sizes. ! 30: * All jumps are assumed to be short. ! 31: * Fix up any that don't reach. ! 32: * Run the second assembly pass to generate the final code. ! 33: */ ! 34: genfunc() ! 35: { ! 36: register INS *ip1, *ip2; ! 37: register int i; ! 38: ! 39: pc = dot; ! 40: pass = 0; ! 41: pcseg = dotseg; ! 42: for (i = 0; i < NSEG; ++i) ! 43: pcdot[i] = seg[i].s_dot; ! 44: ip1 = ins.i_fp; ! 45: while (ip1 != &ins) { ! 46: assemble(ip1); ! 47: ip1 = ip1->i_fp; ! 48: } ! 49: sdi(); ! 50: pc = dot; ! 51: pass = 1; ! 52: pcseg = dotseg; ! 53: for (i = 0; i < NSEG; ++i) ! 54: pcdot[i] = seg[i].s_dot; ! 55: ip1 = ins.i_fp; ! 56: while (ip1 != &ins) { ! 57: asmdbgt(ip1); ! 58: if (isvariant(VASM)) ! 59: unassemble(ip1); ! 60: else ! 61: assemble(ip1); ! 62: ip2 = ip1->i_fp; ! 63: free((char *) ip1); ! 64: ip1 = ip2; ! 65: } ! 66: asmdbgt(&ins); ! 67: } ! 68: ! 69: /* ! 70: * Generate code for a single instruction. ! 71: * Used to compile external data definitions, etc. ! 72: */ ! 73: genins(ip) register INS *ip; ! 74: { ! 75: register int i; ! 76: ! 77: for (pass=0; pass!=2; ++pass) { ! 78: pc = dot; ! 79: pcseg = dotseg; ! 80: for (i = 0; i < NSEG; ++i) ! 81: pcdot[i] = seg[i].s_dot; ! 82: if (isvariant(VASM) && pass != 0) { ! 83: if (ip->i_type != LINE ! 84: || isvariant(VLINES)) ! 85: unassemble(ip); ! 86: } else ! 87: assemble(ip); ! 88: } ! 89: } ! 90: ! 91: /* ! 92: * This function fixes up the span dependent instructions. ! 93: * The only case on the iAPX-86 is the jump, which has limited range. ! 94: * There is nothing to be done with the adjustable displacements, ! 95: * bacause these are always absolute and do not change. ! 96: * For the moment, ! 97: * unconditional JMP gets bumped from JMP i8 to JMP i32 (2 bytes -> 5); ! 98: * conditional Jcc gets bumped from Jcc i8 to Jcc i32 (2 -> 6). ! 99: * The 16-bit forms using operand escape prefix are probably better. ! 100: */ ! 101: sdi() ! 102: { ! 103: register INS *ip1, *ip2; ! 104: register SYM *sp; ! 105: register int bump, changes; ! 106: SIGNEDADDRESS disp; ! 107: ! 108: do { ! 109: changes = 0; ! 110: ip1 = ins.i_fp; ! 111: while (ip1 != &ins) { ! 112: if (isoptjump(ip1)) { ! 113: if ((sp=ip1->i_sp) == NULL) ! 114: cbotch("sdi"); ! 115: if (ip1->i_pcseg != sp->s_seg) ! 116: cbotch("x seg #1"); ! 117: disp = sp->s_value-ip1->i_pc-2; ! 118: if (disp < -128 || disp > 127) { ! 119: ip1->i_long = 1; ! 120: changes = 1; ! 121: bump = 3; ! 122: if (ip1->i_rel != ZJMP) ! 123: bump = 4; ! 124: ip2 = ip1->i_fp; ! 125: while (ip2 != &ins) { ! 126: sdibump(ip1, ip2, bump); ! 127: ip2 = ip2->i_fp; ! 128: } ! 129: } ! 130: } ! 131: ip1 = ip1->i_fp; ! 132: } ! 133: } while (changes); ! 134: } ! 135: ! 136: /* ! 137: * This routine performs the nitty gritty ! 138: * of bumping an instruction to a higher address because ! 139: * an sdi changed from short to long. ! 140: * The 'ip1' argument is a pointer to the INS of the jump. ! 141: * The 'ip2' argument is the node to be bumped by 'bump' bytes. ! 142: * Only labels and code in the same segment as the 'ip1' node are adjusted. ! 143: */ ! 144: sdibump(ip1, ip2, bump) register INS *ip1, *ip2; int bump; ! 145: { ! 146: register int type; ! 147: register SYM *sp; ! 148: ! 149: if ((type=ip2->i_type) == LLABEL) { ! 150: if ((sp=ip2->i_sp) == NULL) ! 151: cbotch("sdibump"); ! 152: if (sp->s_seg == ip1->i_pcseg) ! 153: sp->s_value += bump; ! 154: } else if (type==JUMP || type==CODE) { ! 155: if (ip2->i_pcseg == ip1->i_pcseg) ! 156: ip2->i_pc += bump; ! 157: } ! 158: } ! 159: ! 160: /* ! 161: * This routine checks if a node is an optimizable short jump. ! 162: * The node must be a jump, ! 163: * it must be short and it must either be the unconditional ! 164: * jump or one of the jumps that has a reverse. ! 165: */ ! 166: isoptjump(ip1) register INS *ip1; ! 167: { ! 168: register int rel; ! 169: ! 170: if (ip1->i_type==JUMP && ip1->i_long==0) { ! 171: rel = ip1->i_rel; ! 172: if (rel!=ZJCXZ && rel!=ZLOOP && rel!=ZLOOPE && rel!=ZLOOPNE) ! 173: return 1; ! 174: } ! 175: return 0; ! 176: } ! 177: ! 178: /* ! 179: * Assemble a line. ! 180: * If pass 1 the binary goes straight out. ! 181: * The ip1 argument points to the INS node that is to be assembled. ! 182: */ ! 183: assemble(ip1) register INS *ip1; ! 184: { ! 185: SIGNEDADDRESS disp; ! 186: int opbits, opcode, ostyle, prefix, m1, m2, m3, regm, rn, shortflag; ! 187: int align, count; ! 188: sizeof_t length; ! 189: OPINFO *opinfop; ! 190: SYM *sp; ! 191: AFIELD a1; ! 192: int is16bit; /* Current op needs 16-bit prefix */ ! 193: ! 194: switch (ip1->i_type) { ! 195: ! 196: case ENTER: ! 197: pcdot[pcseg] = pc; ! 198: pcseg = ip1->i_seg; ! 199: pc = pcdot[pcseg]; ! 200: if (pass != 0) ! 201: genseg(pcseg); ! 202: break; ! 203: ! 204: case BLOCK: ! 205: if ((length=ip1->i_len) != 0) { ! 206: if (pcseg == SBSS) { ! 207: pc += length; ! 208: if (pass != 0) ! 209: dot += length; ! 210: } else if (pass != 0) ! 211: outnzb(length, 0); ! 212: } ! 213: break; ! 214: ! 215: case ALIGN: ! 216: if ((align = ip1->i_align) != 0 && (pc & (align-1)) != 0) { ! 217: count = align - (pc & (align-1)); ! 218: if (pcseg == SBSS) { ! 219: pc += count; ! 220: if (pass != 0) ! 221: dot += count; ! 222: } else { ! 223: while (count--) ! 224: asmab(0); ! 225: } ! 226: } ! 227: break; ! 228: ! 229: case JUMP: ! 230: ip1->i_pc = pc; ! 231: ip1->i_pcseg = pcseg; ! 232: if ((sp=ip1->i_sp) == NULL) { ! 233: sp = llookup(ip1->i_labno, 0); ! 234: ip1->i_sp = sp; ! 235: } ! 236: if (pass != 0) { ! 237: if (sp==NULL || (sp->s_flag&S_DEF)==0) ! 238: cbotch("undef"); ! 239: if (ip1->i_long == 0) { ! 240: if (sp->s_seg != ip1->i_pcseg) ! 241: cbotch("x seg #2"); ! 242: disp = sp->s_value - pc - 2; ! 243: if (disp < -128 || disp > 127) ! 244: cbotch("reach, disp=%d", disp); ! 245: } ! 246: } ! 247: opbits = opinfo[ip1->i_rel].op_opcode; ! 248: if (ip1->i_long == 0) { ! 249: /* Short JMP or Jcc, i8 displacement. */ ! 250: asmab(opbits); ! 251: asmab(disp); ! 252: } else { ! 253: /* Long jumps, see comments on sdi() above. */ ! 254: if (ip1->i_rel != ZJMP) { ! 255: /* Jcc i8 becomes Jcc i32. */ ! 256: disp = sp->s_value - pc - 6; ! 257: asmab(ESC_2B); /* 2-byte escape */ ! 258: asmab(opbits+0x10); /* 7x becomes 8x */ ! 259: asmal(disp); ! 260: break; ! 261: } ! 262: disp = sp->s_value - pc - 5; ! 263: asmab(0xE9); /* Jump i32 */ ! 264: asmal(disp); ! 265: } ! 266: break; ! 267: ! 268: case LLABEL: ! 269: if ((sp=ip1->i_sp) == NULL) { ! 270: sp = llookup(ip1->i_labno, 1); ! 271: ip1->i_sp = sp; ! 272: } ! 273: sp->s_seg = pcseg; ! 274: sp->s_value = pc; ! 275: break; ! 276: ! 277: case LLLINK: ! 278: if ((sp=ip1->i_sp) == NULL) { ! 279: sp = llookup(ip1->i_labno, 0); ! 280: ip1->i_sp = sp; ! 281: } ! 282: if (pass!=0 && (sp==NULL || (sp->s_flag&S_DEF)==0)) ! 283: cbotch("undef"); ! 284: a1.a_mode = A_DIR; ! 285: a1.a_sp = sp; ! 286: a1.a_value = 0; ! 287: asmxl(&a1, 0); ! 288: break; ! 289: ! 290: case CODE: ! 291: ip1->i_pc = pc; ! 292: ip1->i_pcseg = pcseg; ! 293: opcode = ip1->i_op; ! 294: opinfop = &opinfo[opcode]; ! 295: opbits = opinfop->op_opcode; ! 296: if (opinfop->op_flag & OP_WORD) { ! 297: is16bit = 1; ! 298: asmab(0x66); /* 16-bit operand prefix */ ! 299: } else ! 300: is16bit = 0; ! 301: switch (ostyle = opinfop->op_style) { ! 302: ! 303: case OF_INH2: ! 304: asmab(opbits); ! 305: asmab(0x0A); ! 306: break; ! 307: ! 308: case OF_INH: ! 309: asmab(opbits); ! 310: break; ! 311: ! 312: case OF_PUSH: ! 313: case OF_POP: ! 314: m1 = MOD(af_p(ip1, 0)); ! 315: rn = REGM(af_p(ip1, 0)); ! 316: if ((ostyle == OF_PUSH) && (m1 == A_IMM)) { ! 317: if (isimmbyte(af_p(ip1, 0))) { ! 318: asmab(0x6A); ! 319: asmxb(af_p(ip1, 0), 0); ! 320: } else if (!is16bit) { ! 321: asmab(0x68); ! 322: asmxl(af_p(ip1, 0), 0); ! 323: } else { ! 324: asmab(0x68); ! 325: asmxw(af_p(ip1, 0), 0); ! 326: } ! 327: break; ! 328: } ! 329: if (m1 == A_DR || m1 == A_WR) { ! 330: asmab((ostyle == OF_PUSH) ? 0x50 | rn ! 331: : 0x58 | rn); ! 332: break; ! 333: } ! 334: if (ostyle == OF_PUSH) ! 335: asmgen(0xFF, 0x30, af_p(ip1, 0)); ! 336: else ! 337: asmgen(0x8F, 0x00, af_p(ip1, 0)); ! 338: break; ! 339: ! 340: case OF_SHR: ! 341: prefix = 0xD0 | (opbits&W); ! 342: opbits &= ~W; ! 343: if (ip1->i_af[1].a_mode == A_RCL) ! 344: prefix |= 0x02; ! 345: else if ((MOD(af_p(ip1, 1))) != A_IMM ! 346: || ip1->i_af[1].a_sp != NULL) ! 347: aerr(ip1); ! 348: disp = ip1->i_af[1].a_value; ! 349: if ((ip1->i_af[1].a_mode != A_RCL) && (disp != 1)) { ! 350: /* 286 shift immediate */ ! 351: prefix &= 0xEF; /* Change 0xD0|W to 0xC0|W */ ! 352: asmgen(prefix, opbits, af_p(ip1, 0)); ! 353: asmab(disp); ! 354: break; ! 355: } ! 356: asmgen(prefix, opbits, af_p(ip1, 0)); ! 357: break; ! 358: ! 359: case OF_ICALL: ! 360: asmgen(0xFF, opbits, af_p(ip1, 0)); ! 361: break; ! 362: ! 363: case OF_CALL: ! 364: if ((MOD(af_p(ip1, 0))) != A_DIR) ! 365: aerr(ip1); ! 366: asmab(0xE8); ! 367: asmxl(af_p(ip1, 0), 1); ! 368: break; ! 369: ! 370: case OF_XCALL: ! 371: if ((MOD(af_p(ip1, 0))) != A_DIR) ! 372: aerr(ip1); ! 373: asmab(0x9A); ! 374: asmxl(af_p(ip1, 0), 0); ! 375: break; ! 376: ! 377: case OF_DOPS: ! 378: case OF_DOP: ! 379: m1 = MOD(af_p(ip1, 0)); ! 380: m2 = MOD(af_p(ip1, 1)); ! 381: if (m2 == A_IMM) { ! 382: /* ! 383: * Immediate right operand. ! 384: * Use the special EAX etc. form if possible, ! 385: * but not for byte immediate operands, ! 386: * where the byte immediate form is better. ! 387: */ ! 388: shortflag = (ostyle == OF_DOPS) && isimmbyte(af_p(ip1, 1)); ! 389: if (isEAX(af_p(ip1, 0)) ! 390: && (!shortflag || opbits == 0x84 || opbits == 0x85)) { ! 391: /* Left operand is EAX, AX or AL. */ ! 392: if (opbits == 0x85) ! 393: opbits = 0xA9; /* test */ ! 394: else if (opbits == 0x84) ! 395: opbits = 0xA8; /* testb */ ! 396: else ! 397: opbits |= 0x04; /* use EAX form */ ! 398: asmab(opbits); ! 399: } else { ! 400: /* ! 401: * Left operand is not EAX, AX or AL, ! 402: * or (right operand is byte immediate ! 403: * and operator is not TEST). ! 404: */ ! 405: if (opbits==0x84 || opbits==0x85) { ! 406: regm = 0; ! 407: if (opbits == 0x84) ! 408: opbits = 0xF6; /* test */ ! 409: else ! 410: opbits = 0xF7; /* testb */ ! 411: } else { ! 412: regm = opbits & 0x38; ! 413: opbits = (opbits&W)|0x80; ! 414: if (shortflag) ! 415: opbits |= 0x02; ! 416: } ! 417: asmgen(opbits, regm, af_p(ip1, 0)); ! 418: } ! 419: if (shortflag || (opbits&W)==0) ! 420: asmxb(af_p(ip1, 1), 0); ! 421: else if (!is16bit) ! 422: asmxl(af_p(ip1, 1), 0); ! 423: else ! 424: asmxw(af_p(ip1, 1), 0); ! 425: break; ! 426: } ! 427: /* To reg */ ! 428: if (m1==A_DR || m1==A_BR || m1==A_WR) { ! 429: /* Test[b] */ ! 430: if (opbits!=0x84 && opbits!=0x85) ! 431: opbits |= 0x02; /* D */ ! 432: asmgen(opbits, (REGM(af_p(ip1, 0)))<<3, ! 433: af_p(ip1, 1)); ! 434: break; ! 435: } ! 436: /* To mem */ ! 437: asmgen(opbits, (REGM(af_p(ip1, 1)))<<3, ! 438: af_p(ip1, 0)); ! 439: break; ! 440: ! 441: case OF_MUL3: ! 442: m1 = MOD(af_p(ip1, 0)); ! 443: m2 = MOD(af_p(ip1, 1)); ! 444: m3 = MOD(af_p(ip1, 2)); ! 445: if ((m1 != A_DR && m1 != A_WR) || m3 != A_IMM) ! 446: aerr(ip1); ! 447: shortflag = 0; ! 448: if (isimmbyte(af_p(ip1, 2))) { ! 449: shortflag = 1; ! 450: opbits |= 0x02; /* Change 0x69 to 0x6B */ ! 451: } ! 452: asmgen(opbits, (REGM(af_p(ip1, 0)))<<3, af_p(ip1, 1)); ! 453: if (shortflag) ! 454: asmxb(af_p(ip1, 2), 0); ! 455: else if (!is16bit) ! 456: asmxl(af_p(ip1, 2), 0); ! 457: else ! 458: asmxw(af_p(ip1, 2), 0); ! 459: break; ! 460: ! 461: case OF_SOP: ! 462: m1 = MOD(af_p(ip1, 0)); ! 463: prefix = ((opbits < 0x10)?0xFE:0xF6) | (opbits&W); ! 464: opbits &= ~W; ! 465: if (prefix==0xFF && (m1==A_DR || m1==A_WR)) { ! 466: asmab(0x40 | opbits | ! 467: (REGM(af_p(ip1, 0)))); ! 468: break; ! 469: } ! 470: asmgen(prefix, opbits, af_p(ip1, 0)); ! 471: break; ! 472: ! 473: case OF_LEA: ! 474: m1 = MOD(af_p(ip1, 0)); ! 475: m2 = MOD(af_p(ip1, 1)); ! 476: if (m1!=A_DR || (m2!=A_DIR && m2!=A_XB)) ! 477: aerr(ip1); ! 478: asmgen(opbits, (REGM(af_p(ip1, 0)))<<3, ! 479: af_p(ip1, 1)); ! 480: break; ! 481: ! 482: case OF_MOV: ! 483: m1 = MOD(af_p(ip1, 0)); ! 484: m2 = MOD(af_p(ip1, 1)); ! 485: /* Sanity check: register specs vs. opcode. */ ! 486: opcode = ip1->i_op; ! 487: #if 1 ! 488: /* ! 489: * Kludge flakey register references generated ! 490: * by the load table in n1/i386/tables/leaves.t. ! 491: * There must be a better way. ! 492: */ ! 493: if ((opcode == ZMOVW && m2 == A_DR) ! 494: || (opcode == ZMOVB && (m2 == A_WR || m2 == A_DR))) { ! 495: ip1->i_af[1].a_mode &= ~A_AMOD; ! 496: ip1->i_af[1].a_mode |= (opcode == ZMOVW) ? A_WR : A_BR; ! 497: m2 = MOD(af_p(ip1, 1)); ! 498: } ! 499: #endif ! 500: if (((opcode != ZMOV ) && ((m1 == A_DR) || (m2 == A_DR))) ! 501: || ((opcode != ZMOVW) && ((m1 == A_WR) || (m2 == A_WR))) ! 502: || ((opcode != ZMOVB) && ((m1 == A_BR) || (m2 == A_BR)))) ! 503: aerr(ip1); ! 504: if (m2 == A_IMM) { ! 505: /* Immediate moves. */ ! 506: if (m1 == A_DR) { ! 507: /* Immediate to dword register. */ ! 508: asmab(0xB8 | ! 509: (REGM(af_p(ip1, 0)))); ! 510: asmxl(af_p(ip1, 1), 0); ! 511: break; ! 512: } else if (m1 == A_BR) { ! 513: /* Immediate to byte register. */ ! 514: asmab(0xB0 | ! 515: (REGM(af_p(ip1, 0)))); ! 516: asmxb(af_p(ip1, 1), 0); ! 517: break; ! 518: } else if (m1 == A_WR) { ! 519: /* Immediate to word register. */ ! 520: asmab(0xB8 | ! 521: (REGM(af_p(ip1, 0)))); ! 522: asmxw(af_p(ip1, 1), 0); ! 523: break; ! 524: } ! 525: /* Immediate to memory. */ ! 526: asmgen((0xC6 | (opbits&W)), 0, af_p(ip1, 0)); ! 527: if ((opbits&W) == 0) ! 528: asmxb(af_p(ip1, 1), 0); ! 529: else if (!is16bit) ! 530: asmxl(af_p(ip1, 1), 0); ! 531: else ! 532: asmxw(af_p(ip1, 1), 0); ! 533: break; ! 534: } ! 535: if (isEAX(af_p(ip1, 0)) && m2==A_DIR) { ! 536: /* Direct to AL, AX, or EAX. */ ! 537: asmab(0xA0 | (opbits&W)); ! 538: asmxl(af_p(ip1, 1), 0); ! 539: break; ! 540: } ! 541: if (m1==A_DIR && isEAX(af_p(ip1, 1))) { ! 542: /* AL, AX or EAX to direct. */ ! 543: asmab(0xA2 | (opbits&W)); ! 544: asmxl(af_p(ip1, 0), 0); ! 545: break; ! 546: } ! 547: if (m1==A_DR || m1==A_WR || m1==A_BR) { ! 548: /* To dword, word or byte register. */ ! 549: asmgen(opbits|D, ! 550: (REGM(af_p(ip1, 0)))<<3, ! 551: af_p(ip1, 1)); ! 552: break; ! 553: } ! 554: if (m2==A_DR || m2==A_WR || m2==A_BR) { ! 555: /* From dword, word or byte register. */ ! 556: asmgen(opbits, ! 557: (REGM(af_p(ip1, 1)))<<3, ! 558: af_p(ip1, 0)); ! 559: break; ! 560: } ! 561: aerr(ip1); ! 562: break; ! 563: ! 564: case OF_MUL: ! 565: prefix = 0xF6 | (opbits&W); ! 566: opbits &= ~W; ! 567: asmgen(prefix, opbits, af_p(ip1, 0)); ! 568: break; ! 569: ! 570: case OF_WORD: ! 571: case OF_BYTE: ! 572: case OF_LONG: ! 573: case OF_LPTR: ! 574: case OF_GPTR: ! 575: if ((MOD(af_p(ip1, 0))) != A_DIR) ! 576: aerr(ip1); ! 577: if (ostyle == OF_BYTE) ! 578: asmxb(af_p(ip1, 0), 0); ! 579: else if (ostyle == OF_WORD) ! 580: asmxw(af_p(ip1, 0), 0); ! 581: else ! 582: asmxl(af_p(ip1, 0), 0); ! 583: break; ! 584: ! 585: case OF_2B: ! 586: /* ! 587: * movsxw and movzxw do not take 16-bit operand prefix, ! 588: * hence do not have OP_WORD set in optab.c; ! 589: * now tell asmgen the operand is a 16-bit object. ! 590: */ ! 591: if ((opinfop->op_flag & OP_BYTE) == 0) ! 592: is16bit = 1; ! 593: m1 = MOD(af_p(ip1, 0)); ! 594: m2 = MOD(af_p(ip1, 1)); ! 595: #if 0 ! 596: if (m1 != A_DR || m2 == A_DR ! 597: || (is16bit && m2 == A_BR) ! 598: || (!is16bit && m2 == A_WR)) ! 599: aerr(ip1); ! 600: #else ! 601: if (m1 != A_DR) ! 602: aerr(ip1); ! 603: /* ! 604: * Kludge flakey register references generated ! 605: * by the widen table in n1/i386/tables/leaves.t. ! 606: * There must be a better way. ! 607: */ ! 608: if (m2 == A_DR) { ! 609: ip1->i_af[1].a_mode &= ~A_AMOD; ! 610: ip1->i_af[1].a_mode |= (is16bit) ? A_WR : A_BR; ! 611: } ! 612: #endif ! 613: asmab(ESC_2B); ! 614: asmgen(opbits, ! 615: (REGM(af_p(ip1, 0)))<<3, ! 616: af_p(ip1, 1)); ! 617: break; ! 618: ! 619: /* ! 620: * 8087 or 80287 floating point operations. ! 621: * See comments preceding "asmfwait()" below. ! 622: */ ! 623: case OF_FWAIT: ! 624: asmfwait(); ! 625: break; ! 626: ! 627: case OF_FD9: ! 628: asmfop(0xD9, 0); ! 629: asmab(opbits); ! 630: break; ! 631: ! 632: case OF_FDD: ! 633: asmfop(0xDD, 0); ! 634: asmab(opbits); ! 635: break; ! 636: ! 637: case OF_FDE: ! 638: asmfop(0xDE, 0); ! 639: asmab(opbits); ! 640: break; ! 641: ! 642: case OF_FRM: ! 643: asmfop(ESC | (opbits & 0x07), 0); ! 644: asmgen(-1, opbits&0x38, af_p(ip1, 0)); ! 645: break; ! 646: ! 647: default: ! 648: cbotch("cannot assemble %d", opcode); ! 649: } ! 650: } ! 651: } ! 652: ! 653: /* ! 654: * Output an effective address. ! 655: * Understands ModR/M byte and SIB and all that. ! 656: * An opcode of -1 is a flag that says don't put ! 657: * out the opcode and treat a register address field as an error. ! 658: * It is used for the 8087. ! 659: * The r field is preshifted left by 3 bits. ! 660: */ ! 661: asmgen(op, r, afp) int op, r; register AFIELD *afp; ! 662: { ! 663: SIGNEDADDRESS disp; ! 664: int mode, regm, sib, sibflag; ! 665: ! 666: if (op >= 0) ! 667: asmab(op); ! 668: mode = MOD(afp); ! 669: regm = REGM(afp); ! 670: if (mode==A_IMM) ! 671: cbotch("asmgen op=%d r=%d mode=%d regm=%d", ! 672: op, r, mode, regm); ! 673: else if (mode==A_DR || mode==A_BR || mode==A_WR) { ! 674: /* Register: mod=11. */ ! 675: if (op < 0) ! 676: cbotch("asmgen"); ! 677: asmab(0xC0 | r | regm); ! 678: return; ! 679: } else if (mode == A_DIR) { ! 680: /* Direct: mod=00, r/m=5, 32-bit displacement. */ ! 681: asmab(0x05 | r); ! 682: asmxl(afp, 0); ! 683: return; ! 684: } ! 685: /* Neither immediate nor register nor direct, must be symbol based or indexed. */ ! 686: sibflag = (mode == A_XSIB); ! 687: if (sibflag) { ! 688: regm = 4; /* r/m=4 indicates SIB present */ ! 689: sib = SIB(afp->a_mode); /* extract SIB contents */ ! 690: if ((sib & A_REGM) == 5) { ! 691: /* SIB with no base, 32-bit displacement: mod=00. */ ! 692: asmab(r | regm); ! 693: asmab(sib); ! 694: asmxl(afp, 0); ! 695: return; ! 696: } ! 697: } ! 698: if (afp->a_sp == NULL) { ! 699: /* Not symbol based. */ ! 700: disp = afp->a_value; ! 701: if (disp == 0) { ! 702: /* No displacement, mod=00. */ ! 703: if (regm != 5) { ! 704: asmab(r | regm); ! 705: if (sibflag) ! 706: asmab(sib); ! 707: return; ! 708: } ! 709: } ! 710: if (disp >= -128 && disp <= 127) { ! 711: /* 8-bit displacement, mod=01. */ ! 712: asmab(0x40 | r | regm); ! 713: if (sibflag) ! 714: asmab(sib); ! 715: asmab(disp); ! 716: return; ! 717: } ! 718: /* Fall through for 32-bit displacement... */ ! 719: } ! 720: /* ! 721: * Symbol based (always requires 4-byte value as relocation target) ! 722: * or indexed with 32-bit displacement, mod=10. ! 723: */ ! 724: asmab(0x80 | r | regm); ! 725: if (sibflag) ! 726: asmab(sib); ! 727: asmxl(afp, 0); ! 728: } ! 729: ! 730: /* ! 731: * Output an absolute byte. ! 732: * Toss the byte away if this is not the second pass. ! 733: * Check for compiling code into the bss segment. ! 734: */ ! 735: asmab(b) int b; ! 736: { ! 737: if (pass != 0) { ! 738: berr(); ! 739: outab(b); ! 740: } ! 741: ++pc; ! 742: } ! 743: ! 744: /* ! 745: * Output an absolute word. ! 746: * Toss the word away if this is not the second pass. ! 747: * Check for compiling code into the bss segment. ! 748: */ ! 749: asmaw(w) int w; ! 750: { ! 751: if (pass != 0) { ! 752: berr(); ! 753: outaw(w); ! 754: } ! 755: pc += 2; ! 756: } ! 757: ! 758: /* ! 759: * Output an absolute dword (ival_t). ! 760: * Toss the word away if this is not the second pass. ! 761: * Check for compiling code into the bss segment. ! 762: */ ! 763: asmal(i) ival_t i; ! 764: { ! 765: if (pass != 0) { ! 766: berr(); ! 767: outal(i); ! 768: } ! 769: pc += 4; ! 770: } ! 771: ! 772: /* ! 773: * Output a general byte. ! 774: * The 'afp' argument is a pointer to an 'afield'. ! 775: * The 'flag' is true for pc relative addressing. ! 776: */ ! 777: asmxb(afp, flag) register AFIELD *afp; int flag; ! 778: { ! 779: if (pass != 0) { ! 780: berr(); ! 781: outxb(afp->a_sp, afp->a_value, flag); ! 782: } ! 783: ++pc; ! 784: } ! 785: ! 786: /* ! 787: * Output a general word. ! 788: * The 'afp' parameter is a pointer to an 'afield'. ! 789: * The 'flag' is true for pc relative addressing. ! 790: */ ! 791: asmxw(afp, flag) register AFIELD *afp; int flag; ! 792: { ! 793: if (pass != 0) { ! 794: berr(); ! 795: outxw(afp->a_sp, afp->a_value, flag); ! 796: } ! 797: pc += 2; ! 798: } ! 799: ! 800: /* ! 801: * Output a general word. ! 802: * The 'afp' parameter is a pointer to an 'afield'. ! 803: * The 'flag' is true for pc relative addressing. ! 804: */ ! 805: asmxl(afp, flag) register AFIELD *afp; int flag; ! 806: { ! 807: if (pass != 0) { ! 808: berr(); ! 809: outxl(afp->a_sp, afp->a_value, flag); ! 810: } ! 811: pc += 4; ! 812: } ! 813: ! 814: /* ! 815: * Notes on 8087 and 80287 opcode generation: ! 816: * The 8086 does not check the coprocessor BUSY line when it encounters ! 817: * a coprocessor escape (an 8087 opcode). ! 818: * Therefore, an FWAIT must precede every 8087 opcode. ! 819: * Sequences which require coprocessor synchronization ! 820: * (e.g., awaiting completion of store from 8087 to 8086 memory) ! 821: * can include explicit FWAITs which do not precede 8087 ops. ! 822: * The 80286 checks its coprocessor BUSY line when it sees an 80287 opcode. ! 823: * Therefore, the 80287 does not require an FWAIT before each 80287 opcode, ! 824: * but explicit FWAITs are still required for synchronization. ! 825: * ! 826: * If EMUFIXUPS is true when the compiler is built, ! 827: * the OMF output writer targets the FWAIT which precedes an 8087 opcode ! 828: * with a magic "M:..." fixup; ! 829: * this happens only in the OMF output writer n1/i8086/outomf.c. ! 830: * The linker can then create objects which use either 8087 hardware ! 831: * or software floating point emulation. In the latter case, the ! 832: * linker changes the 8087 instructions into traps to the emulator. ! 833: * ! 834: * If the compile-time variant VEMU87 is set, ! 835: * the compiler writes "call emu87" before each 8087 opcode ! 836: * and suppresses the leading FWAIT. ! 837: * The emulator "emu87" can execute "fwait; ret" or replace "call emu87" with ! 838: * "nop; nop; fwait" if an 8087 is actually present at runtime. ! 839: */ ! 840: ! 841: /* ! 842: * Output an explicit FWAIT opcode for the 8087. ! 843: * The byte will be fiddled by an M:_WT fixup #if EMUFIXUPS. ! 844: */ ! 845: asmfwait() ! 846: { ! 847: hasfloat = 1; ! 848: #if 0 ! 849: if (isvariant(VEMU87)) { ! 850: asmemucall(); /* call emu87 */ ! 851: return; /* and suppress the FWAIT */ ! 852: } ! 853: #endif ! 854: if (pass != 0) { ! 855: berr(); ! 856: outfb(WAIT); ! 857: } ! 858: ++pc; ! 859: } ! 860: ! 861: /* ! 862: * Output an 8087 opcode for the 8087. ! 863: * The "prefix" argument is just the A_PREFX code from the address. ! 864: * The opcode will be preceded by an FWAIT if necessary, ! 865: * and the FWAIT will be fiddled by an M:_W?S fixup #if EMUFIXUPS. ! 866: */ ! 867: asmfop(op, prefix) ! 868: { ! 869: hasfloat = 1; ! 870: #if 0 ! 871: if (isvariant(VEMU87)) { ! 872: asmemucall(); /* call emu87 */ ! 873: if (pass != 0) ! 874: outfb(op); /* and suppress FWAIT */ ! 875: pc++; ! 876: return; ! 877: } ! 878: #endif ! 879: if (pass != 0) { ! 880: berr(); ! 881: outfb(op); /* no FWAIT for 80x87 */ ! 882: } ! 883: pc++; ! 884: } ! 885: ! 886: #if 0 ! 887: /* ! 888: * Assemble a call to the IEEE software floating point 8087 emulator. ! 889: */ ! 890: asmemucall(){ ! 891: if (pass != 0) { ! 892: berr(); ! 893: outemucall(); ! 894: } ! 895: pc += 5; ! 896: } ! 897: ! 898: /* ! 899: * Output a call to the 8087 emulator. ! 900: * Called from above and from genepilog (for FWAIT in epilog). ! 901: */ ! 902: outemucall() ! 903: { ! 904: static SYM *emu87p; ! 905: ! 906: if (emu87p == NULL) ! 907: emu87p = glookup("emu87", 0); ! 908: outab(0x9A); /* far call */ ! 909: outxl(emu87p, 0, 0); /* offset, absolute */ ! 910: } ! 911: #endif ! 912: ! 913: /* Oops. */ ! 914: aerr(ip1) register INS *ip1; ! 915: { ! 916: register SYM *sp; ! 917: register int i; ! 918: ! 919: printf("aerr: op=%d\n", ip1->i_op); ! 920: for (i = 0; i < ip1->i_naddr; ++i) { ! 921: printf("Operand %d:", i); ! 922: printf(" mode=%04x", ip1->i_af[i].a_mode); ! 923: printf(" offs=%d", ip1->i_af[i].a_value); ! 924: if ((sp=ip1->i_af[i].a_sp) != NULL) { ! 925: if ((sp->s_flag&S_LABNO) != 0) ! 926: printf(" off L%d", sp->s_labno); ! 927: else ! 928: printf(" off %s", sp->s_id); ! 929: } ! 930: printf("\n"); ! 931: } ! 932: cbotch("aerr"); ! 933: } ! 934: ! 935: /* BSS oops. */ ! 936: berr() ! 937: { ! 938: if (pcseg == SBSS) ! 939: cbotch("bss"); ! 940: } ! 941: ! 942: /* Return true if afp represents AL, AX or EAX. */ ! 943: isEAX(afp) register AFIELD *afp; ! 944: { ! 945: register int mode; ! 946: ! 947: mode = afp->a_mode; ! 948: return (mode==A_REAX || mode==A_RAX || mode==A_RAL); ! 949: } ! 950: ! 951: /* ! 952: * This routine returns true if the argument AFIELD is a valid byte immediate, ! 953: * as used by the special s:w encoding on some instructions. ! 954: * This lets the assembler write imm8 (sign-extended by i386) rather than ! 955: * an imm32 or imm16. ! 956: * The legality of the mode and the fact that ! 957: * the AFIELD is an immediate have already been checked. ! 958: */ ! 959: isimmbyte(afp) register AFIELD *afp; ! 960: { ! 961: register ADDRESS value; ! 962: ! 963: if (afp->a_sp == NULL) { ! 964: value = afp->a_value & 0xFFFFFF80L; /* top 25 bits */ ! 965: if (value==0xFFFFFF80L || value==0L) ! 966: return 1; ! 967: } ! 968: return 0; ! 969: } ! 970: ! 971: /* end of n2/i386/asm.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.