//---------------------------------------------------------------------------- // // Assemble X86 machine implementation. // // Copyright (C) Microsoft Corporation, 2000-2002. // //---------------------------------------------------------------------------- #include "ntsdp.hpp" #include "i386_asm.h" UCHAR asm386(ULONG, PUCHAR, PUCHAR); UCHAR CheckData(void); PUCHAR ProcessOpcode(void); PUCHAR GetTemplate(PUCHAR); UCHAR MatchTemplate(PULONG); void CheckTemplate(void); UCHAR CheckPrefix(PUCHAR); void AssembleInstr(void); UCHAR MatchOperand(PASM_VALUE, UCHAR); void OutputInstr(void); void OutputValue(UCHAR size, PUCHAR pchValue); extern UCHAR PeekAsmChar(void); extern ULONG PeekAsmToken(PULONG); extern void AcceptAsmToken(void); extern void GetAsmExpr(PASM_VALUE, UCHAR); extern void GetAsmOperand(PASM_VALUE); extern PUCHAR X86SearchOpcode(PUCHAR); extern ULONG savedAsmClass; extern OPNDTYPE mapOpndType[]; // flags and values to build the assembled instruction static UCHAR fWaitPrfx; // if set, use WAIT prefix for float instr static UCHAR fOpndOvrd; // if set, use operand override prefix static UCHAR fAddrOvrd; // if set, use address override prefix static UCHAR segOvrd; // if nonzero, use segment override prefix static UCHAR preOpcode; // if nonzero, use byte before opcode static UCHAR inOpcode; // opcode of instruction static UCHAR postOpcode; // if nonzero, use byte after opcode static UCHAR fModrm; // if set, modrm byte is defined static UCHAR modModrm; // if fModrm, mod component of modrm static UCHAR regModrm; // if fModrm, reg component of modrm static UCHAR rmModrm; // if fModrm, rm component of modrm static UCHAR fSib; // if set, sib byte is defined static UCHAR scaleSib; // if fSib, scale component of sib static UCHAR indexSib; // if fSib, index component of sib static UCHAR baseSib; // if fSib, base component of sib static UCHAR fSegPtr; // if set, segment for far call defined static USHORT segPtr; // if fSegPtr, value of far call segment static UCHAR addrSize; // size of address: 0, 1, 2, 4 static LONG addrValue; // value of address, if used static UCHAR immedSize; // size of immediate: 0, 1, 2, 4 static LONG immedValue; // value of immediate, if used static UCHAR immedSize2; // size of second immediate, if used static LONG immedValue2; // value of second immediate, if used static ULONG addrAssem; // assembly address (formal) static PUCHAR pchBin; // pointer to binary result string // flags and values of the current instruction template being used static UCHAR cntTmplOpnd; // count of operands in template static UCHAR tmplType[3]; // operand types for current template static UCHAR tmplSize[3]; // operand sizes for current template static UCHAR fForceSize; // set if operand size must be specified static UCHAR fAddToOp; // set if addition to opcode static UCHAR fNextOpnd; // set if character exists for next operand static UCHAR fSegOnly; // set if only segment is used for operand static UCHAR fMpNext; // set on 'Mv' tmpl if next tmpl is 'Mp' static UCHAR segIndex; // index of segment for PUSH/POP // values describing the operands processed from the command line static UCHAR cntInstOpnd; // count of operands read from input line static UCHAR sizeOpnd; // size of operand for template with size v static ASM_VALUE avInstOpnd[3]; // asm values from input line PUCHAR pchAsmLine; // pointer to input line (formal) UCHAR fDBit = TRUE; // set for 32-bit addr/operand mode UCHAR segToOvrdByte[] = { 0x00, // segX 0x26, // segES 0x2e, // segCS 0x36, // segSS 0x3e, // segDS 0x64, // segFS 0x65 // segGS }; void BaseX86MachineInfo::Assemble(ProcessInfo* Process, PADDR paddr, PSTR pchInput) { ULONG length; UCHAR chBinary[60]; length = (ULONG)asm386((ULONG)Flat(*paddr), (PUCHAR)pchInput, chBinary); if (length) { if (g_Target->WriteAllVirtual(Process, Flat(*paddr), chBinary, length) != S_OK) { error(MEMORY); } AddrAdd(paddr,length); } } UCHAR asm386 (ULONG addrAssemble, PUCHAR pchAssemble, PUCHAR pchBinary) { PUCHAR pchTemplate; UCHAR index; // loop index and temp ULONG temp; // general temporary value UCHAR errIndex; // error index of all templates ULONG errType; // error type of all templates // initialize flags and state variables addrAssem = addrAssemble; // make assembly address global pchAsmLine = pchAssemble; // make input string pointer global pchBin = pchBinary; // 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 // check for data entry commands for byte (db), word (dw), dword (dd) // if so, process multiple operands directly if (!CheckData()) { // from the string in pchAsmLine, 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 pchTemplate = ProcessOpcode(); while (CheckPrefix(pchTemplate)); // if a pending opcode to process, pchTemplate is not NULL if (pchTemplate) { // fNextOpnd is initially set on the condition of characters // being available for the first operand on the input line fNextOpnd = (UCHAR)(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 pchTemplate = GetTemplate(pchTemplate); // 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); // 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 == TOOFEW || errType == TOOMANY || temp == BADSIZE || temp == BADRANGE || temp == OVERFLOW))) { errIndex = index; errType = temp; }; } while (index && pchTemplate); // if error occured on template match, process it if (index) error(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. CheckTemplate(); // from the template and operand information, set the field // information of the assembled instruction AssembleInstr(); // from the assembled instruction information, create the // corresponding binary information OutputInstr(); } } // return the size of the binary string output (can be zero) return (UCHAR)(pchBin - pchBinary); // length of binary string } UCHAR CheckData (void) { PUCHAR pchBinStart = pchBin; UCHAR ch; UCHAR size = 0; ASM_VALUE avItem; ULONG temp; // perform an explicit parse for 'db', 'dw', and 'dd' // and set size to that of the data item ch = PeekAsmChar(); if (tolower(ch) == 'd') { ch = (UCHAR)tolower(*(pchAsmLine + 1)); if (ch == 'b') size = 1; if (ch == 'w') size = 2; if (ch == 'd') size = 4; if (size) { ch = *(pchAsmLine + 2); if (ch != ' ' && ch != '\t' && ch != '\0') size = 0; } } // if a valid command entered, then size is nonzero if (size) { // move pointer over command and set loop condition pchAsmLine += 2; temp = ASM_COMMA_CLASS; // for each item in list: // check for binary buffer overflow // get expression value - error if not immediate value // test for byte and word overflow, if applicable // write the value to the binary buffer // check for comma for next operand while (temp == ASM_COMMA_CLASS) { if (pchBin >= pchBinStart + 40) error(LISTSIZE); GetAsmExpr(&avItem, FALSE); if (!(avItem.flags & fIMM)) error(OPERAND); if (avItem.reloc > 1) error(RELOC); if ((size == 1 && ((LONG)avItem.value < -0x80L || (LONG)avItem.value > 0xffL)) || (size == 2 && ((LONG)avItem.value < -0x8000L || (LONG)avItem.value > 0xffffL))) error(OVERFLOW); OutputValue(size, (PUCHAR)&avItem.value); temp = PeekAsmToken(&temp); if (temp == ASM_COMMA_CLASS) AcceptAsmToken(); else if (temp != ASM_EOL_CLASS) error(SYNTAX); } // check for any remaining part after the last operand if (PeekAsmChar() != '\0') error(SYNTAX); } // return size of item listed (zero for none) return size; } PUCHAR ProcessOpcode (void) { UCHAR ch; UCHAR cbOpcode = 0; PUCHAR pchTemplate; UCHAR szOpcode[12]; // skip over any leading white space do ch = *pchAsmLine++; 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 = (UCHAR)tolower(ch); while (((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) && cbOpcode < 11) { szOpcode[cbOpcode++] = ch; ch = (UCHAR)tolower(*pchAsmLine); pchAsmLine++; } // if empty or too long, then error if (cbOpcode == 0 || cbOpcode == 11) error(BADOPCODE); // allow opcode to have trailing colon and terminate if (ch == ':') { szOpcode[cbOpcode++] = ch; ch = (UCHAR)tolower(*pchAsmLine); pchAsmLine++; } szOpcode[cbOpcode] = '\0'; pchAsmLine--; // get pointer to template series for opcode found pchTemplate = X86SearchOpcode(szOpcode); if (pchTemplate == NULL) error(BADOPCODE); return pchTemplate; } PUCHAR GetTemplate (PUCHAR pchTemplate) { UCHAR ch; UCHAR ftEnd; // set if tEnd for last template in list UCHAR 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 = *pchTemplate++; // set pre-opcode for two-byte opcodes (0x0f??) and advance // template if needed if (ch == 0x0f) { preOpcode = ch; ch = *pchTemplate++; } 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 = *pchTemplate; if (ch >= 0xc0) { postOpcode = ch; pchTemplate++; } } // 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 = *pchTemplate++; // extract the tEnd and eEnd bits from the token ftEnd = (UCHAR)(ch & tEnd); feEnd = (UCHAR)(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 = (UCHAR)!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 = (UCHAR)(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 = *pchTemplate++; 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 : pchTemplate); } UCHAR MatchTemplate (PULONG pErrType) { UCHAR fMatch = TRUE; UCHAR 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; *pErrType = TOOFEW; if (fMatch) { cntInstOpnd++; GetAsmOperand(pavInstOpnd); // 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 error(EXTRACHARS); // bad parse - immediate error } } if (fMatch) { fMatch = MatchOperand(pavInstOpnd, tmplType[index]); *pErrType = OPERAND; } // 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 - (addrAssem + 2); fMatch = (UCHAR)(tmplSize[index] == sizeV || ((LONG)temp >= -0x80 && (LONG)temp <= 0x7f)); *pErrType = BADRANGE; } else if (tmplType[index] == typImm || tmplType[index] == typImmEx) { // for immediate operand, // template sizeV matches sizeB, sizeW, sizeV (all) // template sizeW matches sizeB, sizeW // template sizeB matches sizeB fMatch = (UCHAR)(tmplSize[index] == sizeV || pavInstOpnd->size == tmplSize[index] || pavInstOpnd->size == sizeB); *pErrType = OVERFLOW; } 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 = (UCHAR)(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))); *pErrType = BADSIZE; } } } // if more operands to read, then no match if (fMatch & fNextOpnd) { fMatch = FALSE; index++; // next operand is in error *pErrType = TOOMANY; } return fMatch ? (UCHAR)0 : index; } void CheckTemplate (void) { UCHAR 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) error(OPERAND); // 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 && tmplType[index] != typImmEx) && tmplSize[index] == sizeB) { if (avInstOpnd[index].size != sizeX) sizeOpnd = avInstOpnd[index].size; } else break; if (index != 0 && sizeOpnd == sizeX) error(BADSIZE); // 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 && tmplType[index] != typImmEx) { // template entry is 'Xv', set size and check size if (avInstOpnd[index].size != sizeX) { if (sizeOpnd != sizeX && sizeOpnd != avInstOpnd[index].size) error(BADSIZE); sizeOpnd = avInstOpnd[index].size; } } else { // template entry is 'Iv', set sizeOpnd to either // sizeW or sizeD and check for overflow if (sizeOpnd == sizeX) sizeOpnd = (UCHAR)(fDBit ? sizeD : sizeW); if (sizeOpnd == sizeW && avInstOpnd[index].size == sizeD) error(OVERFLOW); } } UCHAR CheckPrefix (PUCHAR pchTemplate) { UCHAR fPrefix; fPrefix = (UCHAR)(pchTemplate && *pchTemplate != 0x0f && (*pchTemplate & ~7) != 0xd8 && *(pchTemplate + 1) == (asPrfx + tEnd + eEnd)); if (fPrefix) *pchBin++ = *pchTemplate; return fPrefix; } void AssembleInstr (void) { UCHAR size; UCHAR 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 error(OVERFLOW); if (pavInstOpnd->flags == fPTR) { modModrm = 0; addrSize = (UCHAR)((1 + fDBit) << 1); rmModrm = (UCHAR)(6 - fDBit); } else if (pavInstOpnd->flags == fPTR16) { fAddrOvrd = fDBit; rmModrm = pavInstOpnd->base; if (modModrm == 0 && rmModrm == 6) modModrm = 1; } else { fAddrOvrd = (UCHAR)!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 = (UCHAR)(pavInstOpnd->base - 1); // remove list offset break; case typReg: rmModrm = pavInstOpnd->base; break; case typImm: case typImmEx: 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 // skip this check if the template is a rel16/32 // type addrValue = pavInstOpnd->value - (addrAssem + 2); if (tmplSize[index] != sizeV && 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 error(BADRANGE); } 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 = (UCHAR) ((UCHAR)(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 error(OVERFLOW); else addrSize = 4; break; } } } UCHAR MatchOperand (PASM_VALUE pavOpnd, UCHAR tmplType) { UCHAR fMatch; // if immediate operand, set minimum unsigned size if (pavOpnd->flags & fIMM) { pavOpnd->size = sizeD; if ((pavOpnd->flags & fSIGNED) || tmplType == typImmEx) { if ((LONG)pavOpnd->value >= -0x80L && (LONG)pavOpnd->value <= 0x7fL) pavOpnd->size = sizeB; else if ((LONG)pavOpnd->value >= -0x8000L && (LONG)pavOpnd->value <= 0x7fffL) pavOpnd->size = sizeW; } else { if (pavOpnd->value <= 0xffL) pavOpnd->size = sizeB; else if (pavOpnd->value <= 0xffffL) pavOpnd->size = sizeW; } } // start matching of operands // compare the template and input operand types switch (tmplType) { case typAX: fMatch = (UCHAR)((pavOpnd->flags & fREG) && pavOpnd->index == regG && pavOpnd->base == indAX); break; case typCL: fMatch = (UCHAR)((pavOpnd->flags & fREG) && pavOpnd->index == regG && pavOpnd->size == sizeB && pavOpnd->base == indCX); break; case typDX: fMatch = (UCHAR)((pavOpnd->flags & fREG) && pavOpnd->index == regG && pavOpnd->size == sizeW && pavOpnd->base == indDX); break; case typAbs: fMatch = (UCHAR)(pavOpnd->flags & fFPTR); break; case typExp: fMatch = (UCHAR)((pavOpnd->flags == fREG && pavOpnd->index == regG) || ((pavOpnd->flags & fIMM) && pavOpnd->reloc == 1) || (pavOpnd->flags & (fPTR | fPTR16 | fPTR32)) != 0); break; case typGen: case typReg: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regG); break; case typIm1: fMatch = (UCHAR)((pavOpnd->flags & fIMM) && pavOpnd->value == 1); break; case typIm3: fMatch = (UCHAR)((pavOpnd->flags & fIMM) && pavOpnd->value == 3); break; case typImm: case typImmEx: fMatch = (UCHAR)((pavOpnd->flags & fIMM) && pavOpnd->reloc == 0); break; case typJmp: fMatch = (UCHAR)(pavOpnd->flags & fIMM); break; case typMem: fMatch = (UCHAR)(((pavOpnd->flags & fIMM) && pavOpnd->reloc == 1) || ((pavOpnd->flags & (fPTR | fPTR16 | fPTR32)) != 0)); break; case typCtl: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regC); break; case typDbg: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regD); break; case typTrc: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regT); break; case typSt: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regF); break; case typSti: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regI); break; case typSeg: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regS && pavOpnd->base == segIndex); break; case typSgr: fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regS); break; case typXsi: fMatch = (UCHAR)(((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 = (UCHAR)(((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 = (UCHAR)(((pavOpnd->flags & fIMM) && pavOpnd->reloc == 1) || pavOpnd->flags == fPTR); break; default: fMatch = FALSE; break; } return fMatch; } void OutputInstr (void) { if (fWaitPrfx) *pchBin++ = 0x9b; if (fAddrOvrd) *pchBin++ = 0x67; if (fOpndOvrd) *pchBin++ = 0x66; if (segOvrd) *pchBin++ = segOvrd; if (preOpcode) *pchBin++ = preOpcode; *pchBin++ = inOpcode; if (postOpcode) *pchBin++ = postOpcode; if (fModrm) *pchBin++ = (UCHAR)((((modModrm << 3) + regModrm) << 3) + rmModrm); if (fSib) *pchBin++ = (UCHAR)((((scaleSib << 3) + indexSib) << 3) + baseSib); OutputValue(addrSize, (PUCHAR)&addrValue); // size = 0, 1, 2, 4 OutputValue((UCHAR)(fSegPtr << 1), (PUCHAR)&segPtr); // size = 0, 2 OutputValue(immedSize, (PUCHAR)&immedValue); // size = 0, 1, 2, 4 OutputValue(immedSize2, (PUCHAR)&immedValue2); // size = 0, 1, 2, 4 } void OutputValue (UCHAR size, PUCHAR pchValue) { while (size--) *pchBin++ = *pchValue++; }