windows-nt/Source/XPSP1/NT/sdktools/masm/asmopc.c
2020-09-26 16:20:57 +08:00

2832 lines
62 KiB
C

/* 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 <stdio.h>
#include <string.h>
#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)? -(long)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 <w> 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;
return(0);
}
/*** 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 = (unsigned char)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 = (unsigned char)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;
}
return (0);
}
/*** 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 = (USHORT)((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 = (unsigned char)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 = (char)((USHORT)(((USHORT) pso2->doffset & ~0x7F ) == (USHORT)(~0x7F)));
else
pso2->s = (char)((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 <EXPLOFFSET> 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 = (char)((USHORT)(((USHORT) pso2->doffset & ~0x7F ) == (USHORT)(~0x7F)));
else
pso2->s = (char)((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<<FIRSTDS) & xoptoseg[opctype]) {
if (wordsize < 4 && pso1->mode > 4) {
emitsize(0x67);
return;
} else if (wordsize > 2 && pso1->mode < 3) {
emitsize(0x67);
return;
}
}
if (!pso2 || !(1<<SECONDDS & xoptoseg[opctype]))
return;
if (wordsize < 4 && pso2->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);
return(0);
}