2833 lines
62 KiB
C
2833 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);
|
|
|
|
pso1 = &(a.dsc1->dsckind.opnd);
|
|
if (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);
|
|
|
|
pso2 = &(a.dsc2->dsckind.opnd);
|
|
|
|
if (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);
|
|
}
|