Source code of Windows XP (NT5)
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.

1093 lines
37 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Assemble X86 machine implementation.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include "i386_asm.h"
  10. UCHAR asm386(ULONG, PUCHAR, PUCHAR);
  11. UCHAR CheckData(void);
  12. PUCHAR ProcessOpcode(void);
  13. PUCHAR GetTemplate(PUCHAR);
  14. UCHAR MatchTemplate(PULONG);
  15. void CheckTemplate(void);
  16. UCHAR CheckPrefix(PUCHAR);
  17. void AssembleInstr(void);
  18. UCHAR MatchOperand(PASM_VALUE, UCHAR);
  19. void OutputInstr(void);
  20. void OutputValue(UCHAR size, PUCHAR pchValue);
  21. extern UCHAR PeekAsmChar(void);
  22. extern ULONG PeekAsmToken(PULONG);
  23. extern void AcceptAsmToken(void);
  24. extern void GetAsmExpr(PASM_VALUE, UCHAR);
  25. extern void GetAsmOperand(PASM_VALUE);
  26. extern PUCHAR X86SearchOpcode(PUCHAR);
  27. extern ULONG savedAsmClass;
  28. extern OPNDTYPE mapOpndType[];
  29. // flags and values to build the assembled instruction
  30. static UCHAR fWaitPrfx; // if set, use WAIT prefix for float instr
  31. static UCHAR fOpndOvrd; // if set, use operand override prefix
  32. static UCHAR fAddrOvrd; // if set, use address override prefix
  33. static UCHAR segOvrd; // if nonzero, use segment override prefix
  34. static UCHAR preOpcode; // if nonzero, use byte before opcode
  35. static UCHAR inOpcode; // opcode of instruction
  36. static UCHAR postOpcode; // if nonzero, use byte after opcode
  37. static UCHAR fModrm; // if set, modrm byte is defined
  38. static UCHAR modModrm; // if fModrm, mod component of modrm
  39. static UCHAR regModrm; // if fModrm, reg component of modrm
  40. static UCHAR rmModrm; // if fModrm, rm component of modrm
  41. static UCHAR fSib; // if set, sib byte is defined
  42. static UCHAR scaleSib; // if fSib, scale component of sib
  43. static UCHAR indexSib; // if fSib, index component of sib
  44. static UCHAR baseSib; // if fSib, base component of sib
  45. static UCHAR fSegPtr; // if set, segment for far call defined
  46. static USHORT segPtr; // if fSegPtr, value of far call segment
  47. static UCHAR addrSize; // size of address: 0, 1, 2, 4
  48. static LONG addrValue; // value of address, if used
  49. static UCHAR immedSize; // size of immediate: 0, 1, 2, 4
  50. static LONG immedValue; // value of immediate, if used
  51. static UCHAR immedSize2; // size of second immediate, if used
  52. static LONG immedValue2; // value of second immediate, if used
  53. static ULONG addrAssem; // assembly address (formal)
  54. static PUCHAR pchBin; // pointer to binary result string
  55. // flags and values of the current instruction template being used
  56. static UCHAR cntTmplOpnd; // count of operands in template
  57. static UCHAR tmplType[3]; // operand types for current template
  58. static UCHAR tmplSize[3]; // operand sizes for current template
  59. static UCHAR fForceSize; // set if operand size must be specified
  60. static UCHAR fAddToOp; // set if addition to opcode
  61. static UCHAR fNextOpnd; // set if character exists for next operand
  62. static UCHAR fSegOnly; // set if only segment is used for operand
  63. static UCHAR fMpNext; // set on 'Mv' tmpl if next tmpl is 'Mp'
  64. static UCHAR segIndex; // index of segment for PUSH/POP
  65. // values describing the operands processed from the command line
  66. static UCHAR cntInstOpnd; // count of operands read from input line
  67. static UCHAR sizeOpnd; // size of operand for template with size v
  68. static ASM_VALUE avInstOpnd[3]; // asm values from input line
  69. PUCHAR pchAsmLine; // pointer to input line (formal)
  70. UCHAR fDBit = TRUE; // set for 32-bit addr/operand mode
  71. UCHAR segToOvrdByte[] = {
  72. 0x00, // segX
  73. 0x26, // segES
  74. 0x2e, // segCS
  75. 0x36, // segSS
  76. 0x3e, // segDS
  77. 0x64, // segFS
  78. 0x65 // segGS
  79. };
  80. void
  81. BaseX86MachineInfo::Assemble(PADDR paddr, PSTR pchInput)
  82. {
  83. ULONG length;
  84. UCHAR chBinary[60];
  85. length = (ULONG)asm386((ULONG)Flat(*paddr), (PUCHAR)pchInput, chBinary);
  86. if (length) {
  87. // printf("setting memory at addr: %s - count: %d\n",
  88. // FormatAddr64(Flat(*paddr)), length);
  89. if (length != SetMemString(paddr, chBinary, length)) {
  90. error(MEMORY);
  91. }
  92. AddrAdd(paddr,length);
  93. }
  94. }
  95. UCHAR asm386 (ULONG addrAssemble, PUCHAR pchAssemble, PUCHAR pchBinary)
  96. {
  97. PUCHAR pchTemplate;
  98. UCHAR index; // loop index and temp
  99. ULONG temp; // general temporary value
  100. UCHAR errIndex; // error index of all templates
  101. ULONG errType; // error type of all templates
  102. // initialize flags and state variables
  103. addrAssem = addrAssemble; // make assembly address global
  104. pchAsmLine = pchAssemble; // make input string pointer global
  105. pchBin = pchBinary; // make binary string pointer global
  106. savedAsmClass = (ULONG)-1; // no peeked token
  107. segOvrd = 0; // no segment override
  108. cntInstOpnd = 0; // no input operands read yet
  109. fModrm = fSib = fSegPtr = FALSE; // no modrm, sib, or far seg
  110. addrSize = immedSize = immedSize2 = 0; // no addr or immed
  111. // check for data entry commands for byte (db), word (dw), dword (dd)
  112. // if so, process multiple operands directly
  113. if (!CheckData()) {
  114. // from the string in pchAsmLine, parse and lookup the opcode
  115. // to return a pointer to its template. check and process
  116. // any prefixes, reading the next opcode for each prefix
  117. do
  118. pchTemplate = ProcessOpcode();
  119. while (CheckPrefix(pchTemplate));
  120. // if a pending opcode to process, pchTemplate is not NULL
  121. if (pchTemplate) {
  122. // fNextOpnd is initially set on the condition of characters
  123. // being available for the first operand on the input line
  124. fNextOpnd = (UCHAR)(PeekAsmToken(&temp) != ASM_EOL_CLASS);
  125. // continue until match occurs or last template read
  126. errIndex = 0; // start with no error
  127. do {
  128. // get infomation on next template - return pointer to
  129. // next template or NULL if last in list
  130. pchTemplate = GetTemplate(pchTemplate);
  131. // match the loaded template against the operands input
  132. // if mismatch, index has the operand index + 1 of
  133. // the error while temp has the error type.
  134. index = MatchTemplate(&temp);
  135. // determine the error to report as templates are matched
  136. // update errIndex to index if later operand
  137. // if same operand index, prioritize to give best error:
  138. // high: SIZE, BADRANGE, OVERFLOW
  139. // medium: OPERAND
  140. // low: TOOFEW, TOOMANY
  141. if (index > errIndex
  142. || (index == errIndex &&
  143. (errType == TOOFEW || errType == TOOMANY
  144. || temp == SIZE || temp == BADRANGE
  145. || temp == OVERFLOW))) {
  146. errIndex = index;
  147. errType = temp;
  148. };
  149. }
  150. while (index && pchTemplate);
  151. // if error occured on template match, process it
  152. if (index)
  153. error(errType);
  154. // preliminary type and size matching has been
  155. // successful on the current template.
  156. // perform further checks for size ambiguity.
  157. // at this point, the assembly is committed to the current
  158. // template. either an error or a successful assembly
  159. // follows.
  160. CheckTemplate();
  161. // from the template and operand information, set the field
  162. // information of the assembled instruction
  163. AssembleInstr();
  164. // from the assembled instruction information, create the
  165. // corresponding binary information
  166. OutputInstr();
  167. }
  168. }
  169. // return the size of the binary string output (can be zero)
  170. return (UCHAR)(pchBin - pchBinary); // length of binary string
  171. }
  172. UCHAR CheckData (void)
  173. {
  174. PUCHAR pchBinStart = pchBin;
  175. UCHAR ch;
  176. UCHAR size = 0;
  177. ASM_VALUE avItem;
  178. ULONG temp;
  179. // perform an explicit parse for 'db', 'dw', and 'dd'
  180. // and set size to that of the data item
  181. ch = PeekAsmChar();
  182. if (tolower(ch) == 'd') {
  183. ch = (UCHAR)tolower(*(pchAsmLine + 1));
  184. if (ch == 'b')
  185. size = 1;
  186. if (ch == 'w')
  187. size = 2;
  188. if (ch == 'd')
  189. size = 4;
  190. if (size) {
  191. ch = *(pchAsmLine + 2);
  192. if (ch != ' ' && ch != '\t' && ch != '\0')
  193. size = 0;
  194. }
  195. }
  196. // if a valid command entered, then size is nonzero
  197. if (size) {
  198. // move pointer over command and set loop condition
  199. pchAsmLine += 2;
  200. temp = ASM_COMMA_CLASS;
  201. // for each item in list:
  202. // check for binary buffer overflow
  203. // get expression value - error if not immediate value
  204. // test for byte and word overflow, if applicable
  205. // write the value to the binary buffer
  206. // check for comma for next operand
  207. while (temp == ASM_COMMA_CLASS) {
  208. if (pchBin >= pchBinStart + 40)
  209. error(LISTSIZE);
  210. GetAsmExpr(&avItem, FALSE);
  211. if (avItem.flags != fIMM)
  212. error(OPERAND);
  213. if (avItem.reloc > 1)
  214. error(RELOC);
  215. if ((size == 1 && ((LONG)avItem.value < -0x80L
  216. || (LONG)avItem.value > 0xffL))
  217. || (size == 2 && ((LONG)avItem.value < -0x8000L
  218. || (LONG)avItem.value > 0xffffL)))
  219. error(OVERFLOW);
  220. OutputValue(size, (PUCHAR)&avItem.value);
  221. temp = PeekAsmToken(&temp);
  222. if (temp == ASM_COMMA_CLASS)
  223. AcceptAsmToken();
  224. else if (temp != ASM_EOL_CLASS)
  225. error(SYNTAX);
  226. }
  227. // check for any remaining part after the last operand
  228. if (PeekAsmChar() != '\0')
  229. error(SYNTAX);
  230. }
  231. // return size of item listed (zero for none)
  232. return size;
  233. }
  234. PUCHAR ProcessOpcode (void)
  235. {
  236. UCHAR ch;
  237. UCHAR cbOpcode = 0;
  238. PUCHAR pchTemplate;
  239. UCHAR szOpcode[12];
  240. // skip over any leading white space
  241. do
  242. ch = *pchAsmLine++;
  243. while (ch == ' ' || ch == '\t');
  244. // return NULL if end of line
  245. if (ch == '\0')
  246. return NULL;
  247. // parse out opcode - first string [a-z] [0-9] (case insensitive)
  248. ch = (UCHAR)tolower(ch);
  249. while (((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) &&
  250. cbOpcode < 11) {
  251. szOpcode[cbOpcode++] = ch;
  252. ch = (UCHAR)tolower(*pchAsmLine); pchAsmLine++;
  253. }
  254. // if empty or too long, then error
  255. if (cbOpcode == 0 || cbOpcode == 11)
  256. error(BADOPCODE);
  257. // allow opcode to have trailing colon and terminate
  258. if (ch == ':') {
  259. szOpcode[cbOpcode++] = ch;
  260. ch = (UCHAR)tolower(*pchAsmLine); pchAsmLine++;
  261. }
  262. szOpcode[cbOpcode] = '\0';
  263. pchAsmLine--;
  264. // get pointer to template series for opcode found
  265. pchTemplate = X86SearchOpcode(szOpcode);
  266. if (pchTemplate == NULL)
  267. error(BADOPCODE);
  268. return pchTemplate;
  269. }
  270. PUCHAR GetTemplate (PUCHAR pchTemplate)
  271. {
  272. UCHAR ch;
  273. UCHAR ftEnd; // set if tEnd for last template in list
  274. UCHAR feEnd; // set if eEnd for last token in template
  275. // initialize template variables and flags
  276. cntTmplOpnd = segIndex = 0;
  277. tmplType[0] = tmplType[1] = tmplType[2] = typNULL;
  278. tmplSize[0] = tmplSize[1] = tmplSize[2] = sizeX;
  279. fForceSize = fAddToOp = fSegOnly = fMpNext = FALSE;
  280. fWaitPrfx = FALSE; // no WAIT prefix
  281. fOpndOvrd = fAddrOvrd = FALSE; // no operand or addr overrides
  282. preOpcode = postOpcode = 0; // no pre- or post-opcode
  283. regModrm = 0; // this is part of some opcodes
  284. ch = *pchTemplate++;
  285. // set pre-opcode for two-byte opcodes (0x0f??) and advance
  286. // template if needed
  287. if (ch == 0x0f) {
  288. preOpcode = ch;
  289. ch = *pchTemplate++;
  290. }
  291. inOpcode = ch; // set opcode
  292. // set post-opcode and advance template for floating-point
  293. // instructions (0xd8 - 0xdf) using a second byte in
  294. // the range 0xc0 - 0xff that is read from the template
  295. if ((ch & ~0x7) == 0xd8) {
  296. ch = *pchTemplate;
  297. if (ch >= 0xc0) {
  298. postOpcode = ch;
  299. pchTemplate++;
  300. }
  301. }
  302. // loop for each flag and/or operand token in template
  303. // the last token in the list has the eEnd bit set.
  304. do {
  305. // read the next template token
  306. ch = *pchTemplate++;
  307. // extract the tEnd and eEnd bits from the token
  308. ftEnd = (UCHAR)(ch & tEnd);
  309. feEnd = (UCHAR)(ch & eEnd);
  310. ch &= ~(tEnd | eEnd);
  311. // if extracted token is a flag, do the appropriate action
  312. if (ch < asRegBase)
  313. switch (ch) {
  314. case as0x0a:
  315. // the postOpcode is set for some decimal instructions
  316. postOpcode = 0x0a;
  317. break;
  318. case asOpRg:
  319. // fAddToOp is set if the register index is added
  320. // directly to the base opcode value
  321. fAddToOp = TRUE;
  322. break;
  323. case asSiz0:
  324. // fOpndOvrd is set or cleared to force a 16-bit operand
  325. fOpndOvrd = fDBit;
  326. break;
  327. case asSiz1:
  328. // fOpndOvrd is set or cleared to force a 32-bit operand
  329. fOpndOvrd = (UCHAR)!fDBit;
  330. break;
  331. case asWait:
  332. // the flag fWaitPrfx is set to emit WAIT before the
  333. // instruction
  334. fWaitPrfx = TRUE;
  335. break;
  336. case asSeg:
  337. // in XLAT, the optional memory operand is used to
  338. // just specify a segment override prefix
  339. fSegOnly = TRUE;
  340. break;
  341. case asFSiz:
  342. // fForceSize is set when a specific size of a memory
  343. // operand must be given for some floating instrs
  344. fForceSize = TRUE;
  345. break;
  346. case asMpNx:
  347. // fMpNext is set when the next template operand is
  348. // 'Mp' and is used to determine how to match
  349. // 'Md' since it matches both 'Mp' and 'Mv'
  350. fMpNext = TRUE;
  351. break;
  352. }
  353. // if token is REG value bit, set the variable regModrm to
  354. // set the opcode-dependent reg value in the modrm byte
  355. else if (ch < opnBase)
  356. regModrm = (UCHAR)(ch - asRegBase);
  357. // otherwise, token is operand descriptor.
  358. // if segment operand, get segment number from template
  359. // normalize and map to get operand type and size.
  360. else {
  361. if (ch == opnSeg)
  362. segIndex = *pchTemplate++;
  363. ch -= opnBase;
  364. tmplType[cntTmplOpnd] = mapOpndType[ch].type;
  365. tmplSize[cntTmplOpnd++] = mapOpndType[ch].size;
  366. }
  367. }
  368. while (!ftEnd);
  369. // return either the pointer to the next template or NULL if
  370. // the last template for the opcode has been processed
  371. return (feEnd ? NULL : pchTemplate);
  372. }
  373. UCHAR MatchTemplate (PULONG pErrType)
  374. {
  375. UCHAR fMatch = TRUE;
  376. UCHAR index;
  377. ULONG temp;
  378. PASM_VALUE pavInstOpnd; // pointer to current operand from input
  379. // process matching for each operand in the specified template
  380. // stop at last operand or when mismatch occurs
  381. for (index = 0; index < cntTmplOpnd && fMatch; index++) {
  382. // set pointer to current instruction operand
  383. pavInstOpnd = &avInstOpnd[index];
  384. // if input operand has not yet been read, check flag
  385. // for existence and process it.
  386. if (index == cntInstOpnd) {
  387. fMatch = fNextOpnd;
  388. *pErrType = TOOFEW;
  389. if (fMatch) {
  390. cntInstOpnd++;
  391. GetAsmOperand(pavInstOpnd);
  392. // recompute existence of next possible operand
  393. // comma implies TRUE, EOL implies FALSE, else error
  394. temp = PeekAsmToken(&temp);
  395. if (temp == ASM_COMMA_CLASS) {
  396. AcceptAsmToken();
  397. fNextOpnd = TRUE;
  398. }
  399. else if (temp == ASM_EOL_CLASS)
  400. fNextOpnd = FALSE;
  401. else
  402. error(EXTRACHARS); // bad parse - immediate error
  403. }
  404. }
  405. if (fMatch) {
  406. fMatch = MatchOperand(pavInstOpnd, tmplType[index]);
  407. *pErrType = OPERAND;
  408. }
  409. // if the template and operand type match, do preliminary
  410. // check on size based solely on template size specified
  411. if (fMatch) {
  412. if (tmplType[index] == typJmp) {
  413. // for relative jumps, test if byte offset is
  414. // sufficient by computing offset which is
  415. // the target offset less the offset of the
  416. // next instruction. (assume Jb instructions
  417. // are two bytes in length.
  418. temp = pavInstOpnd->value - (addrAssem + 2);
  419. fMatch = (UCHAR)(tmplSize[index] == sizeV
  420. || ((LONG)temp >= -0x80 && (LONG)temp <= 0x7f));
  421. *pErrType = BADRANGE;
  422. }
  423. else if (tmplType[index] == typImm) {
  424. // for immediate operand,
  425. // template sizeV matches sizeB, sizeW, sizeV (all)
  426. // template sizeW matches sizeB, sizeW
  427. // template sizeB matches sizeB
  428. fMatch = (UCHAR)(tmplSize[index] == sizeV
  429. || pavInstOpnd->size == tmplSize[index]
  430. || pavInstOpnd->size == sizeB);
  431. *pErrType = OVERFLOW;
  432. }
  433. else {
  434. // for nonimmediate operand,
  435. // template sizeX (unspecified) matches all
  436. // operand sizeX (unspecified) matches all
  437. // same template and operand size matches
  438. // template sizeV matches operand sizeW and sizeD
  439. // (EXCEPT for sizeD when fMpNext and fDBit set)
  440. // template sizeP matches operand sizeD and sizeF
  441. // template sizeA matches operand sizeD and sizeQ
  442. fMatch = (UCHAR)(tmplSize[index] == sizeX
  443. || pavInstOpnd->size == sizeX
  444. || tmplSize[index] == pavInstOpnd->size
  445. || (tmplSize[index] == sizeV
  446. && (pavInstOpnd->size == sizeW
  447. || (pavInstOpnd->size == sizeD
  448. && (!fMpNext || fDBit))))
  449. || (tmplSize[index] == sizeP
  450. && (pavInstOpnd->size == sizeD
  451. || pavInstOpnd->size == sizeF))
  452. || (tmplSize[index] == sizeA
  453. && (pavInstOpnd->size == sizeD
  454. || pavInstOpnd->size == sizeQ)));
  455. *pErrType = SIZE;
  456. }
  457. }
  458. }
  459. // if more operands to read, then no match
  460. if (fMatch & fNextOpnd) {
  461. fMatch = FALSE;
  462. index++; // next operand is in error
  463. *pErrType = TOOMANY;
  464. }
  465. return fMatch ? (UCHAR)0 : index;
  466. }
  467. void CheckTemplate (void)
  468. {
  469. UCHAR index;
  470. // if fForceSize is set, then the first (and only) operand is a
  471. // memory type. return an error if its size is unspecified.
  472. if (fForceSize && avInstOpnd[0].size == sizeX)
  473. error(OPERAND);
  474. // test for template with leading entries of 'Xb', where
  475. // 'X' includes all types except immediate ('I'). if any
  476. // are defined, at least one operand must have a byte size.
  477. // this handles the cases of byte or word/dword ambiguity for
  478. // instructions with no register operands.
  479. sizeOpnd = sizeX;
  480. for (index = 0; index < 2; index++)
  481. if (tmplType[index] != typImm && tmplSize[index] == sizeB) {
  482. if (avInstOpnd[index].size != sizeX)
  483. sizeOpnd = avInstOpnd[index].size;
  484. }
  485. else
  486. break;
  487. if (index != 0 && sizeOpnd == sizeX)
  488. error(SIZE);
  489. // for templates with one entry of 'Xp', where 'X' is
  490. // not 'A', allowable sizes are sizeX (unspecified),
  491. // sizeD (dword), and sizeF (fword). process by
  492. // mapping entry sizes 'p' -> 'v', sizeD -> sizeW,
  493. // and sizeF -> sizeD
  494. // (template 'Ap' is absolute with explicit segment and
  495. // 'v'-sized offset - really treated as 'Av')
  496. if (tmplSize[0] == sizeP) {
  497. tmplSize[0] = sizeV;
  498. if (avInstOpnd[0].size == sizeD)
  499. avInstOpnd[0].size = sizeW;
  500. if (avInstOpnd[0].size == sizeF)
  501. avInstOpnd[0].size = sizeD;
  502. }
  503. // for templates with the second entry of 'Ma', the
  504. // allowable sizes are sizeX (unspecified),
  505. // sizeD (dword), and sizeQ (qword). process by
  506. // mapping entry sizes 'a' -> 'v', sizeD -> sizeW,
  507. // and sizeQ -> sizeD
  508. // (template entry 'Ma' is used only with the BOUND instruction)
  509. if (tmplSize[1] == sizeA) {
  510. tmplSize[1] = sizeV;
  511. if (avInstOpnd[1].size == sizeD)
  512. avInstOpnd[1].size = sizeW;
  513. if (avInstOpnd[1].size == sizeQ)
  514. avInstOpnd[1].size = sizeD;
  515. }
  516. // test for template with leading entries of 'Xv' optionally
  517. // followed by one 'Iv' entry. if two 'Xv' entries, set
  518. // size error if one is word and the other is dword. if
  519. // 'Iv' entry, test for overflow.
  520. sizeOpnd = sizeX;
  521. for (index = 0; index < 3; index++)
  522. if (tmplSize[index] == sizeV)
  523. if (tmplType[index] != typImm) {
  524. // template entry is 'Xv', set size and check size
  525. if (avInstOpnd[index].size != sizeX) {
  526. if (sizeOpnd != sizeX && sizeOpnd
  527. != avInstOpnd[index].size)
  528. error(SIZE);
  529. sizeOpnd = avInstOpnd[index].size;
  530. }
  531. }
  532. else {
  533. // template entry is 'Iv', set sizeOpnd to either
  534. // sizeW or sizeD and check for overflow
  535. if (sizeOpnd == sizeX)
  536. sizeOpnd = (UCHAR)(fDBit ? sizeD : sizeW);
  537. if (sizeOpnd == sizeW && avInstOpnd[index].size == sizeD)
  538. error(OVERFLOW);
  539. }
  540. }
  541. UCHAR CheckPrefix (PUCHAR pchTemplate)
  542. {
  543. UCHAR fPrefix;
  544. fPrefix = (UCHAR)(pchTemplate && *pchTemplate != 0x0f
  545. && (*pchTemplate & ~7) != 0xd8
  546. && *(pchTemplate + 1) == (asPrfx + tEnd + eEnd));
  547. if (fPrefix)
  548. *pchBin++ = *pchTemplate;
  549. return fPrefix;
  550. }
  551. void AssembleInstr (void)
  552. {
  553. UCHAR size;
  554. UCHAR index;
  555. PASM_VALUE pavInstOpnd;
  556. // set operand override flag if operand size differs than fDBit
  557. // (the flag may already be set due to opcode template flag)
  558. if ((sizeOpnd == sizeW && fDBit)
  559. || (sizeOpnd == sizeD && !fDBit))
  560. fOpndOvrd = TRUE;
  561. // for each operand of the successfully matched template,
  562. // build the assembled instruction
  563. // for template entries with size 'v', sizeOpnd has the size
  564. for (index = 0; index < cntTmplOpnd; index++) {
  565. pavInstOpnd = &avInstOpnd[index];
  566. size = tmplSize[index];
  567. if (size == sizeV)
  568. size = sizeOpnd;
  569. switch (tmplType[index]) {
  570. case typExp:
  571. case typMem:
  572. if (!segOvrd) // first one only (movsb...)
  573. segOvrd = segToOvrdByte[pavInstOpnd->segovr];
  574. if (fSegOnly)
  575. break;
  576. fModrm = TRUE;
  577. if (pavInstOpnd->flags == fREG) {
  578. modModrm = 3;
  579. rmModrm = pavInstOpnd->base;
  580. }
  581. else {
  582. addrValue = (LONG)pavInstOpnd->value;
  583. // for 16-bit or 32-bit index off (E)BP, make
  584. // zero displacement a byte one
  585. if (addrValue == 0
  586. && (pavInstOpnd->flags != fPTR16
  587. || pavInstOpnd->base != 6)
  588. && (pavInstOpnd->flags != fPTR32
  589. || pavInstOpnd->base != indBP))
  590. modModrm = 0;
  591. else if (addrValue >= -0x80L && addrValue <= 0x7fL) {
  592. modModrm = 1;
  593. addrSize = 1;
  594. }
  595. else if (pavInstOpnd->flags == fPTR32
  596. || (pavInstOpnd->flags == fPTR && fDBit)) {
  597. modModrm = 2;
  598. addrSize = 4;
  599. }
  600. else if (addrValue >= -0x8000L && addrValue <= 0xffffL) {
  601. modModrm = 2;
  602. addrSize = 2;
  603. }
  604. else
  605. error(OVERFLOW);
  606. if (pavInstOpnd->flags == fPTR) {
  607. modModrm = 0;
  608. addrSize = (UCHAR)((1 + fDBit) << 1);
  609. rmModrm = (UCHAR)(6 - fDBit);
  610. }
  611. else if (pavInstOpnd->flags == fPTR16) {
  612. fAddrOvrd = fDBit;
  613. rmModrm = pavInstOpnd->base;
  614. if (modModrm == 0 && rmModrm == 6)
  615. modModrm = 1;
  616. }
  617. else {
  618. fAddrOvrd = (UCHAR)!fDBit;
  619. if (pavInstOpnd->index == 0xff
  620. && pavInstOpnd->base != indSP) {
  621. rmModrm = pavInstOpnd->base;
  622. if (modModrm == 0 && rmModrm == 5)
  623. modModrm++;
  624. }
  625. else {
  626. rmModrm = 4;
  627. fSib = TRUE;
  628. if (pavInstOpnd->base != 0xff) {
  629. baseSib = pavInstOpnd->base;
  630. if (modModrm == 0 && baseSib == 5)
  631. modModrm++;
  632. }
  633. else
  634. baseSib = 5;
  635. if (pavInstOpnd->index != 0xff) {
  636. indexSib = pavInstOpnd->index;
  637. scaleSib = pavInstOpnd->scale;
  638. }
  639. else {
  640. indexSib = 4;
  641. scaleSib = 0;
  642. }
  643. }
  644. }
  645. }
  646. break;
  647. case typGen:
  648. if (fAddToOp)
  649. inOpcode += pavInstOpnd->base;
  650. else
  651. regModrm = pavInstOpnd->base;
  652. break;
  653. case typSgr:
  654. regModrm = (UCHAR)(pavInstOpnd->base - 1);
  655. // remove list offset
  656. break;
  657. case typReg:
  658. rmModrm = pavInstOpnd->base;
  659. break;
  660. case typImm:
  661. if (immedSize == 0) {
  662. immedSize = size;
  663. immedValue = pavInstOpnd->value;
  664. }
  665. else {
  666. immedSize2 = size;
  667. immedValue2 = pavInstOpnd->value;
  668. }
  669. break;
  670. case typJmp:
  671. // compute displacment for byte offset instruction
  672. // and test if in range
  673. addrValue = pavInstOpnd->value - (addrAssem + 2);
  674. if (addrValue >= -0x80L && addrValue <= 0x7fL)
  675. addrSize = 1;
  676. else {
  677. // too large for byte, compute for word offset
  678. // and test again if in range
  679. // also allow for two-byte opcode 0f xx
  680. addrValue -= 1 + (preOpcode == 0x0f);
  681. if (!fDBit) {
  682. if (addrValue >= -0x8000L && addrValue <= 0x7fffL)
  683. addrSize = 2;
  684. else
  685. error(BADRANGE);
  686. }
  687. else {
  688. // recompute again for dword offset instruction
  689. addrValue -= 2;
  690. addrSize = 4;
  691. }
  692. }
  693. fOpndOvrd = FALSE; // operand size override is NOT set
  694. break;
  695. case typCtl:
  696. case typDbg:
  697. case typTrc:
  698. fModrm = TRUE;
  699. modModrm = 3;
  700. regModrm = pavInstOpnd->base;
  701. break;
  702. case typSti:
  703. postOpcode += pavInstOpnd->base;
  704. break;
  705. case typSeg:
  706. break;
  707. case typXsi:
  708. case typYdi:
  709. fAddrOvrd = (UCHAR)
  710. ((UCHAR)(pavInstOpnd->flags == fPTR32) != fDBit);
  711. break;
  712. case typOff:
  713. segOvrd = segToOvrdByte[pavInstOpnd->segovr];
  714. goto jumpAssem;
  715. case typAbs:
  716. fSegPtr = TRUE;
  717. segPtr = pavInstOpnd->segment;
  718. jumpAssem:
  719. addrValue = (LONG)pavInstOpnd->value;
  720. if (!fDBit)
  721. if (addrValue >= -0x8000L && addrValue <= 0xffffL)
  722. addrSize = 2;
  723. else
  724. error(OVERFLOW);
  725. else
  726. addrSize = 4;
  727. break;
  728. }
  729. }
  730. }
  731. UCHAR MatchOperand (PASM_VALUE pavOpnd, UCHAR tmplType)
  732. {
  733. UCHAR fMatch;
  734. // if immediate operand, set minimum unsigned size
  735. if (pavOpnd->flags == fIMM) {
  736. if ((LONG)pavOpnd->value >= -0x80L && (LONG)pavOpnd->value <= 0xffL)
  737. pavOpnd->size = sizeB;
  738. else if ((LONG)pavOpnd->value >= -0x8000L
  739. && (LONG)pavOpnd->value <= 0xffffL)
  740. pavOpnd->size = sizeW;
  741. else
  742. pavOpnd->size = sizeD;
  743. }
  744. // start matching of operands
  745. // compare the template and input operand types
  746. switch (tmplType) {
  747. case typAX:
  748. fMatch = (UCHAR)((pavOpnd->flags & fREG)
  749. && pavOpnd->index == regG && pavOpnd->base == indAX);
  750. break;
  751. case typCL:
  752. fMatch = (UCHAR)((pavOpnd->flags & fREG)
  753. && pavOpnd->index == regG && pavOpnd->size == sizeB
  754. && pavOpnd->base == indCX);
  755. break;
  756. case typDX:
  757. fMatch = (UCHAR)((pavOpnd->flags & fREG)
  758. && pavOpnd->index == regG && pavOpnd->size == sizeW
  759. && pavOpnd->base == indDX);
  760. break;
  761. case typAbs:
  762. fMatch = (UCHAR)(pavOpnd->flags & fFPTR);
  763. break;
  764. case typExp:
  765. fMatch = (UCHAR)((pavOpnd->flags == fREG
  766. && pavOpnd->index == regG)
  767. || (pavOpnd->flags == fIMM && pavOpnd->reloc == 1)
  768. || (pavOpnd->flags & (fPTR | fPTR16 | fPTR32)) != 0);
  769. break;
  770. case typGen:
  771. case typReg:
  772. fMatch = (UCHAR)(pavOpnd->flags == fREG
  773. && pavOpnd->index == regG);
  774. break;
  775. case typIm1:
  776. fMatch = (UCHAR)(pavOpnd->flags == fIMM && pavOpnd->value == 1);
  777. break;
  778. case typIm3:
  779. fMatch = (UCHAR)(pavOpnd->flags == fIMM && pavOpnd->value == 3);
  780. break;
  781. case typImm:
  782. fMatch = (UCHAR)(pavOpnd->flags == fIMM && pavOpnd->reloc == 0);
  783. break;
  784. case typJmp:
  785. fMatch = (UCHAR)(pavOpnd->flags == fIMM);
  786. break;
  787. case typMem:
  788. fMatch = (UCHAR)((pavOpnd->flags == fIMM && pavOpnd->reloc == 1)
  789. || ((pavOpnd->flags & (fPTR | fPTR16 | fPTR32)) != 0));
  790. break;
  791. case typCtl:
  792. fMatch = (UCHAR)(pavOpnd->flags == fREG
  793. && pavOpnd->index == regC);
  794. break;
  795. case typDbg:
  796. fMatch = (UCHAR)(pavOpnd->flags == fREG
  797. && pavOpnd->index == regD);
  798. break;
  799. case typTrc:
  800. fMatch = (UCHAR)(pavOpnd->flags == fREG
  801. && pavOpnd->index == regT);
  802. break;
  803. case typSt:
  804. fMatch = (UCHAR)(pavOpnd->flags == fREG
  805. && pavOpnd->index == regF);
  806. break;
  807. case typSti:
  808. fMatch = (UCHAR)(pavOpnd->flags == fREG
  809. && pavOpnd->index == regI);
  810. break;
  811. case typSeg:
  812. fMatch = (UCHAR)(pavOpnd->flags == fREG && pavOpnd->index == regS
  813. && pavOpnd->base == segIndex);
  814. break;
  815. case typSgr:
  816. fMatch = (UCHAR)(pavOpnd->flags == fREG
  817. && pavOpnd->index == regS);
  818. break;
  819. case typXsi:
  820. fMatch = (UCHAR)(((pavOpnd->flags == fPTR16 && pavOpnd->base == 4)
  821. || (pavOpnd->flags == fPTR32 && pavOpnd->base == indSI
  822. && pavOpnd->index == 0xff))
  823. && pavOpnd->value == 0
  824. && (pavOpnd->segovr == segX
  825. || pavOpnd->segovr == segDS));
  826. break;
  827. case typYdi:
  828. fMatch = (UCHAR)(((pavOpnd->flags == fPTR16 && pavOpnd->base == 5)
  829. || (pavOpnd->flags == fPTR32 && pavOpnd->base == indDI
  830. && pavOpnd->index == 0xff))
  831. && pavOpnd->value == 0
  832. && pavOpnd->segovr == segES);
  833. break;
  834. case typOff:
  835. fMatch = (UCHAR)((pavOpnd->flags == fIMM && pavOpnd->reloc == 1)
  836. || pavOpnd->flags == fPTR);
  837. break;
  838. default:
  839. fMatch = FALSE;
  840. break;
  841. }
  842. return fMatch;
  843. }
  844. void OutputInstr (void)
  845. {
  846. if (fWaitPrfx)
  847. *pchBin++ = 0x9b;
  848. if (fAddrOvrd)
  849. *pchBin++ = 0x67;
  850. if (fOpndOvrd)
  851. *pchBin++ = 0x66;
  852. if (segOvrd)
  853. *pchBin++ = segOvrd;
  854. if (preOpcode)
  855. *pchBin++ = preOpcode;
  856. *pchBin++ = inOpcode;
  857. if (postOpcode)
  858. *pchBin++ = postOpcode;
  859. if (fModrm)
  860. *pchBin++ = (UCHAR)((((modModrm << 3) + regModrm) << 3) + rmModrm);
  861. if (fSib)
  862. *pchBin++ = (UCHAR)((((scaleSib << 3) + indexSib) << 3) + baseSib);
  863. OutputValue(addrSize, (PUCHAR)&addrValue); // size = 0, 1, 2, 4
  864. OutputValue((UCHAR)(fSegPtr << 1), (PUCHAR)&segPtr); // size = 0, 2
  865. OutputValue(immedSize, (PUCHAR)&immedValue); // size = 0, 1, 2, 4
  866. OutputValue(immedSize2, (PUCHAR)&immedValue2); // size = 0, 1, 2, 4
  867. }
  868. void OutputValue (UCHAR size, PUCHAR pchValue)
  869. {
  870. while (size--)
  871. *pchBin++ = *pchValue++;
  872. }