Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1116 lines
33 KiB

#include "precomp.h"
#pragma hdrstop
#include "asm.h"
#ifdef HOSTDOS
extern int _far _cdecl toupper( int );
extern int _far _cdecl tolower( int );
#else // HOSTDOS
#endif // HOSTDOS
XOSD asm386 ( LPADDR, LSZ, LPBYTE, LPDWORD );
int CheckData(void);
LPBYTE ProcessOpcode ( LPXOSD );
LPBYTE GetTemplate(LPBYTE);
BYTE MatchTemplate ( LPDWORD );
XOSD CheckTemplate(void);
BYTE CheckPrefix(LPBYTE);
XOSD AssembleInstr(void);
BYTE MatchOperand(PASM_VALUE, BYTE);
void OutputInstr(void);
void OutputValue(BYTE size, LPBYTE pchValue);
extern void error(ULONG);
extern BYTE PeekAsmChar(void);
extern ULONG PeekAsmToken(LPDWORD);
extern void AcceptAsmToken(void);
extern XOSD GetAsmExpr(PASM_VALUE, BYTE);
extern XOSD GetAsmOperand(PASM_VALUE);
extern LPBYTE SearchOpcode(LPBYTE);
extern ULONG savedAsmClass;
extern OPNDTYPE mapOpndType[];
// flags and values to build the assembled instruction
static BYTE fWaitPrfx; // if set, use WAIT prefix for float instr
static BYTE fOpndOvrd; // if set, use operand override prefix
static BYTE fAddrOvrd; // if set, use address override prefix
static BYTE segOvrd; // if nonzero, use segment override prefix
static BYTE preOpcode; // if nonzero, use byte before opcode
static BYTE inOpcode; // opcode of instruction
static BYTE postOpcode; // if nonzero, use byte after opcode
static BYTE fModrm; // if set, modrm byte is defined
static BYTE modModrm; // if fModrm, mod component of modrm
static BYTE regModrm; // if fModrm, reg component of modrm
static BYTE rmModrm; // if fModrm, rm component of modrm
static BYTE fSib; // if set, sib byte is defined
static BYTE scaleSib; // if fSib, scale component of sib
static BYTE indexSib; // if fSib, index component of sib
static BYTE baseSib; // if fSib, base component of sib
static BYTE fSegPtr; // if set, segment for far call defined
static USHORT segPtr; // if fSegPtr, value of far call segment
static BYTE addrSize; // size of address: 0, 1, 2, 4
static LONG addrValue; // value of address, if used
static BYTE immedSize; // size of immediate: 0, 1, 2, 4
static LONG immedValue; // value of immediate, if used
static BYTE immedSize2; // size of second immediate, if used
static LONG immedValue2; // value of second immediate, if used
ADDR addrAssem; // assembly address (formal)
static LPBYTE lpbBin; // pointer to binary result string
// flags and values of the current instruction template being used
static BYTE cntTmplOpnd; // count of operands in template
static BYTE tmplType[3]; // operand types for current template
static BYTE tmplSize[3]; // operand sizes for current template
static BYTE fForceSize; // set if operand size must be specified
static BYTE fAddToOp; // set if addition to opcode
static BYTE fNextOpnd; // set if character exists for next operand
static BYTE fSegOnly; // set if only segment is used for operand
static BYTE fMpNext; // set on 'Mv' tmpl if next tmpl is 'Mp'
static BYTE segIndex; // index of segment for PUSH/POP
// values describing the operands processed from the command line
static BYTE cntInstOpnd; // count of operands read from input line
static BYTE sizeOpnd; // size of operand for template with size v
static ASM_VALUE avInstOpnd[3]; // asm values from input line
ULONG baseDefault = 16;
LSZ lszAsmLine = (LSZ)0L; // pointer to input line (formal)
BYTE fDBit = TRUE; // set for 32-bit addr/operand mode
HPID hpidAsm = 0;
HTID htidAsm = 0;
BYTE segToOvrdByte[] = {
0x00, // segX
0x26, // segES
0x2e, // segCS
0x36, // segSS
0x3e, // segDS
0x64, // segFS
0x65 // segGS
};
XOSD
Assemble (
HPID hpid,
HTID htid,
LPADDR lpaddr,
LSZ lszInput
)
{
XOSD xosd = xosdNone;
int cbLength;
BYTE rgb [ 60 ];
hpidAsm = hpid;
htidAsm = htid;
fDBit = ADDR_IS_FLAT(*lpaddr);
xosd = asm386 ( lpaddr, lszInput, rgb, &cbLength );
if ( xosd == xosdNone ) {
#ifdef OSDEBUG4
DWORD cbw;
xosd = WriteBufferCache(hpid, htid, lpaddr, cbLength, rgb, &cbw);
#else
(void) EMFunc ( emfSetAddr, hpid, htid, adrCurrent, (LONG) lpaddr );
xosd = EMFunc ( emfWriteBuf, hpid, htid, cbLength, (LONG) rgb );
#endif
if ( xosd == xosdNone ) {
lpaddr->addr.off += cbLength;
}
}
return xosd;
}
XOSD
asm386 (
LPADDR lpaddr,
LSZ lszAssemble,
LPBYTE lpb,
LPDWORD lpcb
)
{
LPBYTE lpbTemplate;
BYTE index; // loop index and temp
ULONG temp; // general temporary value
BYTE errIndex; // error index of all templates
int errType; // error type of all templates
// initialize flags and state variables
addrAssem = *lpaddr; // make assembly address global
lszAsmLine = lszAssemble; // make input string pointer global
lpbBin = lpb; // make binary string pointer global
savedAsmClass = (ULONG)-1; // no peeked token
segOvrd = 0; // no segment override
cntInstOpnd = 0; // no input operands read yet
fModrm = fSib = fSegPtr = FALSE; // no modrm, sib, or far seg
addrSize = immedSize = immedSize2 = 0; // no addr or immed
// from the string in lszAsmLine, parse and lookup the opcode
// to return a pointer to its template. check and process
// any prefixes, reading the next opcode for each prefix
do {
XOSD xosd = xosdNone;
lpbTemplate = ProcessOpcode ( &xosd );
if ( xosd != xosdNone ) {
return xosd;
}
} while ( CheckPrefix ( lpbTemplate ) );
// if a pending opcode to process, lpbTemplate is not NULL
if ( lpbTemplate ) {
// fNextOpnd is initially set on the condition of characters
// being available for the first operand on the input line
fNextOpnd = (BYTE)(PeekAsmToken(&temp) != ASM_EOL_CLASS);
// continue until match occurs or last template read
errIndex = 0; // start with no error
do {
// get infomation on next template - return pointer to
// next template or NULL if last in list
lpbTemplate = GetTemplate(lpbTemplate);
// match the loaded template against the operands input
// if mismatch, index has the operand index + 1 of
// the error while temp has the error type.
index = MatchTemplate(&temp);
if ( temp == (ULONG) xosdAsmExtraChars ) {
errType = (int) temp;
lpbTemplate = NULL;
}
// determine the error to report as templates are matched
// update errIndex to index if later operand
// if same operand index, prioritize to give best error:
// high: SIZE, BADRANGE, OVERFLOW
// medium: OPERAND
// low: TOOFEW, TOOMANY
if ( index > errIndex ||
( index == errIndex &&
( errType == xosdAsmTooFew ||
errType == xosdAsmTooMany ||
temp == (ULONG) xosdAsmSize ||
temp == (ULONG) xosdAsmBadRange ||
temp == (ULONG) xosdAsmOverFlow
)
)
) {
errIndex = index;
errType = (int) temp;
}
} while ( index && lpbTemplate );
// if error occured on template match, process it
if ( index ) {
return errType;
}
// preliminary type and size matching has been
// successful on the current template.
// perform further checks for size ambiguity.
// at this point, the assembly is committed to the current
// template. either an error or a successful assembly
// follows.
if ( ( errType = CheckTemplate ( ) ) != xosdNone ) {
return errType;
}
// from the template and operand information, set the field
// information of the assembled instruction
if ( ( errType = AssembleInstr ( ) ) != xosdNone ) {
return errType;
}
// from the assembled instruction information, create the
// corresponding binary information
OutputInstr ( );
}
// return the size of the binary string output (can be zero)
*lpcb = (lpbBin - lpb); // length of binary string
return xosdNone;
}
LPBYTE ProcessOpcode ( LPXOSD lpxosd ) {
BYTE ch;
BYTE cbOpcode = 0;
LPBYTE lpbTemplate;
BYTE szOpcode[10];
// skip over any leading white space
do {
ch = *lszAsmLine++;
} while (ch == ' ' || ch == '\t');
// return NULL if end of line
if ( ch == '\0' ) {
return NULL;
}
// parse out opcode - first string [a-z] [0-9] (case insensitive)
ch = (BYTE) tolower ( ch );
while (
( ( ch >= 'a' && ch <= 'z' ) || ( ch >= '0' && ch <= '9' ) ) &&
cbOpcode < 9
) {
szOpcode [ cbOpcode++ ] = ch;
ch = (BYTE)tolower ( *lszAsmLine );
lszAsmLine += 1;
}
// if empty or too long, then error
if ( cbOpcode == 0 || cbOpcode == 9 ) {
*lpxosd = xosdAsmBadOpcode;
return NULL;
}
// allow opcode to have trailing colon and terminate
if (ch == ':') {
szOpcode[cbOpcode++] = ch;
ch = (BYTE)tolower(*lszAsmLine++);
}
szOpcode[cbOpcode] = '\0';
lszAsmLine--;
// get pointer to template series for opcode found
lpbTemplate = SearchOpcode(szOpcode);
if ( lpbTemplate == NULL ) {
*lpxosd = xosdAsmBadOpcode;
}
return lpbTemplate;
}
LPBYTE GetTemplate (LPBYTE lpbTemplate)
{
BYTE ch;
BYTE ftEnd; // set if tEnd for last template in list
BYTE feEnd; // set if eEnd for last token in template
// initialize template variables and flags
cntTmplOpnd = segIndex = 0;
tmplType[0] = tmplType[1] = tmplType[2] = typNULL;
tmplSize[0] = tmplSize[1] = tmplSize[2] = sizeX;
fForceSize = fAddToOp = fSegOnly = fMpNext = FALSE;
fWaitPrfx = FALSE; // no WAIT prefix
fOpndOvrd = fAddrOvrd = FALSE; // no operand or addr overrides
preOpcode = postOpcode = 0; // no pre- or post-opcode
regModrm = 0; // this is part of some opcodes
ch = *lpbTemplate++;
// set pre-opcode for two-byte opcodes (0x0f??) and advance
// template if needed
if (ch == 0x0f) {
preOpcode = ch;
ch = *lpbTemplate++;
}
inOpcode = ch; // set opcode
// set post-opcode and advance template for floating-point
// instructions (0xd8 - 0xdf) using a second byte in
// the range 0xc0 - 0xff that is read from the template
if ((ch & ~0x7) == 0xd8) {
ch = *lpbTemplate;
if (ch >= 0xc0) {
postOpcode = ch;
lpbTemplate++;
}
}
// loop for each flag and/or operand token in template
// the last token in the list has the eEnd bit set.
do {
// read the next template token
ch = *lpbTemplate++;
// extract the tEnd and eEnd bits from the token
ftEnd = (BYTE)(ch & tEnd);
feEnd = (BYTE)(ch & eEnd);
ch &= ~(tEnd | eEnd);
// if extracted token is a flag, do the appropriate action
if (ch < asRegBase)
switch (ch) {
case as0x0a:
// the postOpcode is set for some decimal instructions
postOpcode = 0x0a;
break;
case asOpRg:
// fAddToOp is set if the register index is added
// directly to the base opcode value
fAddToOp = TRUE;
break;
case asSiz0:
// fOpndOvrd is set or cleared to force a 16-bit operand
fOpndOvrd = fDBit;
break;
case asSiz1:
// fOpndOvrd is set or cleared to force a 32-bit operand
fOpndOvrd = (BYTE)!fDBit;
break;
case asWait:
// the flag fWaitPrfx is set to emit WAIT before the
// instruction
fWaitPrfx = TRUE;
break;
case asSeg:
// in XLAT, the optional memory operand is used to
// just specify a segment override prefix
fSegOnly = TRUE;
break;
case asFSiz:
// fForceSize is set when a specific size of a memory
// operand must be given for some floating instrs
fForceSize = TRUE;
break;
case asMpNx:
// fMpNext is set when the next template operand is
// 'Mp' and is used to determine how to match
// 'Md' since it matches both 'Mp' and 'Mv'
fMpNext = TRUE;
break;
}
// if token is REG value bit, set the variable regModrm to
// set the opcode-dependent reg value in the modrm byte
else if (ch < opnBase)
regModrm = (BYTE)(ch - asRegBase);
// otherwise, token is operand descriptor.
// if segment operand, get segment number from template
// normalize and map to get operand type and size.
else {
if (ch == opnSeg)
segIndex = *lpbTemplate++;
ch -= opnBase;
tmplType[cntTmplOpnd] = mapOpndType[ch].type;
tmplSize[cntTmplOpnd++] = mapOpndType[ch].size;
}
}
while (!ftEnd);
// return either the pointer to the next template or NULL if
// the last template for the opcode has been processed
return (feEnd ? NULL : lpbTemplate);
}
BYTE MatchTemplate ( LPDWORD lpulErr ) {
BYTE fMatch = TRUE;
BYTE index;
ULONG temp;
PASM_VALUE pavInstOpnd; // pointer to current operand from input
// process matching for each operand in the specified template
// stop at last operand or when mismatch occurs
for (index = 0; index < cntTmplOpnd && fMatch; index++) {
// set pointer to current instruction operand
pavInstOpnd = &avInstOpnd[index];
// if input operand has not yet been read, check flag
// for existence and process it.
if (index == cntInstOpnd) {
fMatch = fNextOpnd;
*((XOSD*)lpulErr) = xosdAsmTooFew;
if ( fMatch ) {
cntInstOpnd++;
*lpulErr = (ULONG) GetAsmOperand(pavInstOpnd);
if ( *lpulErr != (ULONG) xosdNone ) {
return (BYTE) (index + 1);
}
// recompute existence of next possible operand
// comma implies TRUE, EOL implies FALSE, else error
temp = PeekAsmToken(&temp);
if (temp == ASM_COMMA_CLASS) {
AcceptAsmToken();
fNextOpnd = TRUE;
}
else if (temp == ASM_EOL_CLASS) {
fNextOpnd = FALSE;
}
else {
*lpulErr = (ULONG) xosdAsmExtraChars; // bad parse - immediate error
return cntTmplOpnd;
}
}
}
if (fMatch) {
fMatch = MatchOperand(pavInstOpnd, tmplType[index]);
*lpulErr = (ULONG) xosdAsmOperand;
}
// if the template and operand type match, do preliminary
// check on size based solely on template size specified
if (fMatch) {
if (tmplType[index] == typJmp) {
// for relative jumps, test if byte offset is
// sufficient by computing offset which is
// the target offset less the offset of the
// next instruction. (assume Jb instructions
// are two bytes in length.
temp = pavInstOpnd->value - ( offAddr ( addrAssem ) + 2);
fMatch = (BYTE)(tmplSize[index] == sizeV
|| ((LONG)temp >= -0x80 && (LONG)temp <= 0x7f));
*lpulErr = (ULONG) xosdAsmBadRange;
}
else if (tmplType[index] == typImm) {
// for immediate operand,
// template sizeV matches sizeB, sizeW, sizeV (all)
// template sizeW matches sizeB, sizeW
// template sizeB matches sizeB
fMatch = (BYTE)(tmplSize[index] == sizeV
|| pavInstOpnd->size == tmplSize[index]
|| pavInstOpnd->size == sizeB);
*lpulErr = (ULONG) xosdAsmOverFlow;
}
else {
// for nonimmediate operand,
// template sizeX (unspecified) matches all
// operand sizeX (unspecified) matches all
// same template and operand size matches
// template sizeV matches operand sizeW and sizeD
// (EXCEPT for sizeD when fMpNext and fDBit set)
// template sizeP matches operand sizeD and sizeF
// template sizeA matches operand sizeD and sizeQ
fMatch = (BYTE)(tmplSize[index] == sizeX
|| pavInstOpnd->size == sizeX
|| tmplSize[index] == pavInstOpnd->size
|| (tmplSize[index] == sizeV
&& (pavInstOpnd->size == sizeW
|| (pavInstOpnd->size == sizeD
&& (!fMpNext || fDBit))))
|| (tmplSize[index] == sizeP
&& (pavInstOpnd->size == sizeD
|| pavInstOpnd->size == sizeF))
|| (tmplSize[index] == sizeA
&& (pavInstOpnd->size == sizeD
|| pavInstOpnd->size == sizeQ)));
*lpulErr = (ULONG) xosdAsmSize;
}
}
}
// if more operands to read, then no match
if (fMatch & fNextOpnd) {
fMatch = FALSE;
index++; // next operand is in error
*lpulErr = (ULONG) xosdAsmTooMany;
}
return fMatch ? (BYTE)0 : index;
}
XOSD CheckTemplate ( void ) {
BYTE index;
// if fForceSize is set, then the first (and only) operand is a
// memory type. return an error if its size is unspecified.
if (fForceSize && avInstOpnd[0].size == sizeX) {
return xosdAsmOperand;
}
// test for template with leading entries of 'Xb', where
// 'X' includes all types except immediate ('I'). if any
// are defined, at least one operand must have a byte size.
// this handles the cases of byte or word/dword ambiguity for
// instructions with no register operands.
sizeOpnd = sizeX;
for (index = 0; index < 2; index++)
if (tmplType[index] != typImm && tmplSize[index] == sizeB) {
if (avInstOpnd[index].size != sizeX)
sizeOpnd = avInstOpnd[index].size;
}
else
break;
if (index != 0 && sizeOpnd == sizeX) {
return xosdAsmSize;
}
// for templates with one entry of 'Xp', where 'X' is
// not 'A', allowable sizes are sizeX (unspecified),
// sizeD (dword), and sizeF (fword). process by
// mapping entry sizes 'p' -> 'v', sizeD -> sizeW,
// and sizeF -> sizeD
// (template 'Ap' is absolute with explicit segment and
// 'v'-sized offset - really treated as 'Av')
if (tmplSize[0] == sizeP) {
tmplSize[0] = sizeV;
if (avInstOpnd[0].size == sizeD)
avInstOpnd[0].size = sizeW;
if (avInstOpnd[0].size == sizeF)
avInstOpnd[0].size = sizeD;
}
// for templates with the second entry of 'Ma', the
// allowable sizes are sizeX (unspecified),
// sizeD (dword), and sizeQ (qword). process by
// mapping entry sizes 'a' -> 'v', sizeD -> sizeW,
// and sizeQ -> sizeD
// (template entry 'Ma' is used only with the BOUND instruction)
if (tmplSize[1] == sizeA) {
tmplSize[1] = sizeV;
if (avInstOpnd[1].size == sizeD)
avInstOpnd[1].size = sizeW;
if (avInstOpnd[1].size == sizeQ)
avInstOpnd[1].size = sizeD;
}
// test for template with leading entries of 'Xv' optionally
// followed by one 'Iv' entry. if two 'Xv' entries, set
// size error if one is word and the other is dword. if
// 'Iv' entry, test for overflow.
sizeOpnd = sizeX;
for (index = 0; index < 3; index++)
if (tmplSize[index] == sizeV)
if (tmplType[index] != typImm) {
// template entry is 'Xv', set size and check size
if (avInstOpnd[index].size != sizeX) {
if (
sizeOpnd != sizeX &&
sizeOpnd != avInstOpnd[index].size
) {
return xosdAsmSize;
}
sizeOpnd = avInstOpnd[index].size;
}
}
else {
// template entry is 'Iv', set sizeOpnd to either
// sizeW or sizeD and check for overflow
if (sizeOpnd == sizeX)
sizeOpnd = (BYTE)(fDBit ? sizeD : sizeW);
if (sizeOpnd == sizeW && avInstOpnd[index].size == sizeD) {
return xosdAsmOverFlow;
}
}
return xosdNone;
}
BYTE CheckPrefix (LPBYTE lpbTemplate)
{
BYTE fPrefix;
fPrefix = (BYTE)(lpbTemplate && *lpbTemplate != 0x0f
&& (*lpbTemplate & ~7) != 0xd8
&& *(lpbTemplate + 1) == (asPrfx + tEnd + eEnd));
if (fPrefix)
*lpbBin++ = *lpbTemplate;
return fPrefix;
}
XOSD AssembleInstr ( void ) {
BYTE size;
BYTE index;
PASM_VALUE pavInstOpnd;
// set operand override flag if operand size differs than fDBit
// (the flag may already be set due to opcode template flag)
if ((sizeOpnd == sizeW && fDBit)
|| (sizeOpnd == sizeD && !fDBit))
fOpndOvrd = TRUE;
// for each operand of the successfully matched template,
// build the assembled instruction
// for template entries with size 'v', sizeOpnd has the size
for (index = 0; index < cntTmplOpnd; index++) {
pavInstOpnd = &avInstOpnd[index];
size = tmplSize[index];
if (size == sizeV)
size = sizeOpnd;
switch ( tmplType [ index ] ) {
case typExp:
case typMem:
if ( !segOvrd ) { // first one only (movsb...)
segOvrd = segToOvrdByte[pavInstOpnd->segovr];
}
if ( fSegOnly ) {
break;
}
fModrm = TRUE;
if ( pavInstOpnd->flags == fREG ) {
modModrm = 3;
rmModrm = pavInstOpnd->base;
}
else {
addrValue = (LONG)pavInstOpnd->value;
// for 16-bit or 32-bit index off (E)BP, make
// zero displacement a byte one
if (
addrValue == 0 &&
( pavInstOpnd->flags != fPTR16 || pavInstOpnd->base != 6 ) &&
( pavInstOpnd->flags != fPTR32 || pavInstOpnd->base != indBP )
) {
modModrm = 0;
}
else if (addrValue >= -0x80L && addrValue <= 0x7fL) {
modModrm = 1;
addrSize = 1;
}
else if (
pavInstOpnd->flags == fPTR32 ||
( pavInstOpnd->flags == fPTR && fDBit )
) {
modModrm = 2;
addrSize = 4;
}
else if ( addrValue >= -0x8000L && addrValue <= 0xffffL ) {
modModrm = 2;
addrSize = 2;
}
else {
return xosdAsmOverFlow;
}
if ( pavInstOpnd->flags == fPTR ) {
modModrm = 0;
addrSize = (BYTE)((1 + fDBit) << 1);
rmModrm = (BYTE)(6 - fDBit);
}
else if (pavInstOpnd->flags == fPTR16) {
fAddrOvrd = fDBit;
rmModrm = pavInstOpnd->base;
if ( modModrm == 0 && rmModrm == 6 ) {
modModrm = 1;
}
}
else {
fAddrOvrd = (BYTE)!fDBit;
if (
pavInstOpnd->index == 0xff &&
pavInstOpnd->base != indSP
) {
rmModrm = pavInstOpnd->base;
if ( modModrm == 0 && rmModrm == 5 ) {
modModrm++;
}
}
else {
rmModrm = 4;
fSib = TRUE;
if (pavInstOpnd->base != 0xff) {
baseSib = pavInstOpnd->base;
if (modModrm == 0 && baseSib == 5)
modModrm++;
}
else {
baseSib = 5;
}
if ( pavInstOpnd->index != 0xff ) {
indexSib = pavInstOpnd->index;
scaleSib = pavInstOpnd->scale;
}
else {
indexSib = 4;
scaleSib = 0;
}
}
}
}
break;
case typGen:
if ( fAddToOp ) {
inOpcode += pavInstOpnd->base;
}
else {
regModrm = pavInstOpnd->base;
}
break;
case typSgr:
regModrm = (BYTE)( pavInstOpnd->base - 1 );
// remove list offset
break;
case typReg:
rmModrm = pavInstOpnd->base;
break;
case typImm:
if ( immedSize == 0 ) {
immedSize = size;
immedValue = pavInstOpnd->value;
}
else {
immedSize2 = size;
immedValue2 = pavInstOpnd->value;
}
break;
case typJmp:
// compute displacment for byte offset instruction
// and test if in range
addrValue = pavInstOpnd->value - ( offAddr ( addrAssem ) + 2);
if ( addrValue >= -0x80L && addrValue <= 0x7fL ) {
addrSize = 1;
}
else {
// too large for byte, compute for word offset
// and test again if in range
// also allow for two-byte opcode 0f xx
addrValue -= 1 + (preOpcode == 0x0f);
if (!fDBit) {
if (addrValue >= -0x8000L && addrValue <= 0x7fffL)
addrSize = 2;
else
return xosdAsmBadRange;
}
else {
// recompute again for dword offset instruction
addrValue -= 2;
addrSize = 4;
}
}
fOpndOvrd = FALSE; // operand size override is NOT set
break;
case typCtl:
case typDbg:
case typTrc:
fModrm = TRUE;
modModrm = 3;
regModrm = pavInstOpnd->base;
break;
case typSti:
postOpcode += pavInstOpnd->base;
break;
case typSeg:
break;
case typXsi:
case typYdi:
fAddrOvrd = (BYTE)
((BYTE)(pavInstOpnd->flags == fPTR32) != fDBit);
break;
case typOff:
segOvrd = segToOvrdByte[pavInstOpnd->segovr];
goto jumpAssem;
case typAbs:
fSegPtr = TRUE;
segPtr = pavInstOpnd->segment;
jumpAssem:
addrValue = (LONG)pavInstOpnd->value;
if (!fDBit)
if (addrValue >= -0x8000L && addrValue <= 0xffffL)
addrSize = 2;
else
return xosdAsmOverFlow;
else
addrSize = 4;
break;
}
}
return xosdNone;
}
BYTE MatchOperand ( PASM_VALUE pavOpnd, BYTE tmplType ) {
BYTE fMatch;
// if immediate operand, set minimum unsigned size
if (pavOpnd->flags == fIMM) {
if ((LONG)pavOpnd->value >= -0x80L && (LONG)pavOpnd->value <= 0xffL)
pavOpnd->size = sizeB;
else if ((LONG)pavOpnd->value >= -0x8000L
&& (LONG)pavOpnd->value <= 0xffffL)
pavOpnd->size = sizeW;
else
pavOpnd->size = sizeD;
}
// start matching of operands
// compare the template and input operand types
switch (tmplType) {
case typAX:
fMatch = (BYTE)((pavOpnd->flags & fREG)
&& pavOpnd->index == regG && pavOpnd->base == indAX);
break;
case typCL:
fMatch = (BYTE)((pavOpnd->flags & fREG)
&& pavOpnd->index == regG && pavOpnd->size == sizeB
&& pavOpnd->base == indCX);
break;
case typDX:
fMatch = (BYTE)((pavOpnd->flags & fREG)
&& pavOpnd->index == regG && pavOpnd->size == sizeW
&& pavOpnd->base == indDX);
break;
case typAbs:
fMatch = (BYTE)(pavOpnd->flags & fFPTR);
break;
case typExp:
fMatch = (BYTE)((pavOpnd->flags == fREG
&& pavOpnd->index == regG)
|| (pavOpnd->flags == fIMM && pavOpnd->reloc == 1)
|| (pavOpnd->flags & (fPTR | fPTR16 | fPTR32)) != 0);
break;
case typGen:
case typReg:
fMatch = (BYTE)(pavOpnd->flags == fREG
&& pavOpnd->index == regG);
break;
case typIm1:
fMatch = (BYTE)(pavOpnd->flags == fIMM && pavOpnd->value == 1);
break;
case typIm3:
fMatch = (BYTE)(pavOpnd->flags == fIMM && pavOpnd->value == 3);
break;
case typImm:
fMatch = (BYTE)(pavOpnd->flags == fIMM && pavOpnd->reloc == 0);
break;
case typJmp:
fMatch = (BYTE)(pavOpnd->flags == fIMM);
break;
case typMem:
fMatch = (BYTE)((pavOpnd->flags == fIMM && pavOpnd->reloc == 1)
|| ((pavOpnd->flags & (fPTR | fPTR16 | fPTR32)) != 0));
break;
case typCtl:
fMatch = (BYTE)(pavOpnd->flags == fREG
&& pavOpnd->index == regC);
break;
case typDbg:
fMatch = (BYTE)(pavOpnd->flags == fREG
&& pavOpnd->index == regD);
break;
case typTrc:
fMatch = (BYTE)(pavOpnd->flags == fREG
&& pavOpnd->index == regT);
break;
case typSt:
fMatch = (BYTE)(pavOpnd->flags == fREG
&& pavOpnd->index == regF);
break;
case typSti:
fMatch = (BYTE)(pavOpnd->flags == fREG
&& pavOpnd->index == regI);
break;
case typSeg:
fMatch = (BYTE)(pavOpnd->flags == fREG && pavOpnd->index == regS
&& pavOpnd->base == segIndex);
break;
case typSgr:
fMatch = (BYTE)(pavOpnd->flags == fREG
&& pavOpnd->index == regS);
break;
case typXsi:
fMatch = (BYTE)(((pavOpnd->flags == fPTR16 && pavOpnd->base == 4)
|| (pavOpnd->flags == fPTR32 && pavOpnd->base == indSI
&& pavOpnd->index == 0xff))
&& pavOpnd->value == 0
&& (pavOpnd->segovr == segX
|| pavOpnd->segovr == segDS));
break;
case typYdi:
fMatch = (BYTE)(((pavOpnd->flags == fPTR16 && pavOpnd->base == 5)
|| (pavOpnd->flags == fPTR32 && pavOpnd->base == indDI
&& pavOpnd->index == 0xff))
&& pavOpnd->value == 0
&& pavOpnd->segovr == segES);
break;
case typOff:
fMatch = (BYTE)((pavOpnd->flags == fIMM && pavOpnd->reloc == 1)
|| pavOpnd->flags == fPTR);
break;
default:
fMatch = FALSE;
break;
}
return fMatch;
}
void OutputInstr ( void ) {
if ( fWaitPrfx ) {
*lpbBin++ = 0x9b;
}
if ( fAddrOvrd ) {
*lpbBin++ = 0x67;
}
if ( fOpndOvrd ) {
*lpbBin++ = 0x66;
}
if ( segOvrd ) {
*lpbBin++ = segOvrd;
}
if ( preOpcode ) {
*lpbBin++ = preOpcode;
}
*lpbBin++ = inOpcode;
if ( postOpcode ) {
*lpbBin++ = postOpcode;
}
if ( fModrm ) {
*lpbBin++ = (BYTE)((((modModrm << 3) + regModrm) << 3) + rmModrm);
}
if ( fSib ) {
*lpbBin++ = (BYTE)((((scaleSib << 3) + indexSib) << 3) + baseSib);
}
OutputValue ( addrSize, (LPBYTE)&addrValue); // size = 0, 1, 2, 4
OutputValue ( (BYTE)(fSegPtr << 1), (LPBYTE)&segPtr); // size = 0, 2
OutputValue ( immedSize, (LPBYTE)&immedValue); // size = 0, 1, 2, 4
OutputValue ( immedSize2, (LPBYTE)&immedValue2); // size = 0, 1, 2, 4
}
void OutputValue ( BYTE size, LPBYTE pchValue ) {
while (size--)
*lpbBin++ = *pchValue++;
}