dcc/src/scanner.cpp
2012-02-22 20:56:27 +01:00

872 lines
37 KiB
C++

/*****************************************************************************
* dcc project scanner module
* Implements a simple state driven scanner to convert 8086 machine code into
* I-code
* (C) Cristina Cifuentes, Jeff Ledermann
****************************************************************************/
#include <cstring>
#include "dcc.h"
#include "scanner.h"
static void rm(Int i);
static void modrm(Int i);
static void segrm(Int i);
static void data1(Int i);
static void data2(Int i);
static void regop(Int i);
static void segop(Int i);
static void strop(Int i);
static void escop(Int i);
static void axImp(Int i);
static void alImp(Int i);
static void axSrcIm(Int i);
static void memImp(Int i);
static void memReg0(Int i);
static void memOnly(Int i);
static void dispM(Int i);
static void dispS(Int i);
static void dispN(Int i);
static void dispF(Int i);
static void prefix(Int i);
static void immed(Int i);
static void shift(Int i);
static void arith(Int i);
static void trans(Int i);
static void const1(Int i);
static void const3(Int i);
static void none1(Int i);
static void none2(Int i);
static void checkInt(Int i);
#define iZERO (llIcode)0 // For neatness
#define IC llIcode
static struct {
void (*state1)(Int);
void (*state2)(Int);
flags32 flg;
llIcode opcode;
byte df;
byte uf;
} stateTable[] = {
{ modrm, none2, B , iADD , Sf | Zf | Cf , 0 }, /* 00 */
{ modrm, none2, 0 , iADD , Sf | Zf | Cf , 0 }, /* 01 */
{ modrm, none2, TO_REG | B , iADD , Sf | Zf | Cf , 0 }, /* 02 */
{ modrm, none2, TO_REG , iADD , Sf | Zf | Cf , 0 }, /* 03 */
{ data1, axImp, B , iADD , Sf | Zf | Cf , 0 }, /* 04 */
{ data2, axImp, 0 , iADD , Sf | Zf | Cf , 0 }, /* 05 */
{ segop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 06 */
{ segop, none2, NO_SRC , iPOP , 0 , 0 }, /* 07 */
{ modrm, none2, B , iOR , Sf | Zf | Cf , 0 }, /* 08 */
{ modrm, none2, NSP , iOR , Sf | Zf | Cf , 0 }, /* 09 */
{ modrm, none2, TO_REG | B , iOR , Sf | Zf | Cf , 0 }, /* 0A */
{ modrm, none2, TO_REG | NSP , iOR , Sf | Zf | Cf , 0 }, /* 0B */
{ data1, axImp, B , iOR , Sf | Zf | Cf , 0 }, /* 0C */
{ data2, axImp, 0 , iOR , Sf | Zf | Cf , 0 }, /* 0D */
{ segop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 0E */
{ none1, none2, OP386 , iZERO , 0 , 0 }, /* 0F */
{ modrm, none2, B , iADC , Sf | Zf | Cf , Cf }, /* 10 */
{ modrm, none2, NSP , iADC , Sf | Zf | Cf , Cf }, /* 11 */
{ modrm, none2, TO_REG | B , iADC , Sf | Zf | Cf , Cf }, /* 12 */
{ modrm, none2, TO_REG | NSP , iADC , Sf | Zf | Cf , Cf }, /* 13 */
{ data1, axImp, B , iADC , Sf | Zf | Cf , Cf }, /* 14 */
{ data2, axImp, 0 , iADC , Sf | Zf | Cf , Cf }, /* 15 */
{ segop, none2, NOT_HLL | NO_SRC , iPUSH , 0 , 0 }, /* 16 */
{ segop, none2, NOT_HLL | NO_SRC , iPOP , 0 , 0 }, /* 17 */
{ modrm, none2, B , iSBB , Sf | Zf | Cf , Cf }, /* 18 */
{ modrm, none2, NSP , iSBB , Sf | Zf | Cf , Cf }, /* 19 */
{ modrm, none2, TO_REG | B , iSBB , Sf | Zf | Cf , Cf }, /* 1A */
{ modrm, none2, TO_REG | NSP , iSBB , Sf | Zf | Cf , Cf }, /* 1B */
{ data1, axImp, B , iSBB , Sf | Zf | Cf , Cf }, /* 1C */
{ data2, axImp, 0 , iSBB , Sf | Zf | Cf , Cf }, /* 1D */
{ segop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 1E */
{ segop, none2, NO_SRC , iPOP , 0 , 0 }, /* 1F */
{ modrm, none2, B , iAND , Sf | Zf | Cf , 0 }, /* 20 */
{ modrm, none2, NSP , iAND , Sf | Zf | Cf , 0 }, /* 21 */
{ modrm, none2, TO_REG | B , iAND , Sf | Zf | Cf , 0 }, /* 22 */
{ modrm, none2, TO_REG | NSP , iAND , Sf | Zf | Cf , 0 }, /* 23 */
{ data1, axImp, B , iAND , Sf | Zf | Cf , 0 }, /* 24 */
{ data2, axImp, 0 , iAND , Sf | Zf | Cf , 0 }, /* 25 */
{ prefix, none2, 0 , (IC)rES,0 , 0 }, /* 26 */
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAA , Sf | Zf | Cf , 0 }, /* 27 */
{ modrm, none2, B , iSUB , Sf | Zf | Cf , 0 }, /* 28 */
{ modrm, none2, 0 , iSUB , Sf | Zf | Cf , 0 }, /* 29 */
{ modrm, none2, TO_REG | B , iSUB , Sf | Zf | Cf , 0 }, /* 2A */
{ modrm, none2, TO_REG , iSUB , Sf | Zf | Cf , 0 }, /* 2B */
{ data1, axImp, B , iSUB , Sf | Zf | Cf , 0 }, /* 2C */
{ data2, axImp, 0 , iSUB , Sf | Zf | Cf , 0 }, /* 2D */
{ prefix, none2, 0 , (IC)rCS,0 , 0 }, /* 2E */
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAS , Sf | Zf | Cf , 0 }, /* 2F */
{ modrm, none2, B , iXOR , Sf | Zf | Cf , 0 }, /* 30 */
{ modrm, none2, NSP , iXOR , Sf | Zf | Cf , 0 }, /* 31 */
{ modrm, none2, TO_REG | B , iXOR , Sf | Zf | Cf , 0 }, /* 32 */
{ modrm, none2, TO_REG | NSP , iXOR , Sf | Zf | Cf , 0 }, /* 33 */
{ data1, axImp, B , iXOR , Sf | Zf | Cf , 0 }, /* 34 */
{ data2, axImp, 0 , iXOR , Sf | Zf | Cf , 0 }, /* 35 */
{ prefix, none2, 0 , (IC)rSS,0 , 0 }, /* 36 */
{ none1, axImp, NOT_HLL | NO_SRC , iAAA , Sf | Zf | Cf , 0 }, /* 37 */
{ modrm, none2, B , iCMP , Sf | Zf | Cf , 0 }, /* 38 */
{ modrm, none2, NSP , iCMP , Sf | Zf | Cf , 0 }, /* 39 */
{ modrm, none2, TO_REG | B , iCMP , Sf | Zf | Cf , 0 }, /* 3A */
{ modrm, none2, TO_REG | NSP , iCMP , Sf | Zf | Cf , 0 }, /* 3B */
{ data1, axImp, B , iCMP , Sf | Zf | Cf , 0 }, /* 3C */
{ data2, axImp, 0 , iCMP , Sf | Zf | Cf , 0 }, /* 3D */
{ prefix, none2, 0 , (IC)rDS,0 , 0 }, /* 3E */
{ none1, axImp, NOT_HLL | NO_SRC , iAAS , Sf | Zf | Cf , 0 }, /* 3F */
{ regop, none2, 0 , iINC , Sf | Zf, 0 }, /* 40 */
{ regop, none2, 0 , iINC , Sf | Zf, 0 }, /* 41 */
{ regop, none2, 0 , iINC , Sf | Zf, 0 }, /* 42 */
{ regop, none2, 0 , iINC , Sf | Zf, 0 }, /* 43 */
{ regop, none2, NOT_HLL , iINC , Sf | Zf, 0 }, /* 44 */
{ regop, none2, 0 , iINC , Sf | Zf, 0 }, /* 45 */
{ regop, none2, 0 , iINC , Sf | Zf, 0 }, /* 46 */
{ regop, none2, 0 , iINC , Sf | Zf, 0 }, /* 47 */
{ regop, none2, 0 , iDEC , Sf | Zf, 0 }, /* 48 */
{ regop, none2, 0 , iDEC , Sf | Zf, 0 }, /* 49 */
{ regop, none2, 0 , iDEC , Sf | Zf, 0 }, /* 4A */
{ regop, none2, 0 , iDEC , Sf | Zf, 0 }, /* 4B */
{ regop, none2, NOT_HLL , iDEC , Sf | Zf, 0 }, /* 4C */
{ regop, none2, 0 , iDEC , Sf | Zf, 0 }, /* 4D */
{ regop, none2, 0 , iDEC , Sf | Zf, 0 }, /* 4E */
{ regop, none2, 0 , iDEC , Sf | Zf, 0 }, /* 4F */
{ regop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 50 */
{ regop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 51 */
{ regop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 52 */
{ regop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 53 */
{ regop, none2, NOT_HLL | NO_SRC , iPUSH , 0 , 0 }, /* 54 */
{ regop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 55 */
{ regop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 56 */
{ regop, none2, NO_SRC , iPUSH , 0 , 0 }, /* 57 */
{ regop, none2, NO_SRC , iPOP , 0 , 0 }, /* 58 */
{ regop, none2, NO_SRC , iPOP , 0 , 0 }, /* 59 */
{ regop, none2, NO_SRC , iPOP , 0 , 0 }, /* 5A */
{ regop, none2, NO_SRC , iPOP , 0 , 0 }, /* 5B */
{ regop, none2, NOT_HLL | NO_SRC , iPOP , 0 , 0 }, /* 5C */
{ regop, none2, NO_SRC , iPOP , 0 , 0 }, /* 5D */
{ regop, none2, NO_SRC , iPOP , 0 , 0 }, /* 5E */
{ regop, none2, NO_SRC , iPOP , 0 , 0 }, /* 5F */
{ none1, none2, NOT_HLL | NO_OPS , iPUSHA, 0 , 0 }, /* 60 */
{ none1, none2, NOT_HLL | NO_OPS , iPOPA , 0 , 0 }, /* 61 */
{ memOnly, modrm, TO_REG | NSP , iBOUND, 0 , 0 }, /* 62 */
{ none1, none2, OP386 , iZERO , 0 , 0 }, /* 63 */
{ none1, none2, OP386 , iZERO , 0 , 0 }, /* 64 */
{ none1, none2, OP386 , iZERO , 0 , 0 }, /* 65 */
{ none1, none2, OP386 , iZERO , 0 , 0 }, /* 66 */
{ none1, none2, OP386 , iZERO , 0 , 0 }, /* 67 */
{ data2, none2, NO_SRC , iPUSH , 0 , 0 }, /* 68 */
{ modrm, data2, TO_REG | NSP , iIMUL , Sf | Zf | Cf, 0 }, /* 69 */
{ data1, none2, S_EXT | NO_SRC , iPUSH , 0 , 0 }, /* 6A */
{ modrm, data1, TO_REG | NSP | S_EXT , iIMUL , Sf | Zf | Cf, 0 }, /* 6B */
{ strop, memImp, NOT_HLL | B|IM_OPS , iINS , 0 , Df }, /* 6C */
{ strop, memImp, NOT_HLL | IM_OPS , iINS , 0 , Df }, /* 6D */
{ strop, memImp, NOT_HLL | B|IM_OPS , iOUTS , 0 , Df }, /* 6E */
{ strop, memImp, NOT_HLL | IM_OPS , iOUTS , 0 , Df }, /* 6F */
{ dispS, none2, NOT_HLL , iJO , 0 , 0 }, /* 70 */
{ dispS, none2, NOT_HLL , iJNO , 0 , 0 }, /* 71 */
{ dispS, none2, 0 , iJB , 0 , Cf }, /* 72 */
{ dispS, none2, 0 , iJAE , 0 , Cf }, /* 73 */
{ dispS, none2, 0 , iJE , 0 , Zf }, /* 74 */
{ dispS, none2, 0 , iJNE , 0 , Zf }, /* 75 */
{ dispS, none2, 0 , iJBE , 0 , Zf | Cf }, /* 76 */
{ dispS, none2, 0 , iJA , 0 , Zf | Cf }, /* 77 */
{ dispS, none2, 0 , iJS , 0 , Sf }, /* 78 */
{ dispS, none2, 0 , iJNS , 0 , Sf }, /* 79 */
{ dispS, none2, NOT_HLL , iJP , 0 , 0 }, /* 7A */
{ dispS, none2, NOT_HLL , iJNP , 0 , 0 }, /* 7B */
{ dispS, none2, 0 , iJL , 0 , Sf }, /* 7C */
{ dispS, none2, 0 , iJGE , 0 , Sf }, /* 7D */
{ dispS, none2, 0 , iJLE , 0 , Sf | Zf }, /* 7E */
{ dispS, none2, 0 , iJG , 0 , Sf | Zf }, /* 7F */
{ immed, data1, B , iZERO , 0 , 0 }, /* 80 */
{ immed, data2, NSP , iZERO , 0 , 0 }, /* 81 */
{ immed, data1, B , iZERO , 0 , 0 }, /* 82 */ /* ?? */
{ immed, data1, NSP | S_EXT , iZERO , 0 , 0 }, /* 83 */
{ modrm, none2, TO_REG | B , iTEST , Sf | Zf | Cf, 0 }, /* 84 */
{ modrm, none2, TO_REG | NSP , iTEST , Sf | Zf | Cf, 0 }, /* 85 */
{ modrm, none2, TO_REG | B , iXCHG , 0 , 0 }, /* 86 */
{ modrm, none2, TO_REG | NSP , iXCHG , 0 , 0 }, /* 87 */
{ modrm, none2, B , iMOV , 0 , 0 }, /* 88 */
{ modrm, none2, 0 , iMOV , 0 , 0 }, /* 89 */
{ modrm, none2, TO_REG | B , iMOV , 0 , 0 }, /* 8A */
{ modrm, none2, TO_REG , iMOV , 0 , 0 }, /* 8B */
{ segrm, none2, NSP , iMOV , 0 , 0 }, /* 8C */
{ memOnly, modrm, TO_REG | NSP , iLEA , 0 , 0 }, /* 8D */
{ segrm, none2, TO_REG | NSP , iMOV , 0 , 0 }, /* 8E */
{ memReg0, none2, NO_SRC , iPOP , 0 , 0 }, /* 8F */
{ none1, none2, NO_OPS , iNOP , 0 , 0 }, /* 90 */
{ regop, axImp, 0 , iXCHG , 0 , 0 }, /* 91 */
{ regop, axImp, 0 , iXCHG , 0 , 0 }, /* 92 */
{ regop, axImp, 0 , iXCHG , 0 , 0 }, /* 93 */
{ regop, axImp, NOT_HLL , iXCHG , 0 , 0 }, /* 94 */
{ regop, axImp, 0 , iXCHG , 0 , 0 }, /* 95 */
{ regop, axImp, 0 , iXCHG , 0 , 0 }, /* 96 */
{ regop, axImp, 0 , iXCHG , 0 , 0 }, /* 97 */
{ alImp, axImp, SRC_B | S_EXT , iSIGNEX,0 , 0 }, /* 98 */
{axSrcIm, axImp, IM_DST | S_EXT , iSIGNEX,0 , 0 }, /* 99 */
{ dispF, none2, 0 , iCALLF ,0 , 0 }, /* 9A */
{ none1, none2, FLOAT_OP| NO_OPS , iWAIT , 0 , 0 }, /* 9B */
{ none1, none2, NOT_HLL | NO_OPS , iPUSHF, 0 , 0 }, /* 9C */
{ none1, none2, NOT_HLL | NO_OPS , iPOPF , Sf | Zf | Cf | Df,}, /* 9D */
{ none1, none2, NOT_HLL | NO_OPS , iSAHF , Sf | Zf | Cf, 0 }, /* 9E */
{ none1, none2, NOT_HLL | NO_OPS , iLAHF , 0 , Sf | Zf | Cf }, /* 9F */
{ dispM, axImp, B , iMOV , 0 , 0 }, /* A0 */
{ dispM, axImp, 0 , iMOV , 0 , 0 }, /* A1 */
{ dispM, axImp, TO_REG | B , iMOV , 0 , 0 }, /* A2 */
{ dispM, axImp, TO_REG , iMOV , 0 , 0 }, /* A3 */
{ strop, memImp, B | IM_OPS , iMOVS , 0 , Df }, /* A4 */
{ strop, memImp, IM_OPS , iMOVS , 0 , Df }, /* A5 */
{ strop, memImp, B | IM_OPS , iCMPS , Sf | Zf | Cf, Df }, /* A6 */
{ strop, memImp, IM_OPS , iCMPS , Sf | Zf | Cf, Df }, /* A7 */
{ data1, axImp, B , iTEST , Sf | Zf | Cf, 0 }, /* A8 */
{ data2, axImp, 0 , iTEST , Sf | Zf | Cf, 0 }, /* A9 */
{ strop, memImp, B | IM_OPS , iSTOS , 0 , Df }, /* AA */
{ strop, memImp, IM_OPS , iSTOS , 0 , Df }, /* AB */
{ strop, memImp, B | IM_OPS , iLODS , 0 , Df }, /* AC */
{ strop, memImp, IM_OPS , iLODS , 0 , Df }, /* AD */
{ strop, memImp, B | IM_OPS , iSCAS , Sf | Zf | Cf, Df }, /* AE */
{ strop, memImp, IM_OPS , iSCAS , Sf | Zf | Cf, Df }, /* AF */
{ regop, data1, B , iMOV , 0 , 0 }, /* B0 */
{ regop, data1, B , iMOV , 0 , 0 }, /* B1 */
{ regop, data1, B , iMOV , 0 , 0 }, /* B2 */
{ regop, data1, B , iMOV , 0 , 0 }, /* B3 */
{ regop, data1, B , iMOV , 0 , 0 }, /* B4 */
{ regop, data1, B , iMOV , 0 , 0 }, /* B5 */
{ regop, data1, B , iMOV , 0 , 0 }, /* B6 */
{ regop, data1, B , iMOV , 0 , 0 }, /* B7 */
{ regop, data2, 0 , iMOV , 0 , 0 }, /* B8 */
{ regop, data2, 0 , iMOV , 0 , 0 }, /* B9 */
{ regop, data2, 0 , iMOV , 0 , 0 }, /* BA */
{ regop, data2, 0 , iMOV , 0 , 0 }, /* BB */
{ regop, data2, NOT_HLL , iMOV , 0 , 0 }, /* BC */
{ regop, data2, 0 , iMOV , 0 , 0 }, /* BD */
{ regop, data2, 0 , iMOV , 0 , 0 }, /* BE */
{ regop, data2, 0 , iMOV , 0 , 0 }, /* BF */
{ shift, data1, B , iZERO , 0 , 0 }, /* C0 */
{ shift, data1, NSP | SRC_B , iZERO , 0 , 0 }, /* C1 */
{ data2, none2, 0 , iRET , 0 , 0 }, /* C2 */
{ none1, none2, NO_OPS , iRET , 0 , 0 }, /* C3 */
{ memOnly, modrm, TO_REG | NSP , iLES , 0 , 0 }, /* C4 */
{ memOnly, modrm, TO_REG | NSP , iLDS , 0 , 0 }, /* C5 */
{ memReg0, data1, B , iMOV , 0 , 0 }, /* C6 */
{ memReg0, data2, 0 , iMOV , 0 , 0 }, /* C7 */
{ data2, data1, 0 , iENTER, 0 , 0 }, /* C8 */
{ none1, none2, NO_OPS , iLEAVE, 0 , 0 }, /* C9 */
{ data2, none2, 0 , iRETF , 0 , 0 }, /* CA */
{ none1, none2, NO_OPS , iRETF , 0 , 0 }, /* CB */
{ const3, none2, NOT_HLL , iINT , 0 , 0 }, /* CC */
{ data1,checkInt, NOT_HLL , iINT , 0 , 0 }, /* CD */
{ none1, none2, NOT_HLL | NO_OPS , iINTO , 0 , 0 }, /* CE */
{ none1, none2, NOT_HLL | NO_OPS , iIRET , 0 , 0 }, /* Cf */
{ shift, const1, B , iZERO , 0 , 0 }, /* D0 */
{ shift, const1, SRC_B , iZERO , 0 , 0 }, /* D1 */
{ shift, none1, B , iZERO , 0 , 0 }, /* D2 */
{ shift, none1, SRC_B , iZERO , 0 , 0 }, /* D3 */
{ data1, axImp, NOT_HLL , iAAM , Sf | Zf | Cf, 0 }, /* D4 */
{ data1, axImp, NOT_HLL , iAAD , Sf | Zf | Cf, 0 }, /* D5 */
{ none1, none2, 0 , iZERO , 0 , 0 }, /* D6 */
{ memImp, axImp, NOT_HLL | B| IM_OPS, iXLAT , 0 , 0 }, /* D7 */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* D8 */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* D9 */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* DA */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* DB */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* DC */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* DD */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* DE */
{ escop, none2, FLOAT_OP , iESC , 0 , 0 }, /* Df */
{ dispS, none2, 0 , iLOOPNE,0 , Zf }, /* E0 */
{ dispS, none2, 0 , iLOOPE, 0 , Zf }, /* E1 */
{ dispS, none2, 0 , iLOOP , 0 , 0 }, /* E2 */
{ dispS, none2, 0 , iJCXZ , 0 , 0 }, /* E3 */
{ data1, axImp, NOT_HLL | B|NO_SRC , iIN , 0 , 0 }, /* E4 */
{ data1, axImp, NOT_HLL | NO_SRC , iIN , 0 , 0 }, /* E5 */
{ data1, axImp, NOT_HLL | B|NO_SRC , iOUT , 0 , 0 }, /* E6 */
{ data1, axImp, NOT_HLL | NO_SRC , iOUT , 0 , 0 }, /* E7 */
{ dispN, none2, 0 , iCALL , 0 , 0 }, /* E8 */
{ dispN, none2, 0 , iJMP , 0 , 0 }, /* E9 */
{ dispF, none2, 0 , iJMPF , 0 , 0 }, /* EA */
{ dispS, none2, 0 , iJMP , 0 , 0 }, /* EB */
{ none1, axImp, NOT_HLL | B|NO_SRC , iIN , 0 , 0 }, /* EC */
{ none1, axImp, NOT_HLL | NO_SRC , iIN , 0 , 0 }, /* ED */
{ none1, axImp, NOT_HLL | B|NO_SRC , iOUT , 0 , 0 }, /* EE */
{ none1, axImp, NOT_HLL | NO_SRC , iOUT , 0 , 0 }, /* EF */
{ none1, none2, NOT_HLL | NO_OPS , iLOCK , 0 , 0 }, /* F0 */
{ none1, none2, 0 , iZERO , 0 , 0 }, /* F1 */
{ prefix, none2, 0 , iREPNE, 0 , 0 }, /* F2 */
{ prefix, none2, 0 , iREPE , 0 , 0 }, /* F3 */
{ none1, none2, NOT_HLL | NO_OPS , iHLT , 0 , 0 }, /* F4 */
{ none1, none2, NO_OPS , iCMC , Cf, Cf }, /* F5 */
{ arith, none1, B , iZERO , 0 , 0 }, /* F6 */
{ arith, none1, NSP , iZERO , 0 , 0 }, /* F7 */
{ none1, none2, NO_OPS , iCLC , Cf, 0 }, /* F8 */
{ none1, none2, NO_OPS , iSTC , Cf, 0 }, /* F9 */
{ none1, none2, NOT_HLL | NO_OPS , iCLI , 0 , 0 }, /* FA */
{ none1, none2, NOT_HLL | NO_OPS , iSTI , 0 , 0 }, /* FB */
{ none1, none2, NO_OPS , iCLD , Df, 0 }, /* FC */
{ none1, none2, NO_OPS , iSTD , Df, 0 }, /* FD */
{ trans, none1, B , iZERO , 0 , 0 }, /* FE */
{ trans, none1, NSP , iZERO , 0 , 0 } /* FF */
} ;
static word SegPrefix, RepPrefix;
static byte *pInst; /* Ptr. to current byte of instruction */
static ICODE * pIcode; /* Ptr to Icode record filled in by scan() */
/*****************************************************************************
Scans one machine instruction at offset ip in prog.Image and returns error.
At the same time, fill in low-level icode details for the scanned inst.
****************************************************************************/
eErrorId scan(dword ip, ICODE *p)
{
Int op;
memset(p, 0, sizeof(ICODE));
p->type = LOW_LEVEL;
p->ic.ll.label = ip; /* ip is absolute offset into image*/
if (ip >= (dword)prog.cbImage)
{
return (IP_OUT_OF_RANGE);
}
SegPrefix = RepPrefix = 0;
pInst = prog.Image + ip;
pIcode = p;
do
{
op = *pInst++; /* First state - trivial */
p->ic.ll.opcode = stateTable[op].opcode; /* Convert to Icode.opcode */
p->ic.ll.flg = stateTable[op].flg & ICODEMASK;
p->ic.ll.flagDU.d = stateTable[op].df;
p->ic.ll.flagDU.u = stateTable[op].uf;
(*stateTable[op].state1)(op); /* Second state */
(*stateTable[op].state2)(op); /* Third state */
} while (stateTable[op].state1 == prefix); /* Loop if prefix */
if (p->ic.ll.opcode)
{
/* Save bytes of image used */
p->ic.ll.numBytes = (byte)((pInst - prog.Image) - ip);
return ((SegPrefix)? FUNNY_SEGOVR: /* Seg. Override invalid */
(RepPrefix ? FUNNY_REP: NO_ERR));/* REP prefix invalid */
}
/* Else opcode error */
return ((stateTable[op].flg & OP386)? INVALID_386OP: INVALID_OPCODE);
}
/***************************************************************************
relocItem - returns TRUE if word pointed at is in relocation table
**************************************************************************/
static boolT relocItem(byte *p)
{
Int i;
dword off = p - prog.Image;
for (i = 0; i < prog.cReloc; i++)
if (prog.relocTable[i] == off)
return TRUE;
return FALSE;
}
/***************************************************************************
getWord - returns next word from image
**************************************************************************/
static word getWord(void)
{
word w = LH(pInst);
pInst += 2;
return w;
}
/****************************************************************************
signex - returns byte sign extended to Int
***************************************************************************/
static Int signex(byte b)
{
long s = b;
return ((b & 0x80)? (Int)(0xFFFFFF00 | s): (Int)s);
}
/****************************************************************************
* setAddress - Updates the source or destination field for the current
* icode, based on fdst and the TO_REG flag.
* Note: fdst == TRUE is for the r/m part of the field (dest, unless TO_REG)
* fdst == FALSE is for reg part of the field
***************************************************************************/
static void setAddress(Int i, boolT fdst, word seg, int16 reg, word off)
{
ICODEMEM *pm;
/* If not to register (i.e. to r/m), and talking about r/m,
then this is dest */
pm = (!(stateTable[i].flg & TO_REG) == fdst) ?
&pIcode->ic.ll.dst : &pIcode->ic.ll.src;
/* Set segment. A later procedure (lookupAddr in proclist.c) will
* provide the value of this segment in the field segValue. */
if (seg) /* segment override */
{
pm->seg = pm->segOver = (byte)seg;
}
else
{ /* no override, check indexed register */
if ((reg >= INDEXBASE) && (reg == INDEXBASE + 2 ||
reg == INDEXBASE + 3 || reg == INDEXBASE + 6))
{
pm->seg = rSS; /* indexed on bp */
}
else
{
pm->seg = rDS; /* any other indexed reg */
}
}
pm->regi = (byte)reg;
pm->off = (int16)off;
if (reg && reg < INDEXBASE && (stateTable[i].flg & B))
{
pm->regi += rAL - rAX;
}
if (seg) /* So we can catch invalid use of segment overrides */
{
SegPrefix = 0;
}
}
/****************************************************************************
rm - Decodes r/m part of modrm byte for dst (unless TO_REG) part of icode
***************************************************************************/
static void rm(Int i)
{
byte mod = *pInst >> 6;
byte rm = *pInst++ & 7;
switch (mod) {
case 0: /* No disp unless rm == 6 */
if (rm == 6) {
setAddress(i, TRUE, SegPrefix, 0, getWord());
pIcode->ic.ll.flg |= WORD_OFF;
}
else setAddress(i, TRUE, SegPrefix, rm + INDEXBASE, 0);
break;
case 1: /* 1 byte disp */
setAddress(i, TRUE, SegPrefix, rm+INDEXBASE, (word)signex(*pInst++));
break;
case 2: /* 2 byte disp */
setAddress(i, TRUE, SegPrefix, rm + INDEXBASE, getWord());
pIcode->ic.ll.flg |= WORD_OFF;
break;
case 3: /* reg */
setAddress(i, TRUE, 0, rm + rAX, 0);
break;
}
if ((stateTable[i].flg & NSP) && (pIcode->ic.ll.src.regi==rSP ||
pIcode->ic.ll.dst.regi==rSP))
pIcode->ic.ll.flg |= NOT_HLL;
}
/****************************************************************************
modrm - Sets up src and dst from modrm byte
***************************************************************************/
static void modrm(Int i)
{
setAddress(i, FALSE, 0, REG(*pInst) + rAX, 0);
rm(i);
}
/****************************************************************************
segrm - seg encoded as reg of modrm
****************************************************************************/
static void segrm(Int i)
{
Int reg = REG(*pInst) + rES;
if (reg > rDS || (reg == rCS && (stateTable[i].flg & TO_REG)))
pIcode->ic.ll.opcode = (llIcode)0;
else {
setAddress(i, FALSE, 0, (int16)reg, 0);
rm(i);
}
}
/****************************************************************************
regop - src/dst reg encoded as low 3 bits of opcode
***************************************************************************/
static void regop(Int i)
{
setAddress(i, FALSE, 0, ((int16)i & 7) + rAX, 0);
pIcode->ic.ll.dst.regi = pIcode->ic.ll.src.regi;
}
/*****************************************************************************
segop - seg encoded in middle of opcode
*****************************************************************************/
static void segop(Int i)
{
setAddress(i, TRUE, 0, (((int16)i & 0x18) >> 3) + rES, 0);
}
/****************************************************************************
axImp - Plugs an implied AX dst
***************************************************************************/
static void axImp(Int i)
{
setAddress(i, TRUE, 0, rAX, 0);
}
/* Implied AX source */
static void axSrcIm (Int )
{
pIcode->ic.ll.src.regi = rAX;
}
/* Implied AL source */
static void alImp (Int )
{
pIcode->ic.ll.src.regi = rAL;
}
/*****************************************************************************
memImp - Plugs implied src memory operand with any segment override
****************************************************************************/
static void memImp(Int i)
{
setAddress(i, FALSE, SegPrefix, 0, 0);
}
/****************************************************************************
memOnly - Instruction is not valid if modrm refers to register (i.e. mod == 3)
***************************************************************************/
static void memOnly(Int )
{
if ((*pInst & 0xC0) == 0xC0)
pIcode->ic.ll.opcode = (llIcode)0;
}
/****************************************************************************
memReg0 - modrm for 'memOnly' and Reg field must also be 0
****************************************************************************/
static void memReg0(Int i)
{
if (REG(*pInst) || (*pInst & 0xC0) == 0xC0)
pIcode->ic.ll.opcode = (llIcode)0;
else
rm(i);
}
/***************************************************************************
immed - Sets up dst and opcode from modrm byte
**************************************************************************/
static void immed(Int i)
{
static llIcode immedTable[8] = {iADD, iOR, iADC, iSBB, iAND, iSUB, iXOR, iCMP};
static byte uf[8] = { 0, 0, Cf, Cf, 0, 0, 0, 0 };
pIcode->ic.ll.opcode = immedTable[REG(*pInst)];
pIcode->ic.ll.flagDU.u = uf[REG(*pInst)];
pIcode->ic.ll.flagDU.d = (Sf | Zf | Cf);
rm(i);
if (pIcode->ic.ll.opcode == iADD || pIcode->ic.ll.opcode == iSUB)
pIcode->ic.ll.flg &= ~NOT_HLL; /* Allow ADD/SUB SP, immed */
}
/****************************************************************************
shift - Sets up dst and opcode from modrm byte
***************************************************************************/
static void shift(Int i)
{
static llIcode shiftTable[8] =
{
(llIcode)iROL, (llIcode)iROR, (llIcode)iRCL, (llIcode)iRCR,
(llIcode)iSHL, (llIcode)iSHR, (llIcode)0, (llIcode)iSAR};
static byte uf[8] = {0, 0, Cf, Cf, 0, 0, 0, 0 };
static byte df[8] = {Cf, Cf, Cf, Cf, Sf | Zf | Cf,
Sf | Zf | Cf, 0, Sf | Zf | Cf};
pIcode->ic.ll.opcode = shiftTable[REG(*pInst)];
pIcode->ic.ll.flagDU.u = uf[REG(*pInst)];
pIcode->ic.ll.flagDU.d = df[REG(*pInst)];
rm(i);
pIcode->ic.ll.src.regi = rCL;
}
/****************************************************************************
trans - Sets up dst and opcode from modrm byte
***************************************************************************/
static void trans(Int i)
{
static llIcode transTable[8] =
{
(llIcode)iINC, (llIcode)iDEC, (llIcode)iCALL, (llIcode)iCALLF,
(llIcode)iJMP, (llIcode)iJMPF,(llIcode)iPUSH, (llIcode)0
};
static byte df[8] = {Sf | Zf, Sf | Zf, 0, 0, 0, 0, 0, 0};
if ((byte)REG(*pInst) < 2 || !(stateTable[i].flg & B)) { /* INC & DEC */
pIcode->ic.ll.opcode = transTable[REG(*pInst)]; /* valid on bytes */
pIcode->ic.ll.flagDU.d = df[REG(*pInst)];
rm(i);
memcpy(&pIcode->ic.ll.src, &pIcode->ic.ll.dst, sizeof(ICODEMEM));
if (pIcode->ic.ll.opcode == iJMP || pIcode->ic.ll.opcode == iCALL || pIcode->ic.ll.opcode == iCALLF)
pIcode->ic.ll.flg |= NO_OPS;
else if (pIcode->ic.ll.opcode == iINC || pIcode->ic.ll.opcode == iPUSH || pIcode->ic.ll.opcode == iDEC)
pIcode->ic.ll.flg |= NO_SRC;
}
}
/****************************************************************************
arith - Sets up dst and opcode from modrm byte
****************************************************************************/
static void arith(Int i)
{ byte opcode;
static llIcode arithTable[8] =
{
(llIcode)iTEST, (llIcode)0, (llIcode)iNOT, (llIcode)iNEG,
(llIcode)iMUL, (llIcode)iIMUL, (llIcode)iDIV, (llIcode)iIDIV
};
static byte df[8] = {Sf | Zf | Cf, 0, 0, Sf | Zf | Cf,
Sf | Zf | Cf, Sf | Zf | Cf, Sf | Zf | Cf,
Sf | Zf | Cf};
opcode = pIcode->ic.ll.opcode = arithTable[REG(*pInst)];
pIcode->ic.ll.flagDU.d = df[REG(*pInst)];
rm(i);
if (opcode == iTEST)
{
if (stateTable[i].flg & B)
data1(i);
else
data2(i);
}
else if (!(opcode == iNOT || opcode == iNEG))
{
memcpy(&pIcode->ic.ll.src, &pIcode->ic.ll.dst, sizeof(ICODEMEM));
setAddress(i, TRUE, 0, rAX, 0); /* dst = AX */
}
else if (opcode == iNEG || opcode == iNOT)
pIcode->ic.ll.flg |= NO_SRC;
if ((opcode == iDIV) || (opcode == iIDIV))
{
if ((pIcode->ic.ll.flg & B) != B)
pIcode->ic.ll.flg |= IM_TMP_DST;
}
}
/*****************************************************************************
data1 - Sets up immed from 1 byte data
*****************************************************************************/
static void data1(Int i)
{
pIcode->ic.ll.immed.op = (stateTable[i].flg & S_EXT)? signex(*pInst++):
*pInst++;
pIcode->ic.ll.flg |= I;
}
/*****************************************************************************
data2 - Sets up immed from 2 byte data
****************************************************************************/
static void data2(Int )
{
if (relocItem(pInst))
pIcode->ic.ll.flg |= SEG_IMMED;
/* ENTER is a special case, it does not take a destination operand,
* but this field is being used as the number of bytes to allocate
* on the stack. The procedure level is stored in the immediate
* field. There is no source operand; therefore, the flag flg is
* set to NO_OPS. */
if (pIcode->ic.ll.opcode == iENTER)
{
pIcode->ic.ll.dst.off = getWord();
pIcode->ic.ll.flg |= NO_OPS;
}
else
pIcode->ic.ll.immed.op = getWord();
pIcode->ic.ll.flg |= I;
}
/****************************************************************************
dispM - 2 byte offset without modrm (== mod 0, rm 6) (Note:TO_REG bits are
reversed)
****************************************************************************/
static void dispM(Int i)
{
setAddress(i, FALSE, SegPrefix, 0, getWord());
}
/****************************************************************************
dispN - 2 byte disp as immed relative to ip
****************************************************************************/
static void dispN(Int )
{
long off = (short)getWord(); /* Signed displacement */
/* Note: the result of the subtraction could be between 32k and 64k, and
still be positive; it is an offset from prog.Image. So this must be
treated as unsigned */
pIcode->ic.ll.immed.op = (dword)(off + (unsigned)(pInst - prog.Image));
pIcode->ic.ll.flg |= I;
}
/***************************************************************************
dispS - 1 byte disp as immed relative to ip
***************************************************************************/
static void dispS(Int )
{
long off = signex(*pInst++); /* Signed displacement */
pIcode->ic.ll.immed.op = (dword)(off + (unsigned)(pInst - prog.Image));
pIcode->ic.ll.flg |= I;
}
/****************************************************************************
dispF - 4 byte disp as immed 20-bit target address
***************************************************************************/
static void dispF(Int )
{
dword off = (unsigned)getWord();
dword seg = (unsigned)getWord();
pIcode->ic.ll.immed.op = off + ((dword)(unsigned)seg << 4);
pIcode->ic.ll.flg |= I;
}
/****************************************************************************
prefix - picks up prefix byte for following instruction (LOCK is ignored
on purpose)
****************************************************************************/
static void prefix(Int )
{
if (pIcode->ic.ll.opcode == iREPE || pIcode->ic.ll.opcode == iREPNE)
RepPrefix = pIcode->ic.ll.opcode;
else
SegPrefix = pIcode->ic.ll.opcode;
}
inline void BumpOpcode(llIcode& ic)
{
ic = (llIcode)(((int)ic)+1); // Bump this icode via the int type
}
/*****************************************************************************
strop - checks RepPrefix and converts string instructions accordingly
*****************************************************************************/
static void strop(Int )
{
if (RepPrefix)
{
// pIcode->ic.ll.opcode += ((pIcode->ic.ll.opcode == iCMPS ||
// pIcode->ic.ll.opcode == iSCAS)
// && RepPrefix == iREPE)? 2: 1;
if ((pIcode->ic.ll.opcode == iCMPS || pIcode->ic.ll.opcode == iSCAS)
&& RepPrefix == iREPE)
BumpOpcode(pIcode->ic.ll.opcode); // += 2
BumpOpcode(pIcode->ic.ll.opcode); // else += 1
if (pIcode->ic.ll.opcode == iREP_LODS)
pIcode->ic.ll.flg |= NOT_HLL;
RepPrefix = 0;
}
}
/***************************************************************************
escop - esc operands
***************************************************************************/
static void escop(Int i)
{
pIcode->ic.ll.immed.op = REG(*pInst) + (dword)((i & 7) << 3);
pIcode->ic.ll.flg |= I;
rm(i);
}
/****************************************************************************
const1
****************************************************************************/
static void const1(Int )
{
pIcode->ic.ll.immed.op = 1;
pIcode->ic.ll.flg |= I;
}
/*****************************************************************************
const3
****************************************************************************/
static void const3(Int )
{
pIcode->ic.ll.immed.op = 3;
pIcode->ic.ll.flg |= I;
}
/****************************************************************************
none1
****************************************************************************/
static void none1(Int )
{
}
/****************************************************************************
none2 - Sets the NO_OPS flag if the operand is immediate
****************************************************************************/
static void none2(Int )
{
if (pIcode->ic.ll.flg & I)
pIcode->ic.ll.flg |= NO_OPS;
}
/****************************************************************************
Checks for int 34 to int 3B - if so, converts to ESC nn instruction
****************************************************************************/
static void checkInt(Int )
{
word wOp = (word) pIcode->ic.ll.immed.op;
if ((wOp >= 0x34) && (wOp <= 0x3B))
{
/* This is a Borland/Microsoft floating point emulation instruction.
Treat as if it is an ESC opcode */
pIcode->ic.ll.immed.op = wOp - 0x34;
pIcode->ic.ll.opcode = iESC;
pIcode->ic.ll.flg |= FLOAT_OP;
escop(wOp - 0x34 + 0xD8);
}
}