/* asmopc.c -- microsoft 80x86 assembler ** ** microsoft (r) macro assembler ** copyright (c) microsoft corp 1986. all rights reserved ** ** randy nevin ** ** 10/90 - Quick conversion to 32 bit by Jeff Spencer */ #include #include "asm86.h" #include "asmfcn.h" #include "asmctype.h" #include "asmopcod.h" static SHORT CODESIZE nolong(struct psop *); VOID CODESIZE pmovx(struct parsrec *); VOID CODESIZE psetcc(struct parsrec *); VOID CODESIZE pbit(struct parsrec *); VOID CODESIZE pbitscan(struct parsrec *); CODESIZE checkwreg(struct psop *); VOID PASCAL CODESIZE pclts (void); #define M_ESCAPE (M_PRELJMP | M_PCALL | M_PJUMP | M_PRETURN | M_PINT | M_PARITH | \ M_PINOUT | M_PLOAD | M_PSTR | M_PESC | M_PBOUND | M_PARSL) #define M_ERRIMMED (M_PSHIFT | M_PARITH | M_PINCDEC | M_PCALL | M_PJUMP | \ M_PMOV | M_PSTR | M_PRELJMP | M_PGENARG | M_PXCHG | \ M_PBOUND | M_PCLTS | M_PDESCRTBL | M_PDTTRSW | M_PARSL | \ M_PARPL | M_PVER) /* EMITcall decides what type of calljump is present and outputs the appropriate code. Coding of last 4 args to EMITcall: DIRto: Direct to different segment(inter) DIRin: DIRect in same segment(intra) INDto: Indirect to different segment(inter) INDin: Indirect in same segment(intra) */ /*** emitcall - emit call * * emitcall (dirin, dirto, indin, indto, p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE emitcall ( UCHAR dirin, UCHAR dirto, UCHAR indin, UCHAR indto, struct parsrec *p ){ register struct psop *pso; /* parse stack operand structure */ char fNop = FALSE; pso = &(p->dsc1->dsckind.opnd); if (!isdirect(pso)) { /* Have indexing? */ if (pso->dsize == 0) { /* make [BX] be word */ pso->dsize = wordsize; pso->dtype |= xltsymtoresult[DVAR]; } else if (pso->dsize >= CSFAR) { errorc (E_ASD); pso->dsize = wordsize; /* Data only, force word */ } } if ((M_DATA & pso->dtype) && pso->dflag == UNDEFINED) pso->dflag = KNOWN; if (pso->dsize == CSNEAR || (pso->dflag == UNDEFINED && !(M_PTRSIZE & pso->dtype))) { #ifndef FEATURE if (regsegment[CSSEG] == pFlatGroup) pso->dcontext = pFlatGroup; #endif if (regsegment[CSSEG] != pso->dcontext && pso->dflag != XTERNAL) errorc (E_JCD); /* Can't go near to dif assume */ pso->dsize = wordsize; pso->dtype |= M_SHRT; emitopcode (dirin); } else if (pso->dsize == CSFAR) { if (M_FORTYPE & pso->dtype) /* Forward far */ errorc (E_FOF); /* Couldn't guess */ pso->fixtype = FPOINTER; pso->dsize = wordsize; if (pso->dsegment) { /* target has different segment size */ pso->dsize = pso->dsegment->symu.segmnt.use32; if (pso->dsize != wordsize) { if (!(M_BACKREF & pso->dsegment->attr)) errorc (E_FOF); /* Forward mixed type */ emitsize(0x66); if (wordsize == 4) { /* set modes so you get the */ pso->mode = 0; /* correct OFFSET size */ pso->rm = 6; fNop++; /* 16:32 -> 0x66 16:16 */ } else { pso->fixtype = F32POINTER; pso->mode = 8; pso->rm = 5; } } } pso->dsize += 2; emitopcode (dirto); } else { #ifdef V386 emit67(pso, NULL); #endif if ((pso->dsize == wordsize) || (pso->dsize == wordsize+2)) { /* Indirect */ #ifdef V386 /* if mode is through register, then it must be a near * call, so we can tell if its a foreign mode call */ if (pso->dsize != wordsize && pso->mode == 3) emitsize(0x66); #endif emitescape (p->dsc1, p->defseg); emitopcode (255); /* must use defseg([BP]) */ if (pso->dsize == wordsize || pso->mode == 3) /* Near indirect */ emitmodrm ((USHORT)pso->mode, (USHORT)(indin>>3), pso->rm); else /* Far indirect */ emitmodrm ((USHORT)pso->mode, (USHORT)(indto>>3), pso->rm); } #ifdef V386 else if (pso->dsize == 2 || pso->dsize == 6) { /* indirect foreign mode call */ /* in 16 bit mode normal near and far get done by the * above, and only 32 bit mode far gets here. for 32 * bit normal only 16 bit near. the latter seems a bit * useless....*/ emitsize(0x66); emitescape (p->dsc1, p->defseg); emitopcode (255); /* must use defseg([BP]) */ if (pso->dsize == 2) /* Near indirect */ emitmodrm ((USHORT)pso->mode, (USHORT)(indin>>3), pso->rm); else /* Far indirect */ emitmodrm ((USHORT)pso->mode, (USHORT)(indto>>3), pso->rm); } #endif else /* Bad size */ errorc (E_IIS); } emitrest (p->dsc1); if (fNop) emitnop(); } /*** movesegreg - emit move to/from segment register * * movesegreg (first, p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE movesegreg ( char first, struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ DSCREC *t; if (!first) { if (p->dsc1->dsckind.opnd.mode != 3 && impure) /* MOV cs:mem,segreg */ errorc (E_IMP); t = p->dsc1; p->dsc1 = p->dsc2; p->dsc2 = t; } pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); if ((pso2->dsize | wordsize) == 6) emitsize(0x66); emitopcode ((UCHAR)(first? 142: 140)); errorimmed (p->dsc2); #ifdef V386 rangecheck (&pso1->rm, (UCHAR)((cputype&P386)?5:3)); #else rangecheck (&pso1->rm, (UCHAR)3); #endif if ((pso2->mode == 3) && (pso2->dsegment->symu.regsym.regtype == SEGREG)) errorc (E_WRT); /* MOV segreg,segreg not allowed */ if (pso2->sized && !pso2->w) errorc (E_IIS); if (first && (pso1->rm == CSSEG)) /* CS illegal */ errorc (E_CSI); emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); emitrest (p->dsc2); } #ifdef V386 /*** movecreg - emit move to/from control/debug/test register * * movecreg (first, p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE movecreg ( char first, struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ UCHAR opbase; if ((cputype&(P386|PROT)) != (P386|PROT)) { errorc(E_WRT); return; } emitopcode (0x0F); pso1 = &(p->dsc1->dsckind.opnd); opbase = 0x22; if (first) pso2 = &(p->dsc2->dsckind.opnd); else{ opbase = 0x20; pso2 = pso1; pso1 = &(p->dsc2->dsckind.opnd); } if ((pso2->dsegment->symkind != REGISTER) || (pso2->dsegment->symu.regsym.regtype != DWRDREG)) errorc (E_OCI); if ((pso1->rm&030) == 020) /* test register */ opbase += 2; emitopcode((UCHAR)(opbase + (pso1->rm >> 3))); emitmodrm((USHORT)3, (USHORT)(pso1->rm & 7), (USHORT)(pso2->rm & 7)); if (pso2->mode != 3) /* only allowed to from register */ errorc(E_MBR); } #endif /*** emitmove - emit code for MOV reg and MOV accum * * emitmove (opcode, first, p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE emitmove ( UCHAR opc, char first, struct parsrec *p ){ DSCREC *t; char accummove; register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ accummove = (opc == 160); if (!first) { t = p->dsc1; p->dsc1 = p->dsc2; p->dsc2 = t; } pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); emit66 (pso1, pso2); if ((pso1->dsize != pso2->dsize) && pso2->sized) errorc (E_OMM); emitopcode ((UCHAR)(opc + ((accummove != first)? 2: 0) + pso1->w)); errorimmed (p->dsc2); if (!accummove) emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); emitrest (p->dsc2); } /*** moveaccum - move to/from accumulator and direct address * * moveaccum (first, p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE moveaccum ( char first, struct parsrec *p ){ if (!first && p->dsc1->dsckind.opnd.mode != 3 && impure) errorc (E_IMP); emitmove (160, first, p); } /*** movereg - emit general move between register and memory * * movereg (first, p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE movereg ( char first, struct parsrec *p ){ register struct psop *pso2; /* parse stack operand structure */ char flag; flag = FALSE; pso2 = &(p->dsc2->dsckind.opnd); /* Is not special */ if (pso2->mode == 3) /* 2nd is reg */ switch (pso2->dsegment->symu.regsym.regtype) { case SEGREG: /* Catch 2nd is SEGREG */ movesegreg (FALSE, p); return; #ifdef V386 case CREG: /* Catch 2nd is SEGREG */ movecreg (FALSE, p); return; #endif } if (p->dsc1->dsckind.opnd.mode != 3 && impure) errorc (E_IMP); emitmove (136, first, p); } /*** segdefault - return default segment for operand * * seg = segdefault (op); * * Entry * Exit * Returns * Calls */ USHORT PASCAL CODESIZE segdefault ( register char goo ){ register USHORT defseg; register char op; defseg = NOSEG; if (1 << goo & xoptoseg[opctype]) defseg = DSSEG; if (opctype == PSTR) { op = (opcbase == O_CMPS || opcbase == O_LODS || opcbase == O_OUTS); defseg = ((goo == FIRSTDS) != op)? ESSEG: DSSEG; } return (defseg); } /*** errorover - * * errorover (seg); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE errorover ( char seg ){ if (seg != ESSEG && seg != NOSEG) errorc (E_OES); } /*** checksize - check for memory s byte and immed is word * * checksize (p); * * Entry * Exit * Returns * Calls */ SHORT PASCAL CODESIZE checksize ( struct parsrec *p ){ OFFSET off; register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); if (pso1->sized) { /* Only set dsc2->w if dsc2 has no size. Set * dsc1->w to dsc2->w, not TRUE(WORD). [BX],WRD PTR 5 */ if (!pso2->sized) pso2->w = pso1->w; } else pso1->w = pso2->w; if (pso2->fixtype == FCONSTANT) { /* check for constant overflow */ off = (pso2->doffset > 0x7fffffff)? -pso2->doffset: pso2->doffset; if ((pso1->dsize == 1 && off > 0xff && off < 0xff00) || (pso1->dsize == 2 && off > 0xffff)) errorc (E_VOR); } /* check fixup'ed constants with implied sizes */ if ((pso1->sized && pso1->dsize != 2) && (pso2->dtype & (M_SEGMENT) || pso2->fixtype == FGROUPSEG || pso2->fixtype == FBASESEG)) errorc (E_OMM); if (!(pso1->sized || pso2->sized)) errorc (E_OHS); /* Also need to set field if operand 1 sized */ if (pso1->sized) {/* Force size */ pso2->dsize = pso1->dsize; pso2->w = pso1->w; } if (pso2->dsize == 1 && pso2->dflag == XTERNAL && pso2->fixtype != FHIGH) /* makes sure linker puts out correct stuff */ pso2->fixtype = FLOW; } /*** opcode - process opcode and emit code * * opcode (); * * Entry * Exit * Returns * Calls */ SHORT PASCAL CODESIZE opcode () { struct parsrec a; register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ long opctypemask; /* 1L << opctype */ char leaflag; a.dsc1 = a.dsc2 = NULL; pso1 = pso2 = NULL; impure = FALSE; if (xoptoargs[opctype] != NONE) { /* Evaulate 1st arg */ a.dirscan = lbufp; /* In case JMP should be SHORT */ a.defseg = segdefault (FIRSTDS); a.dsc1 = expreval (&a.defseg); if (noexp && (xoptoargs[opctype] == ONE || xoptoargs[opctype] == TWO)) errorc(E_MDZ); if ((pso1 = &(a.dsc1->dsckind.opnd)) && pso1->dtype & M_STRUCTEMPLATE) errorc(E_IOT); /* Give error so sizes >wordsize and not CODE don't get thru */ if (!((opctypemask = 1L << opctype) & (M_PLOAD | M_PCALL | M_PJUMP | M_PDESCRTBL)) && ((pso1->dsize > wordszdefault) && (pso1->dsize < CSFAR))) if (pso1->mode != 4) { errorc (E_IIS); /* No error if cst */ /* Don't allow CSFAR or CSNEAR if not CODE opcode */ pso1->dsize = wordszdefault; } if (!(opctypemask & (M_PRELJMP | M_PCALL | M_PJUMP))) if (pso1->dsize >= CSFAR) errorc (E_IIS); if (!(opctypemask & M_ESCAPE)) emitescape (a.dsc1, a.defseg); if (opctypemask & M_ERRIMMED) /* 1st operand not immediate */ errorimmed (a.dsc1); if (!(opctypemask & (M_PMOV | M_PSTACK))) /* Give error if segment reg used */ errorsegreg (a.dsc1); if (opctypemask & (M_PRETURN | M_PINT | M_PESC | M_PENTER)) forceimmed (a.dsc1); if ((xoptoargs[opctype] == TWO) || ((opctype == PSTR) && ((opcbase == O_MOVS) || (opcbase == O_CMPS) || (opcbase == O_INS) || (opcbase == O_OUTS)))) { /* Two args or 2 arg string oper */ if (NEXTC () != ',') error (E_EXP,"comma"); leaflag = (opcbase == O_LEA)? TRUE: FALSE; a.defseg = segdefault (SECONDDS); a.dsc2 = expreval (&a.defseg); if (noexp) errorc(E_MDZ); if ((pso2 = &(a.dsc2->dsckind.opnd)) && pso2->dtype & M_STRUCTEMPLATE) errorc(E_IOT); /* IF LEA(215), then never segment prefix */ if ((opcbase != O_LEA) && (opctype != PSTR)) emitescape (a.dsc2, a.defseg); if (opctypemask & (M_PLOAD | M_PXCHG | M_PESC | M_PSTR | M_PBOUND | M_PARSL | M_PARPL)) errorimmed (a.dsc2); if (opctype != PMOV) /* Give error if SEGREG and not a MOV opcode */ errorsegreg (a.dsc2); if (!(opctypemask & (M_PLOAD | M_PBOUND)) && (pso2->dsize > 2 && #ifdef V386 ( !(cputype & P386) || pso2->dsize != 4) && #endif pso2->dsize < CSFAR)) /* Give error so sizes > 2 and not CODE don't * get thru */ if (pso2->mode != 4) errorc (E_IIS); if (pso2->dsize >= CSFAR && !leaflag) /* Don't allow CSFAR or CSNEAR if not code opcode. But allow LEA since it is untyped anyway. */ errorc (E_IIS); } } #ifdef V386 /* for most instructions, the 386 0x66 prefix is appropriate. * for some classes, we either never allow it, or do some * special handling specific to the instruction. */ if (cputype & P386) { switch(opctype) { default: emit67(pso1, pso2); emit66(pso1, pso2); break; case PMOV: case PMOVX: case PLOAD: case PSHIFT: case PSTACK: case PSTR: case PARPL: case PDTTRSW: case PDESCRTBL: emit67(pso1, pso2); break; case PCALL: case PJUMP: case PRELJMP: case PENTER: case PNOARGS: case PESC: case PRETURN: case PINT: case PINOUT: case PARITH: break; } } #endif switch (opctype) { case PNOARGS: pnoargs (); break; case PJUMP: case PRELJMP: preljmp (&a); break; case PSHIFT: pshift (&a); break; case PSTACK: pstack (&a); break; case PARITH: parith (&a); break; case PBOUND: pbound (&a); break; case PENTER: penter (&a); break; case PCLTS: pclts (); break; case PDESCRTBL: pdescrtbl (&a); break; case PDTTRSW: pdttrsw (&a); break; case PVER: pver (&a); break; case PARSL: parsl (&a); break; case PARPL: parpl (&a); break; case PRETURN: preturn (&a); break; case PINCDEC: pincdec (&a); break; case PINT: pint (&a); break; case PINOUT: pinout (&a); break; case PLOAD: pload (&a); break; case PCALL: emitcall (232, 154, 16, 24, &a); break; case PMOV: pmov (&a); break; case PGENARG: pgenarg (&a); break; case PXCHG: pxchg (&a); break; case PESC: pesc (&a); break; case PREPEAT: prepeat (&a); break; case PSTR: pstr (&a); break; case PXLAT: pxlat (&a); break; #ifdef V386 case PMOVX: pmovx (&a); break; case PSETCC: psetcc (&a); break; case PBIT: pbit (&a); break; case PBITSCAN: pbitscan (&a); break; #endif } if (a.dsc1) dfree ((char *)a.dsc1 ); if (a.dsc2) dfree ((char *)a.dsc2 ); if (pcsegment){ pcsegment->symu.segmnt.hascode = 1; } } /*** pnoargs - no arguments * * pnoargs (); * * Entry * Exit * Returns * Calls */ #ifdef V386 UCHAR stackOps[] = {O_PUSHA, O_PUSHAD, O_POPA, O_POPAD, O_PUSHF, O_PUSHFD, O_POPF, O_POPFD, O_IRET, O_IRETD, NULL }; #endif VOID PASCAL CODESIZE pnoargs () { /* some no argument instructions have an implied arg which determines * whether to do the 386 66 prefix. that this is the case is encoded * in the modrm in the op code table. -Hans */ #ifdef V386 if (modrm != 0 && modrm <= 4 && modrm != wordsize){ emitsize(0x66); if (strchr(stackOps, (UCHAR) opcbase)) errorc (E_ONW); } #endif emitopcode (opcbase); if (opcbase == O_AAM || opcbase == O_AAD) /* emit modrm byte for AAD/AAM* */ emitopcode (modrm); } /*** preljmp - Relative jump -128..+127 * * preljmp (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE preljmp ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register SHORT cPadNop; SHORT rangeisshort; #ifdef V386 SHORT maybelong; #else #define maybelong 0 #endif pso1 = &(p->dsc1->dsckind.opnd); #ifdef V386 maybelong = (cputype & P386) && !nolong(pso1) && pso1->dsize != CSFAR; #endif rangeisshort = shortrange(p); cPadNop = 0; if (opcbase == O_JMP) { if (pso1->dtype & M_SHRT || rangeisshort && pso1->dflag != XTERNAL) { opcbase += 2; if (rangeisshort == 2 && !(pso1->dtype & M_SHRT)){ cPadNop = wordsize; errorc(E_JSH); if (M_PTRSIZE & pso1->dtype && pso1->dsize == CSFAR) cPadNop += 2; } } else{ /* Is normal jump */ emitcall (opcbase, 234, 32, 40, p); return; } } if (!(M_CODE & pso1->dtype)) errorc (E_ASC); /* an extrn may have no segment with it but still be near */ if (pso1->dsegment != pcsegment && !(maybelong && !pso1->dsegment)) errorc (E_NIP); if (pso1->dtype & (M_HIGH | M_LOW)) errorc (E_IOT); if (M_SHRT & pso1->dtype) { if (pass2 && !rangeisshort) errorc (E_JOR); } else if (!rangeisshort && !maybelong) error (E_JOR, (char *)NULL); /* common pass1 error */ #ifdef V386 if (maybelong && !(M_SHRT & pso1->dtype) && (!rangeisshort || pso1->dflag == XTERNAL)) { /* 386 long conditional branches */ emitopcode(0x0f); emitopcode((UCHAR)(0x80 | (opcbase&0xf))); pso1->dtype |= M_SHRT; emitrest(p->dsc1); return; } #endif emitopcode (opcbase); if (pso1->dflag == XTERNAL) { /* EXTERNAL jump */ pso1->dsize = 1; pso1->fixtype = FLOW; /* SHORT to EXTERNAL */ pso1->dtype |= M_SHRT; /* One byte result */ emitOP (pso1); } else emitopcode ((UCHAR)pso1->doffset); while (--cPadNop > 0) emitnop(); } #ifdef V386 /* most 386 conditional jumps can take a long or short form. these can * only take a short form */ static SHORT CODESIZE nolong( register struct psop *pso1 ){ switch(opcbase) { case O_JCXZ: case O_LOOP: case O_LOOPZ: case O_LOOPNZ: #ifdef V386 pso1->dtype |= M_SHRT; pso1->dtype &= ~M_PTRSIZE; /* allow `loop word ptr label' for cx|ecx overide */ if (modrm && modrm != wordsize || pso1->sized && pso1->dsize != wordsize && (pso1->dsize == 4 || pso1->dsize == 2)){ pso1->dtype = (pso1->dtype & ~M_DATA) | M_CODE; emitsize(0x67); } #endif return(1); default: return(0); } } #endif /*** shortrange - check range of short jump * * flag = shortrange (p); * * Entry * Exit * Returns 1 for short jump, not shortened * 2 for forward label shortened * 0 for not short jmp * Calls */ SHORT PASCAL CODESIZE shortrange ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register OFFSET disp; pso1 = &(p->dsc1->dsckind.opnd); if (pso1->dtype & M_PTRSIZE #ifdef V386 && !((cputype & P386) && (pso1->dsize == CSNEAR)) #endif ) if (opcbase == O_JMP) { if (!isdirect(pso1)) return (0); } else errorc (E_IIS|E_WARN1); if (pso1->dflag == XTERNAL && pso1->dsize == CSNEAR) return (1); if (pso1->dsegment == pcsegment && M_CODE&pso1->dtype && pso1->dflag != UNDEFINED){ if (pso1->dflag == XTERNAL) return (1); if (pcoffset + 2 < pso1->doffset) { /* Forward */ disp = (pso1->doffset - pcoffset) - 2; CondJmpDist = disp - 127; /* Get displace, only jump shorten for explicid * forward jumps */ if (disp < 128) if (pso1->dflag == KNOWN || opcbase == O_JMP || !(cputype&P386) || (cputype&P386 && pso1->dtype & M_SHRT)){ pso1->doffset = disp; if (pso1->dflag == KNOWN) return(1); else return (2); } else errorc(E_JSH); } else { /* Backwards jump */ disp = (pcoffset + 2) - pso1->doffset; CondJmpDist = disp - 128; if (disp < 129) { pso1->doffset = 256 - disp; return (1); } } } return (FALSE); } /*** pshift - shift opcodes * * pshift (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pshift ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ DSCREC *op3; pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); if (impure) errorc (E_IMP); #ifdef V386 /* Shift/rotate opcodes */ if (pso1->dsize >= 2 && pso1->dsize != wordsize) emitsize(0x66); /* parse 3rd operand for SHLD and SHRD */ /* note that we wont have even gotten here if not 386 */ if (opcbase == O_SHRD || opcbase == O_SHLD) { if (pso1->dsize != pso2->dsize) errorc (E_OMM); pso2->dsegment = NULL; /* for checksize */ checksize (p); emitopcode(0x0f); checkwreg(pso2); if (NEXTC() == ',') { op3 = expreval (&nilseg); if (op3->dsckind.opnd.mode == 3 && op3->dsckind.opnd.rm == 1 && !op3->dsckind.opnd.w) emitopcode((UCHAR)(opcbase | 1)); else { forceimmed (op3); emitopcode(opcbase); } emitmodrm ((USHORT)pso1->mode, (USHORT)(pso2->rm & 7), pso1->rm); /* Emit any effective address */ emitrest (p->dsc1); /* and the immediate if appropriate */ if (op3->dsckind.opnd.mode == 4) emitrest (op3); } else error(E_EXP,"comma"); return; } #endif if (pso2->mode == 3 && pso2->rm == 1 && pso2->dsize == 1) /* Have CL now */ emitopcode ((UCHAR)(0xD2 + pso1->w)); /* * 1st byte * */ else { /* Shift count is 1 */ forceimmed (p->dsc2); if (pso2->doffset == 1) /* * 1st byte */ emitopcode ((UCHAR)(0xD0 + pso1->w)); else if (cputype == P86) errorc (E_IOT); else { if (pso2->doffset > 0xFF) errorc (E_VOR); emitopcode ((UCHAR)(0xC0 + pso1->w)); } } /* Must have size or error */ forcesize (p->dsc1); emitmodrm ((USHORT)pso1->mode, modrm, pso1->rm); /* Emit any effective address */ emitrest (p->dsc1); if ((cputype != P86) && (pso2->doffset != 1)) emitrest (p->dsc2); } #ifdef V386 /*** pmovx - 386 movzx, movsx operators * */ VOID CODESIZE pmovx( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); checkwreg(pso1); if (pso2->mode == 4) errorc(E_IOT); if (pso1->dsize != wordsize) emitsize(0x66); if (pso2->sized && pso2->dsize != 1 && (pso1->dsize>>1 != pso2->dsize)) errorc(E_IIS); emitopcode(0x0f); emitopcode((UCHAR)(opcbase|pso2->w)); emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); emitrest (p->dsc2); } /*** psetcc - 386 setle, seto, etc * */ VOID CODESIZE psetcc( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); if (pso1->dsize != 1) errorc(E_IIS); emitopcode(0x0f); emitopcode(modrm); emitmodrm ((USHORT)pso1->mode, 0, pso1->rm); emitrest (p->dsc1); } /*** pbit -- 386 bit test and set, complement or reset * */ VOID CODESIZE pbit( register struct parsrec *p ){ register struct psop *pso1; struct psop *pso2; pso1 = &(p->dsc1->dsckind.opnd); emitopcode(0x0f); if (pso1->mode == 4) errorc(E_NIM); pso2 = &(p->dsc2->dsckind.opnd); if (pso2->mode == 4) { emitopcode(0xBA); emitmodrm ((USHORT)pso1->mode, modrm, pso1->rm); emitrest (p->dsc1); emitrest (p->dsc2); forcesize (p->dsc1); byteimmcheck (pso2); } else if (pso2->mode == 3) { static UCHAR byte2[] = {0xA3, 0xAB, 0xB3, 0xBB}; emitopcode(byte2[modrm&3]); emitmodrm ((USHORT)pso1->mode, pso2->rm, pso1->rm); checkmatch (p->dsc2, p->dsc1); emitrest (p->dsc1); } else errorc(E_IOT); } /*** pbitscan -- 386 bit scan forward, reverse * */ VOID CODESIZE pbitscan( register struct parsrec *p ){ register struct psop *pso2; pso2 = &(p->dsc2->dsckind.opnd); checkwreg (&p->dsc1->dsckind.opnd); if (pso2->mode == 4) errorc (E_NIM); checkmatch (p->dsc1, p->dsc2); emitopcode(0x0f); emitopcode(modrm); emitmodrm ((USHORT)pso2->mode, p->dsc1->dsckind.opnd.rm, pso2->rm); emitrest (p->dsc2); } #endif /* V386 */ /*** parith - arithmetic operators * * parith (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE parith ( register struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ DSCREC *op1; pso1 = &(p->dsc1->dsckind.opnd); /* note that opcbase is the same for IMUL and IDIV--thus this was * trying to accept immediates. modrm has the right stuff, strangely */ if (opcbase == O_IMUL && (modrm == R_IMUL) && (PEEKC () == ',') && (cputype != P86)) { /* IMUL reg | ea,imm */ SKIPC (); if (pso1->dsize != 2 && pso1->dsize != 4) errorc (E_BRI); p->defseg = segdefault (SECONDDS); p->dsc2 = expreval (&p->defseg); pso2 = &(p->dsc2->dsckind.opnd); if (PEEKC () == ',') { SKIPC (); if (pso2->sized && ((pso2->dsize != 2 && pso2->dsize != 4) || pso2->dsize != pso1->dsize)) errorc (E_IIS); /* IMUL reg,ea,immed */ #ifdef V386 emit67 (pso1, pso2); emit66 (pso1, pso2); #endif op1 = p->dsc1; p->dsc1 = p->dsc2; pso1 = pso2; p->dsc2 = expreval (&nilseg); pso2 = &(p->dsc2->dsckind.opnd); forceimmed (p->dsc2); emitescape (p->dsc1, p->defseg); emitopcode ((UCHAR)(IMUL3 + 2 * pso2->s)); emitmodrm ((USHORT)pso1->mode, op1->dsckind.opnd.rm, pso1->rm); emitrest (p->dsc1); pso2->w = !pso2->s; /* shorten to byte if necessary */ if (!pso2->w) byteimmcheck(pso2); /* force size immediate size to match op 1 */ pso2->dsize = op1->dsckind.opnd.dsize; emitrest (p->dsc2); dfree ((char *)op1 ); } #ifdef V386 else if (pso2->mode != 4 && (cputype & P386)) { /* IMUL reg, reg/mem */ if (pso1->dsize != pso2->dsize && pso2->sized) errorc (E_OMM); emit67 (pso1, pso2); emit66 (pso1, pso2); emitescape (p->dsc2, p->defseg); emitopcode(0x0f); emitopcode(0xaf); emitmodrm(pso2->mode, pso1->rm, pso2->rm); emitrest(p->dsc2); } #endif /* V386 */ else { /* IMUL reg,immed */ #ifdef V386 /* recompute immediate size based op 1 size not word size */ if (!(pso2->dflag & (UNDEFINED|FORREF|XTERNAL)) && pso2->fixtype == FCONSTANT && pso2->doffset & 0x8000) if (pso1->dsize == 2) pso2->s = (USHORT)(((USHORT) pso2->doffset & ~0x7F ) == (USHORT)(~0x7F)); else pso2->s = (OFFSET)((pso2->doffset & ~0x7F ) == (OFFSET)(~0x7F)); emit67 (pso1, pso2); emit66 (pso1, pso2); #endif forceimmed (p->dsc2); checksize(p); emitopcode ((UCHAR)(IMUL3 + 2 * pso2->s)); emitmodrm ((USHORT)pso1->mode, pso1->rm, pso1->rm); pso2->w = !pso2->s; /* shorten to byte if necessary */ if (!pso2->w) byteimmcheck(pso2); pso2->dsize = pso1->dsize; emitrest (p->dsc2); } } else { #ifdef V386 emit67 (pso1, NULL); emit66 (pso1, NULL); #endif forcesize (p->dsc1); emitescape (p->dsc1, p->defseg); if ((opcbase == O_NEG || opcbase == O_NOT) && impure) errorc (E_IMP); emitopcode ((UCHAR)(ARITHBASE + pso1->w)); emitmodrm ((USHORT)pso1->mode, modrm, pso1->rm); emitrest (p->dsc1); } } /*** pbound - bounds operators * * pbound (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pbound ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); checkwreg(pso1); if (pso2->dsize != pso1->dsize*2) errorc (E_IIS); #ifdef V386_0 if (wordsize != pso1->dsize) emitsize(0x66); #endif emitopcode (opcbase); emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); emitrest (p->dsc2); } /*** penter - enter operators * * penter (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE penter ( register struct parsrec *p ){ emitopcode (opcbase); p->dsc1->dsckind.opnd.dsize = 2; emitOP (&p->dsc1->dsckind.opnd); p->dsc2->dsckind.opnd.dsize = 1; forceimmed (p->dsc2); emitOP (&p->dsc2->dsckind.opnd); } /*** pclts - operators * * pclts (); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pclts () { emitopcode (opcbase); emitopcode (modrm); } /*** pdescrtbl - table operators * * pdescrtbl (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pdescrtbl ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); if (pso1->dsize != 6) errorc (E_IIS); emitopcode (opcbase); emitopcode (1); emitmodrm ((USHORT)pso1->mode, modrm, pso1->rm); emitrest (p->dsc1); } /*** pdttrsw - operators * * pdttrsw (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pdttrsw ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); if (!pso1->w || (pso1->sized && pso1->dsize != 2)) errorc ((USHORT)(pso1->mode != 3? E_IIS: E_IIS & ~E_WARN1)); emitopcode (opcbase); if ((modrm == R_LMSW) || (modrm == R_SMSW)) emitopcode (1); else emitopcode (0); emitmodrm ((USHORT)pso1->mode, modrm, pso1->rm); emitrest (p->dsc1); } /*** pver - operators * * pver (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pver ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); if (!pso1->w || (pso1->sized && pso1->dsize != 2)) errorc ((UCHAR)(pso1->mode != 3? E_IIS: E_IIS & ~E_WARN1)); emitopcode (opcbase); emitopcode (0); emitmodrm ((USHORT)pso1->mode, modrm, pso1->rm); emitrest (p->dsc1); } /*** parsl - operators * * parsl (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE parsl ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); checkmatch (p->dsc1, p->dsc2); checkwreg(pso1); emitopcode (opcbase); emitopcode (modrm); emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); emitrest (p->dsc2); } /*** parpl - operators * * parpl (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE parpl ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); if (pso2->dsize != 2) errorc (E_IIS); checkmatch (p->dsc2, p->dsc1); emitopcode (opcbase); emitmodrm ((USHORT)pso1->mode, pso2->rm, pso1->rm); emitrest (p->dsc1); } /*** pstack - push|pos stack * * pstack (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pstack ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); #ifdef V386 if (!(pso1->fixtype == FBASESEG || pso1->fixtype == FGROUPSEG) && pso1->sized && (pso1->dsize|wordsize) == 6 && !(pso1->mode == 3 && pso1->dsegment->symu.regsym.regtype == SEGREG)) { emitsize(0x66); errorc (E_ONW); } #endif if (pso1->mode == 3) { /* Using register */ /* Forward is error */ errorforward (p->dsc1); switch (pso1->dsegment->symu.regsym.regtype) { case SEGREG: /* CS | DS | ES | SS | FS | GS */ rangecheck (&pso1->rm, (UCHAR)7); if (opcbase == O_POP && pso1->rm == CSSEG) errorc (E_CSI); #ifdef V386 if (pso1->rm >= FSSEG) { emitopcode(0x0f); emitopcode ((UCHAR)(((pso1->rm << 3)+ 0x80) + (opcbase == O_POP))); } else #endif emitopcode ((UCHAR)(((pso1->rm << 3)+ 6) + (opcbase == O_POP))); break; case WRDREG: case INDREG: #ifdef V386 case DWRDREG: #endif rangecheck (&pso1->rm, (UCHAR)7); emitopcode ((UCHAR)(opcbase + pso1->rm)); /* Reg form */ break; default: errorc(E_BRI); } } else if (pso1->mode == 4) { #ifdef V386 /* detect immediate too big */ if (wordsize == 2 && pso1->dsize != 4 && highWord(pso1->doffset)) if (highWord(pso1->doffset) != 0xFFFF || !pso1->s) errorc(E_VOR); #endif if (opcbase == O_POP || cputype == P86) errorimmed (p->dsc1); emitopcode ((UCHAR)(0x68 + 2 * pso1->s)); pso1->w = !pso1->s; /* shorten to byte if necessary */ if (!pso1->w) byteimmcheck(pso1); else if (!(M_PTRSIZE & pso1->dtype)) pso1->dsize = wordsize; /* force size to wordsize */ emitrest (p->dsc1); } else { if (pso1->sized && pso1->dsize && !(pso1->dsize == 2 || pso1->dsize == 4)) errorc(E_IIS); /* Have memory operand of some kind */ if (opcbase == O_POP && impure) errorc (E_IMP); emitopcode ((UCHAR)((opcbase == O_PUSH)? O_PUSHM: O_POPM)); emitmodrm ((USHORT)pso1->mode, (USHORT)((opcbase == O_PUSH)? 6: 0), pso1->rm); emitrest (p->dsc1); } } /*** buildFrame - builds stack frame * * preturn (p); * * Entry before first instruction is generated in proc */ VOID PASCAL CODESIZE buildFrame() { char szLocal[32]; char szT[48]; SHORT i; strcpy(save, lbuf); /* save line for later .. */ fSkipList++; fProcArgs = -fProcArgs; /* mark already processed */ if (fProcArgs < -ARGS_REG) { *radixconvert (cbProcLocals, szLocal) = NULL; if (cputype & P86) { doLine("push bp"); doLine("mov bp,sp"); if (fProcArgs == -ARGS_LOCALS) /* locals present */ doLine(strcat( strcpy(szT, "sub sp,"), szLocal)); } else doLine(strcat( strcat( strcpy(szT, "enter "), szLocal), ",0")); } for (i = 0; i <= iRegSave; i++){ /* push all the saved registers */ doLine( strcat( strcpy(lbuf, "push "), regSave[i]) ); } fSkipList--; lbufp = strcpy(lbuf, save); linebp = lbufp + strlen(lbufp); strcpy(linebuffer, save); parse(); } /*** preturn - various forms of return * * preturn (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE preturn ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ SHORT i; pso1 = &(p->dsc1->dsckind.opnd); /* Decide whether inter or intra segment */ if (!modrm){ /* determine distance, if not RETN or RETF */ if (fProcArgs) { /* tear down the stack frame */ strcpy(save, linebuffer); fSkipList++; for (i = iRegSave; i >= 0; i--){ /* pop all the saved registers */ doLine( strcat( strcpy(lbuf, "pop "), regSave[i]) ); } if (fProcArgs < -ARGS_REG) if (cputype & P86) { if (fProcArgs == -ARGS_LOCALS) /* locals present */ doLine("mov sp,bp"); doLine("pop bp"); } else doLine("leave"); if (!(pcproc->attr & M_CDECL)) pso1->doffset = cbProcParms; strcpy(linebuffer, save); listindex = 1; fSkipList = FALSE; } opcbase = O_RET; if (pcproc && pcproc->symtype == CSFAR) opcbase = O_RET + 8; } /* Optimize, if constant is 0 and not forward, use SHORT */ if (pso1->doffset == 0 && pso1->dflag != FORREF) emitopcode (opcbase); else { /* Gen 2 byte version */ emitopcode ((UCHAR)(opcbase - 1)); /* Pop form */ /* Force word--always 2 bytes, even on 386 */ pso1->dsize = 2; emitOP (pso1); /* Immediate word */ } } /*** pincdec - increment|decrement * * pincdec (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pincdec ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); /* INC | DEC */ if (!pso1->sized) errorc (E_OHS); if (pso1->mode == 3 && pso1->w) /* Is word reg */ emitopcode ((UCHAR)(opcbase + pso1->rm)); else { /* Use mod reg r/m form */ if (impure) errorc (E_IMP); emitopcode ((UCHAR)(0xFE + pso1->w)); emitmodrm ((USHORT)pso1->mode, (USHORT)(opcbase == O_DEC), pso1->rm); emitrest (p->dsc1); } } /*** pint - interrupt * * pint (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pint ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); /* INT */ valuecheck (&pso1->doffset, 255); if (pso1->doffset == 3 && pso1->dflag != FORREF) /* Use SHORT form */ emitopcode (opcbase); else { /* Use long form */ emitopcode ((UCHAR)(opcbase + 1)); emitopcode ((UCHAR)(pso1->doffset & 255)); } } /*** pinout - input|output * * pinout (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pinout ( struct parsrec *p ){ register DSCREC *pso1; register DSCREC *pso2; pso1 = p->dsc1; pso2 = p->dsc2; if (opcbase == O_OUT) { pso2 = pso1; pso1 = p->dsc2; } /* IN ax|al, DX|immed */ /* OUT DX|immed, ax|al, */ #ifdef V386 emit66(&pso1->dsckind.opnd, NULL); #endif forceaccum (pso1); /* Must be accum */ if (pso2->dsckind.opnd.mode == 3 && pso2->dsckind.opnd.rm == 2) { /* Have DX */ emitopcode ((UCHAR)(opcbase + pso1->dsckind.opnd.w + 8)); if (pso2->dsckind.opnd.dsize != 2) errorc(E_IRV); } else { /* Have port # */ forceimmed (pso2); /* Must be constant */ valuecheck (&pso2->dsckind.opnd.doffset, 255); emitopcode ((UCHAR)(opcbase + pso1->dsckind.opnd.w)); emitopcode ((UCHAR)(pso2->dsckind.opnd.doffset)); } } /*** pload - load * * pload (p); lea, les, les, etc * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pload ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); /* LDS | LEA | LES */ if (pso1->mode != 3) /* Must be reg */ errorc (E_MBR); else if (1 << pso1->dsegment->symu.regsym.regtype & (M_STKREG | M_SEGREG | M_BYTREG)) errorc (E_WRT); if (pso2->mode == 3) errorc (E_IUR); if (opcbase != O_LEA) { if (pso2->dsize && pso2->dsize != 4 && pso2->dsize != 6) errorc (E_IIS); /* complain about mismatching source and destination */ if (pso2->dsize && pso1->dsize && pso1->dsize + 2 != pso2->dsize) errorc (E_IIS); #ifdef V386 else if (pso2->dsize && pso2->dsize != wordsize+2) emitsize(0x66); else if (pso1->dsize && pso1->dsize != wordsize) emitsize(0x66); #endif } #ifdef V386 else if (pso1->dsize != wordsize) emitsize(0x66); switch (opcbase) { case O_LFS: case O_LGS: case O_LSS: emitopcode(0x0F); break; } #endif emitopcode (opcbase); emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); /* If FAR, make offset so only 2 bytes out */ if (pso2->fixtype == FPOINTER) pso2->fixtype = FOFFSET; emitrest (p->dsc2); } /*** pmov - move * * pmov (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pmov ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); /* If 1st arg is memory or undef, force 2nd to be * immed for pass 1 and set in pass 2 */ if ((pso1->mode < 3) && (pso2->mode != 3)) { /* mem,immed */ pso2->dtype |= M_EXPLOFFSET; /* Look like OFFSET val */ if (!pass2) /* Force immed on pass1 */ pso2->mode = 4; } /* See if this is immediate move */ if (pso2->mode == 4) { emit66 (pso1, pso2); /* MOV arg,immed */ if (pso1->mode == 3) { /* MOV reg,immed */ if (1 << pso1->dsegment->symu.regsym.regtype & (M_SEGREG | M_STKREG | M_CREG )) /* Wrong type of register */ errorc (E_NIM); emitopcode ((UCHAR)(176 + 8*pso1->w + pso1->rm)); /* Make sure agree */ checksize (p); emitrest (p->dsc2); /* Emit immed */ if (pso1->rm && pso2->dtype & M_FORTYPE && !pso2->dsegment && !(M_EXPLOFFSET & pso2->dtype)) /* Pass 1 assumed not immed */ emitnop(); } else {/* MOV mem,immed */ checksize (p); if (!(pso1->sized || pso2->sized)) { pso1->sized = pso2->sized = TRUE; pso1->w = pso2->w = TRUE; } /* Make sure agree */ if (impure) errorc (E_IMP); emitopcode ((UCHAR)(198 + pso1->w)); emitmodrm ((USHORT)pso1->mode, 0, pso1->rm); emitrest (p->dsc1); emitrest (p->dsc2); } if (!pso1->w) /* 1st operand is byte, 2nd is immed * Check below on dsc1 should only be done * on MOV since the PGENARG opcodes always shorten a known * byte const */ if ((pso1->dtype & (M_FORTYPE|M_PTRSIZE|M_EXPLOFFSET)) == M_FORTYPE || (pso2->dtype & (M_FORTYPE|M_PTRSIZE|M_EXPLOFFSET)) == M_FORTYPE) emitnop(); } /* See if either is segment register */ else if (pso1->mode == 3) { /* 1st arg is reg */ switch (pso1->dsegment->symu.regsym.regtype) { case SEGREG: /* MOV SEGREG,arg */ movesegreg (TRUE, p); break; #ifdef V386 case CREG: /* mov CREG,reg */ movecreg (TRUE, p); break; case DWRDREG: #endif case BYTREG: case WRDREG: /* MOV ac,addr? */ if ((pso1->rm == 0) && isdirect(pso2)) /* MOV ac,addr */ moveaccum (TRUE, p); else /* MOV reg,arg */ movereg (TRUE, p); break; case INDREG: /* MOV indreg,arg */ movereg (TRUE, p); break; default: errorc (E_WRT); break; } } else if (pso2->mode == 3) { /* 2nd arg is reg */ switch (pso2->dsegment->symu.regsym.regtype) { case SEGREG: /* MOV arg,SEGREG */ movesegreg (FALSE, p); break; #ifdef V386 case CREG: /* mov reg, CREG */ movecreg(FALSE, p); break; case DWRDREG: #endif case BYTREG: case WRDREG: /* MOV addr,ac? */ if ((pso2->rm == 0) && isdirect(pso1)) /* MOV addr,ac */ moveaccum (FALSE, p); else /* MOV arg,reg */ movereg (FALSE, p); break; case INDREG: /* MOV arg,indreg */ movereg (FALSE, p); break; default: errorc (E_WRT); break; } } else errorc (E_IOT); } /*** pgenarg * * pgenarg (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pgenarg ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ char fAccumMode = 0; pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); /* ADC | ADD | AND | CMP | OR | SBB SUB | XOR | TEST */ if (pso1->mode != 3 && pso2->mode != 3) { /* Force to mem,immed */ if (!pass2) /* Force immediate */ pso2->mode = 4; } /* Not AX,immed */ if (pso2->mode == 4) { #ifdef V386 /* recompute immediate size based op 1 size not word size */ if (!(pso2->dflag & (UNDEFINED|FORREF|XTERNAL)) && pso2->fixtype == FCONSTANT && pso2->doffset & 0x8000) if (pso1->dsize == 2) pso2->s = (USHORT)(((USHORT) pso2->doffset & ~0x7F ) == (USHORT)(~0x7F)); else pso2->s = (OFFSET)((pso2->doffset & ~0x7F ) == (OFFSET)(~0x7F)); #endif /* OP mem/reg,immed */ if (pso1->mode == 3 && pso1->rm == 0 #ifdef V386 && !(pso1->dsize == 4 && pso2->s && opcbase != O_TEST) /* chose size extended */ #endif /* general purpose over ac*/ ) { /* OP al|ax|eax,immed */ checksize (p); /* Make sure agree */ if (opcbase == O_TEST) /* * TEST is special * */ emitopcode ((UCHAR)(0xA8 + pso1->w)); else/* Other reg immed */ /* Is AX,immed */ emitopcode ((UCHAR)(opcbase + 4 + pso1->w)); fAccumMode = 1; } else {/* OP mem/reg, immed */ checksize (p); if (!(pso1->sized || pso2->sized)) { pso1->sized = pso2->sized = TRUE; pso1->w = pso2->w = TRUE; } /* Make sure agree */ if (opcbase == O_TEST) { /* TEST is special */ emitopcode ((UCHAR)(ARITHBASE + pso1->w)); emitmodrm ((USHORT)pso1->mode, 0, pso1->rm); } else { if (opcbase != O_CMP && impure) errorc (E_IMP); if (pso2->w) { /* Try to shorten word */ emitopcode ((UCHAR)(0x80 + (pso2->s <<1) +pso1->w)); pso2->w = !pso2->s; /* So only byte out */ if (!pso2->w){ fAccumMode = wordsize - 1; byteimmcheck(pso2); } } else { emitopcode (128); } emitmodrm ((USHORT)pso1->mode, (USHORT)(opcbase>>3), pso1->rm); } emitrest (p->dsc1); } if (pso2->w && !pso1->w) /* size mismatch */ errorc (E_VOR); emitrest (p->dsc2); /* Emit immed */ if (!pso1->w) if (((pso2->dtype & (M_FORTYPE|M_PTRSIZE|M_EXPLOFFSET)) == M_FORTYPE || opcbase == O_TEST && pso1->mode != 3) && ((pso1->dtype & (M_FORTYPE|M_PTRSIZE|M_EXPLOFFSET)) == M_FORTYPE || pso1->mode == 3)) emitnop(); if (fAccumMode && M_FORTYPE & pso2->dtype && !(M_EXPLOFFSET & pso2->dtype)) while (--fAccumMode >= 0) emitnop(); } else { /* Not immediate */ if (pso1->mode == 3) { /* OP reg,mem/reg */ checkmatch (p->dsc1, p->dsc2); if (opcbase == O_TEST) opcbase = O_TEST - 2; emitopcode ((UCHAR)(opcbase + 2 + pso1->w)); emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); emitrest (p->dsc2); } else if (pso2->mode != 3) errorc (E_IOT); else { /* Have OP mem,reg */ if (opcbase != O_CMP && opcbase != O_TEST && impure) errorc (E_IMP); checkmatch (p->dsc2, p->dsc1); emitopcode ((UCHAR)(opcbase + pso2->w)); emitmodrm ((USHORT)pso1->mode, pso2->rm, pso1->rm); emitrest (p->dsc1); } } } /*** pxchg - exchange register and register/memory * * pxchg (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pxchg ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ DSCREC *t; if (impure) errorc (E_IMP); pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); if (pso1->mode != 3) { if (pso2->mode != 3){ errorc (E_OCI); /* Illegal */ return; } t = p->dsc1; p->dsc1 = p->dsc2; p->dsc2 = t; pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); } /* First operand is register */ if (1 << pso1->dsegment->symu.regsym.regtype & (M_STKREG | M_SEGREG)) errorc (E_WRT); rangecheck (&pso1->rm, (UCHAR)7); if (pso1->dsize != pso2->dsize && pso2->sized) errorc (E_OMM); if (pso2->mode == 3) { /* XCHG reg, reg */ if (1 << pso2->dsegment->symu.regsym.regtype & (M_STKREG | M_SEGREG)) errorc (E_WRT); rangecheck (&pso2->rm, (UCHAR)7); /* Check for XCHG accum, reg */ if (pso1->rm == 0 && pso1->w) { emitopcode ((UCHAR)(144 + pso2->rm)); return; } else if (pso2->w && pso2->rm == 0) { emitopcode ((UCHAR)(144 + pso1->rm)); return; } } emitopcode ((UCHAR)(134 + pso1->w)); emitmodrm ((USHORT)pso2->mode, pso1->rm, pso2->rm); emitrest (p->dsc2); } /*** pesc - escape operators * * pesc (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pesc ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); /* ESC opcode,modrm */ valuecheck (&pso1->doffset, 63); emitopcode ((UCHAR)(216 + pso1->doffset / 8)); emitmodrm ((USHORT)pso2->mode, (USHORT)(pso1->doffset & 7), pso2->rm); emitrest (p->dsc2); } /*** prepeat - repeat operators * * prepeat (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE prepeat ( struct parsrec *p ){ /* REP | REPZ | REPE | REPNE | REPNZ */ emitopcode (opcbase); listbuffer[listindex-1] = '/'; listindex++; /* Flag is LOCK/REP */ getatom (); if (!opcodesearch ()) /* Must have another op */ errorc (E_OAP); else /* Prefix for string instr */ opcode (); p->dsc1 = NULL; p->dsc2 = NULL; } /*** pstr - string operators * * pstr (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pstr ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ register struct psop *pso2; /* parse stack operand structure */ /* SCAS | STOS | MOVS | LODS | CMPS */ if (!p->dsc2) p->dsc2 = p->dsc1; pso1 = &(p->dsc1->dsckind.opnd); pso2 = &(p->dsc2->dsckind.opnd); if (opcbase == O_OUTS) { if (pso1->mode != 3) errorc (E_MBR); else if (pso1->rm != 2) errorc (E_WRT); p->dsc1 = p->dsc2; pso1 = pso2; } if (opcbase == O_INS) { if (pso2->mode != 3) errorc (E_MBR); else if (pso2->rm != 2) errorc (E_WRT); p->dsc2 = p->dsc1; pso2 = pso1; } /* Had to wait til now, so OUTS, INS would be adjusted already */ emit66 (pso1, pso2); if ((pso1->mode > 2 && pso1->mode < 5) || (pso2->mode > 2 && pso2->mode < 5)) errorc (E_IOT); if (!(pso1->sized || pso2->sized)) /* Give error if don't have a size specified */ errorc (E_OHS); if (pso1->w != pso2->w) errorc (E_OMM); if (opcbase == O_MOVS || opcbase == O_LODS || opcbase == O_OUTS) { emitescape (p->dsc2, DSSEG); /* 2nd can be override */ if (p->dsc1 != p->dsc2) errorover (pso1->seg); } else { errorover (pso2->seg); /* No 2nd override */ if (p->dsc1 != p->dsc2) emitescape (p->dsc1, DSSEG); } emitopcode ((UCHAR)(opcbase + pso1->w)); if (p->dsc1 == p->dsc2) { p->dsc1 = NULL; } } /*** pxlat * * pxlat (p); * * Entry * Exit * Returns * Calls */ VOID PASCAL CODESIZE pxlat ( struct parsrec *p ){ register struct psop *pso1; /* parse stack operand structure */ pso1 = &(p->dsc1->dsckind.opnd); /* XLAT */ if (pso1->mode <= 2 || pso1->mode >= 5) /* Good mode */ if (pso1->w) /* Must be byte */ errorc (E_IIS); emitopcode (opcbase); } /* isdirect -- given a psop representing a modrm, is it mem-direct? */ USHORT CODESIZE isdirect( register struct psop *pso /* parse stack operand structure */ ){ return ((pso->mode == 0 && pso->rm == 6) || /* for 8086 */ (pso->mode == 5 && pso->rm == 5)); /* for 386 */ } #ifdef V386 /* emit66 -- if dsize == 2 && wordsize == 4, or vice versa, we generate * a 66 prefix to locally change the operand mode. */ VOID PASCAL CODESIZE emit66( register struct psop *pso1, /* parse stack operand structure */ register struct psop *pso2 /* parse stack operand structure */ ){ if (!pso1) return; if (!pso2) { if (pso1->sized && (pso1->dsize | wordsize) == 6) emitsize(0x66); } else { /* key off the first operand if size known AND second isn't a register */ if (pso1->sized && pso2->mode != 3 || /* bogusness--sized and dsize 0 means immed bigger than 127 */ (pso2->sized && (pso1->dsize == pso2->dsize || pso2->dsize == 0))) { if ((pso1->dsize | wordsize) == 6) emitsize(0x66); } else if (pso2->sized) { if ((pso2->dsize | wordsize) == 6) emitsize(0x66); } } /* otherwise we have inconsistent opcodes and we cant do a thing. so dont. bogus!!! */ } /* emit67-- checks for operand size not matching wordsize and emits the * appropriate override */ VOID PASCAL emit67( register struct psop *pso1, /* parse stack operand structure */ register struct psop *pso2 /* parse stack operand structure */ ){ if (!pso1) return; if ((1<mode > 4) { emitsize(0x67); return; } else if (wordsize > 2 && pso1->mode < 3) { emitsize(0x67); return; } } if (!pso2 || !(1<mode > 4) { emitsize(0x67); return; } else if (wordsize > 2 && pso2->mode < 3) { emitsize(0x67); return; } } #endif /* V386 */ /* check for word register, or if 386, dword register */ CODESIZE checkwreg( register struct psop *psop /* parse stack operand structure */ ){ if (psop->mode != 3) errorc (E_MBR); if (psop->dsize != 2 #ifdef V386 && (!(cputype&P386) || psop->dsize != 4) #endif ) errorc (E_BRI); }