Leaked source code of windows server 2003
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.

1110 lines
38 KiB

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