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.

768 lines
21 KiB

  1. /* disasm.c
  2. Future Features -
  3. Current bugs -
  4. Data32 for
  5. (callf fword ptr [mem]), (jmpf fword ptr [mem])
  6. Floating point insns
  7. Call not tested
  8. jecxz disassembled as large_address, not large_data
  9. lidt/lgdt are 6-byte operands
  10. segload doesn't set memXxxxx vars
  11. some 0x0f opcodes should set gpSafe flag
  12. bt, bts, btr, btc
  13. SetBcc [mem]
  14. SHD[l,r]
  15. Usage:
  16. Call DisAsm86(code ptr)
  17. gpRegs = 0
  18. gpSafe = 0
  19. If we can continue,
  20. set gpSafe = 1
  21. if instruction is POP SEGREG
  22. gpRegs |= POPSEG
  23. else
  24. gpInsLen = length of instruction
  25. gpRegs |= regs modified (SegLoad or String)
  26. endif
  27. endif
  28. */
  29. /* #include <string.h> */
  30. #include <windows.h> /* wsprintf() */
  31. /* Disasm.h - definitions for Don's Tiny Disassembler */
  32. typedef unsigned long dword;
  33. typedef unsigned short word;
  34. typedef unsigned char byte;
  35. extern word memOp; /* actual operation performed */
  36. extern char *memName[]; /* name corresponding to memOp */
  37. enum { memNOP, memRead, memWrite, memRMW, memSegReg, memSegMem};
  38. extern word memSeg; /* value of segment of memory address */
  39. extern dword memLinear, /* offset of operand */
  40. memLinear2;
  41. extern word memSeg2, /* duplicate of above if dual mem op */
  42. memSize2, memOp2,
  43. memDouble; /* true if two-mem-operand instruction */
  44. extern word memSize; /* bytes of memory of operation */
  45. enum { MemByte=1, MemWord=2, MemDWord=4, MemQWord=8, MemTword=10,
  46. Adr4, Adr6=6};
  47. enum { memNoSeg, memES, memCS, memSS, memDS, memFS, memGS};
  48. enum {strCX=1, strSI=2, strDI=4, segDS=8, segES=16, segFS=32, segGS=64};
  49. extern word gpSafe, /* 1 if may continue instruction */
  50. gpRegs, /* regs which instruction modifies as side effect */
  51. gpStack; /* amount stack is changed by */
  52. #ifdef PM386
  53. #define SHERLOCK 1
  54. #else
  55. #define SHERLOCK 0
  56. #endif
  57. #if SHERLOCK
  58. #define STATIC /*static*/
  59. #ifdef WOW
  60. // Note: The functions in this file were moved to the _MISCTEXT code segment
  61. // because _TEXT was exceeding the 64K segment limit a-craigj
  62. STATIC void InitDisAsm86(void);
  63. STATIC byte GetByte(void);
  64. STATIC word GetWord(void);
  65. STATIC long GetDWord(void);
  66. STATIC int GetImmAdr(int w);
  67. STATIC int GetImmData(int w);
  68. void PopSeg(int seg);
  69. STATIC void ModRMGeneral(byte op);
  70. STATIC void F(void);
  71. STATIC void DisAsmF(void);
  72. int IsPrefix(byte op0);
  73. int FAR DisAsm86(byte far *codeParm);
  74. #pragma alloc_text(_MISCTEXT,DisAsm86)
  75. #pragma alloc_text(_MISCTEXT,IsPrefix)
  76. #pragma alloc_text(_MISCTEXT,DisAsmF)
  77. #pragma alloc_text(_MISCTEXT,F)
  78. #pragma alloc_text(_MISCTEXT,ModRMGeneral)
  79. #pragma alloc_text(_MISCTEXT,PopSeg)
  80. #pragma alloc_text(_MISCTEXT,GetImmData)
  81. #pragma alloc_text(_MISCTEXT,GetImmAdr)
  82. #pragma alloc_text(_MISCTEXT,GetDWord)
  83. #pragma alloc_text(_MISCTEXT,GetWord)
  84. #pragma alloc_text(_MISCTEXT,GetByte)
  85. #pragma alloc_text(_MISCTEXT,InitDisAsm86)
  86. #endif
  87. #define NO_MEM
  88. /* int gpTrying = 0, gpEnable = 1, gpInsLen = 0; */
  89. extern int gpTrying, gpEnable, gpInsLen;
  90. extern word gpSafe, gpRegs, gpStack; /* indicate side effects of instruction */
  91. STATIC byte lookup[256] = {0}; /* lookup table for first byte of opcode */
  92. STATIC int dataSize=0, adrSize=0, /* flag to indicate 32 bit data/code */
  93. segSize=0; /* flag if 32 bit code segment */
  94. enum { /* operand decoding classes */
  95. UNK, /*NOOP, BREG, VREG, SREG, */ BWI, /*BRI, WRI,*/
  96. SMOV, IMOV, /*IBYTE, IWORD, JMPW, JMPB, LEA, JCond,
  97. GrpF,*/ Grp1, Grp2, Grp3, Grp4, Grp5, /*IADR, */ MOVABS,
  98. RRM, RRMW, /*IMUL,*/ POPMEM, /*TEST, ENTER, FLOP, ARPL,
  99. INOUT, IWORD1, ASCII, */ XLAT,
  100. };
  101. #define opBase 0
  102. STATIC struct {
  103. /* char *name; /* opcode mnemonic */
  104. byte base, count; /* first table entry, number of entries */
  105. byte operand; /* operand class */
  106. } ops[] = {
  107. #define NoText(n, b, c, o) b, c, o
  108. NoText("?UNKNOWN", 0, 0, UNK),
  109. NoText("add", 0x00, 6, BWI),
  110. NoText("or", 0x08, 6, BWI),
  111. /* NoText("FGrp", 0x0f, 1, GrpF), */
  112. NoText("adc", 0x10, 6, BWI),
  113. NoText("sbb", 0x18, 6, BWI),
  114. NoText("and", 0x20, 6, BWI),
  115. NoText("sub", 0x28, 6, BWI),
  116. NoText("xor", 0x30, 6, BWI),
  117. NoText("cmp", 0x38, 6, BWI),
  118. /* NoText("inc", 0x40, 8, VREG), */
  119. /* "dec", 0x48, 8, VREG, */
  120. /* NoText("push", 0x50, 8, VREG), */
  121. /* "pop", 0x58, 8, VREG, */
  122. NoText("bound", 0x62, 1, RRMW),
  123. /* "arpl", 0x63, 1, ARPL, */
  124. /* NoText("push", 0x68, 1, IWORD), */
  125. /* "imul", 0x69, 3, IMUL, */
  126. /* NoText("push", 0x6a, 1, IBYTE), */
  127. /* "jcond", 0x70, 16, JCond, */
  128. NoText("Grp1", 0x80, 4, Grp1),
  129. NoText("test", 0x84, 2, RRM),
  130. NoText("xchg", 0x86, 2, RRM),
  131. NoText("mov", 0x88, 4, BWI),
  132. NoText("mov", 0x8c, 3, SMOV),
  133. /* NoText("lea", 0x8d, 1, LEA), */
  134. NoText("pop", 0x8f, 1, POPMEM),
  135. /* NoText("xchg", 0x90, 8, VREG), */
  136. /* NoText("callf", 0x9a, 1, IADR), */
  137. NoText("mov", 0xa0, 4, MOVABS),
  138. /* NoText("test", 0xa8, 2, TEST), */
  139. /* NoText("mov", 0xb0, 8, BRI), */
  140. /* NoText("mov", 0xb8, 8, WRI), */
  141. NoText("Grp2", 0xc0, 2, Grp2),
  142. /* NoText("retn", 0xc2, 1, IWORD1), */
  143. NoText("les", 0xc4, 1, RRMW),
  144. NoText("lds", 0xc5, 1, RRMW),
  145. NoText("mov", 0xc6, 2, IMOV),
  146. /* NoText("enter", 0xc8, 1, ENTER), */
  147. /* NoText("retf", 0xca, 1, IWORD1), */
  148. /* NoText("int", 0xcd, 1, IBYTE), */
  149. NoText("Grp2", 0xd0, 4, Grp2),
  150. /* NoText("aam", 0xd4, 1, ASCII), */
  151. /* NoText("aad", 0xd5, 1, ASCII), */
  152. NoText("xlat", 0xd7, 1, XLAT),
  153. /* NoText("float", 0xd8, 8, FLOP), */
  154. /* NoText("loopne", 0xe0, 1, JMPB), */
  155. /* NoText("loope", 0xe1, 1, JMPB), */
  156. /* NoText("loop", 0xe2, 1, JMPB), */
  157. /* NoText("jcxz", 0xe3, 1, JMPB), */
  158. /* NoText("in", 0xe4, 2, INOUT), */
  159. /* NoText("out", 0xe6, 2, INOUT), */
  160. /* NoText("call", 0xe8, 1, JMPW), */
  161. /* NoText("jmp", 0xe9, 1, JMPW), */
  162. /* NoText("jmpf", 0xea, 1, IADR), */
  163. /* NoText("jmp", 0xeb, 1, JMPB), */
  164. NoText("Grp3", 0xf6, 2, Grp3),
  165. NoText("Grp4", 0xfe, 1, Grp4),
  166. NoText("Grp5", 0xff, 1, Grp5),
  167. };
  168. #define opCnt (sizeof(ops)/sizeof(ops[0]))
  169. #define simpleBase (opBase + opCnt)
  170. STATIC struct { /* these are single byte opcodes, no decode */
  171. byte val;
  172. /* char *name; */
  173. } simple[] = {
  174. #define NoText2(v, n) v
  175. /* NoText2(0x06, "push es"), */
  176. NoText2(0x07, "pop es"),
  177. /* NoText2(0x0e, "push cs"), */
  178. /* NoText2(0x16, "push ss"), */
  179. /* NoText2(0x17, "pop ss"), */
  180. /* NoText2(0x1e, "push ds"), */
  181. NoText2(0x1f, "pop ds"),
  182. /* NoText2(0x27, "daa"), */
  183. /* NoText2(0x2f, "das"), */
  184. /* NoText2(0x37, "aaa"), */
  185. /* NoText2(0x3f, "aas"), */
  186. /* NoText2(0x90, "nop"), */
  187. /* NoText2(0x9b, "wait"), */
  188. /* NoText2(0x9e, "sahf"), */
  189. /* NoText2(0x9f, "lahf"), */
  190. /* NoText2(0xc3, "retn"), */
  191. /* NoText2(0xc9, "leave"), */
  192. /* NoText2(0xcb, "retf"), */
  193. /* NoText2(0xcc, "int 3"), */
  194. /* NoText2(0xce, "into"), */
  195. /* NoText2(0xec, "in al), dx", */
  196. /* NoText2(0xee, "out dx), al", */
  197. /* NoText2(0xf0, "lock"), */
  198. /* NoText2(0xf2, "repne"), */
  199. /* NoText2(0xf3, "rep/repe"), */
  200. /* NoText2(0xf4, "hlt"), */
  201. /* NoText2(0xf5, "cmc"), */
  202. /* NoText2(0xf8, "clc"), */
  203. /* NoText2(0xf9, "stc"), */
  204. /* NoText2(0xfa, "cli"), */
  205. /* NoText2(0xfb, "sti"), */
  206. /* NoText2(0xfc, "cld"), */
  207. /* NoText2(0xfd, "std"), */
  208. };
  209. #define simpleCnt (sizeof(simple)/sizeof(simple[0]))
  210. #define dSimpleBase (simpleBase + simpleCnt)
  211. #if 0
  212. STATIC struct { /* these are simple opcodes that change */
  213. byte val; /* based on current data size */
  214. char *name, *name32;
  215. } dsimple[] = {
  216. /* 0x60, "pusha", "pushad", */
  217. /* 0x61, "popa", "popad", */
  218. /* 0x98, "cbw", "cwde", */
  219. /* 0x99, "cwd", "cdq", */
  220. /* 0x9c, "pushf", "pushfd", */
  221. /* 0x9d, "popf", "popfd", */
  222. /* 0xcf, "iret", "iretd", */
  223. /* 0xed, "in ax, dx", "in eax, dx", */
  224. /* 0xef, "out dx, ax", "out dx, eax", */
  225. };
  226. #define dSimpleCnt (sizeof(dsimple)/sizeof(dsimple[0]))
  227. #endif
  228. #define dSimpleCnt 0
  229. #define STR_S 1 /* string op, source regs */
  230. #define STR_D 2 /* string op, dest regs */
  231. #define STR_D_Read 4 /* string op, reads from dest regs */
  232. #define STR_NO_COND 8 /* rep ignores flags */
  233. #define stringOpBase (dSimpleBase+ dSimpleCnt)
  234. STATIC struct {
  235. byte val;
  236. /* char *name; */
  237. byte flag; /* should be 'next' to op, to pack nicely */
  238. } stringOp[] = {
  239. #define NoText3(v, n, f) v, f
  240. NoText3(0x6c, "ins", STR_D | STR_NO_COND),
  241. NoText3(0x6e, "outs", STR_S | STR_NO_COND),
  242. NoText3(0xa4, "movs", STR_S | STR_D | STR_NO_COND),
  243. NoText3(0xa6, "cmps", STR_S | STR_D | STR_D_Read),
  244. NoText3(0xaa, "stos", STR_D | STR_NO_COND),
  245. NoText3(0xac, "lods", STR_S | STR_NO_COND),
  246. NoText3(0xae, "scas", STR_D | STR_D_Read),
  247. };
  248. #define stringOpCnt (sizeof(stringOp)/sizeof(stringOp[0]))
  249. STATIC void InitDisAsm86(void) {
  250. int i, j;
  251. for (i=0; i<opCnt; i++) { /* Init complex entries */
  252. for (j=0; j<(int)ops[i].count; j++)
  253. lookup[ops[i].base+j] = (byte)i + opBase;
  254. }
  255. for (i=0; i<simpleCnt; i++) /* Init simple entries */
  256. lookup[simple[i].val] = (byte)(i + simpleBase);
  257. for (i=0; i<stringOpCnt; i++) { /* Init string op table */
  258. lookup[stringOp[i].val] = (byte)(i + stringOpBase);
  259. lookup[stringOp[i].val+1] = (byte)(i + stringOpBase);
  260. }
  261. } /* InitDisAsm86 */
  262. STATIC byte far *code = 0; /* this is ugly - it saves passing current */
  263. /* code position to all the GetByte() funcs */
  264. #define Mid(v) (((v) >> 3) & 7) /* extract middle 3 bits from a byte */
  265. /* If you don't want to return memory access info, #def NO_MEM */
  266. #if !defined(NO_MEM)
  267. /* global vars set by DisAsm() to indicate current instruction's memory */
  268. /* access type. */
  269. word memSeg, memSize, memOp; /* segment value, operand size, operation */
  270. word memSeg2, memSize2, memOp2, /* instruction may have two memory accesses */
  271. memDouble;
  272. dword memLinear, memLinear2; /* offset from segment of access */
  273. STATIC dword memReg, memDisp; /* used to pass information from GetReg()... */
  274. char *memName[] = { /* used to convert 'enum memOp' to ascii */
  275. "NOP",
  276. "Read",
  277. "Write",
  278. "RMW",
  279. "MovStr",
  280. };
  281. #define SetMemSize(s) memSize = s
  282. #define SetMemSeg(s) memSeg = regs[s+9]
  283. #define SetMemOp(o) memOp = o
  284. #define SetMemLinear(l) memLinear = l
  285. #define SetMemSeg2(s) memSeg2 = regs[s+9]
  286. #define SetMemOp2(o) memOp2 = o
  287. #define SetMemLinear2(l) memLinear2 = l
  288. #define ModMemLinear(l) memLinear += l
  289. #define SetMemReg(r) memReg = r
  290. #define SetMemDisp(d) memDisp = d
  291. #define Read_RMW(o) ((o) ? memRead : memRMW)
  292. #else
  293. #define SetMemSeg(s)
  294. #define SetMemSize(s)
  295. #define StMemOp(o)
  296. #define SetMemLinear(l)
  297. #define SetMemSeg2(s)
  298. #define StMemOp2(o)
  299. #define SetMemLinear2(l)
  300. #define ModMemLinear(l)
  301. #define SetMemReg(r)
  302. #define SetMemDisp(d)
  303. #define Read_RMW(o) 0
  304. #endif
  305. /******************** Register Decode *******************************/
  306. /* These helper functions return char pointers to register names.
  307. They are safe to call multiple times, as the return values are not
  308. stored in a single buffer. The ?Reg() functions are passed a register
  309. number. They mask this with 7, so you can pass in the raw opcode.
  310. The ?Mid() functions extract the register field from e.g. a ModRM byte.
  311. The Vxxx() functions look at dataSize to choose between 16 and 32 bit
  312. registers. The Xxxx() functions look at the passed in W bit, and then
  313. the dataSize global, do decide between 8, 16, and 32 bit registers.
  314. */
  315. /************************* Opcode Fetch ***************************/
  316. /* GetByte(), GetWord(), and GetDWord() read from the code segment */
  317. /* and increment the pointer appropriately. They also add the current */
  318. /* value to the hexData display, and set the MemDisp global in case the */
  319. /* value fetched was a memory displacement */
  320. STATIC byte GetByte(void) { /* Read one byte from code segment */
  321. return *code++;
  322. } /* GetByte */
  323. STATIC word GetWord(void) { /* Read two bytes from code seg */
  324. word w = *(word far *)code;
  325. code += 2;
  326. return w;
  327. } /* GetWord */
  328. STATIC long GetDWord(void) { /* Read four bytes from code seg */
  329. unsigned long l = *(long far *)code;
  330. code += 4;
  331. return l;
  332. } /* GetDWord */
  333. #define GetImmByte() GetByte()
  334. #define GetImmWord() GetWord()
  335. #define GetImmDWord() GetDWord()
  336. STATIC int GetImmAdr(int w) { /* Get an immediate address value */
  337. if (!w) return GetImmByte();
  338. else if (!adrSize) return GetImmWord();
  339. return (int)GetImmDWord();
  340. } /* GetImmAdr */
  341. STATIC int GetImmData(int w) { /* Get an immediate data value */
  342. if (!w) return GetImmByte();
  343. else if (!dataSize) return GetImmWord();
  344. return (int)GetImmDWord();
  345. } /* GetImmData */
  346. /************************* Helper Functions **************************/
  347. void PopSeg(int seg) {
  348. gpSafe = 1;
  349. gpRegs = seg;
  350. gpStack = 1;
  351. } /* PopSeg */
  352. enum {
  353. RegAX, RegCX, RegDX, RegBX, RegSP, RegBP, RegSI, RegDI
  354. };
  355. /* Based on the second byte of opcode, width flag, adrSize and dataSize, */
  356. /* determine the disassembly of the current instruction, and what */
  357. /* memory address was referenced */
  358. /* needinfo indicates that we need a size override on a memory operand */
  359. /* for example, "mov [bx], ax" is obviously a 16 bit move, while */
  360. /* "mov [bx], 0" could be 8, 16, or 32 bit. We add the proper */
  361. /* "mov word ptr [bx], 0" information. */
  362. /* The 'mem' parameter indicates the kind of operation, Read, Write, RMW */
  363. /* don't bother trying to understand this code without an Intel manual */
  364. /* and assembler nearby. :-) */
  365. STATIC void ModRMGeneral(byte op) {
  366. int mod = op >> 6;
  367. int rm = op & 7;
  368. if (adrSize) { /* do 32 bit addressing */
  369. if (mod == 3) return; /*XReg(w, rm); /* register operand */
  370. if (rm == 4) /* [esp+?] is special S-I-B style */
  371. GetByte();
  372. if (mod==1) GetImmAdr(0);
  373. else if (mod == 2) GetImmAdr(1);
  374. } else { /* do 16 bit addressing */
  375. if (mod == 3) return;/* XReg(w, rm); /* register operand */
  376. if (mod == 0 && rm == 6) /* [bp] becomes [mem16] */
  377. GetImmAdr(1);
  378. else if (mod) /* (mod3 already returned) */
  379. GetImmAdr(mod-1); /* mod==1 is byte, mod==2 is (d)word */
  380. }
  381. } /* ModRMGeneral */
  382. #define ModRMInfo(op, w, mem) ModRMGeneral(op)
  383. #define ModRM(op, w, mem) ModRMGeneral(op)
  384. STATIC void F(void) {
  385. ModRMGeneral(GetByte());
  386. gpSafe = 1;
  387. } /* F */
  388. #define ModRMF(m) F()
  389. /* Disassemble the 386 instructions whose first opcode is 0x0f */
  390. /* Sorry, but this is just too ugly to comment */
  391. STATIC void DisAsmF(void) {
  392. byte op0;
  393. op0 = GetByte();
  394. switch (op0 >> 4) { /* switch on top 4 bits of opcode */
  395. case 0:
  396. #if 0
  397. switch (op0 & 0xf) {
  398. case 0: /* grp6 - scary */
  399. case 1: /* grp7 - scary */
  400. case 2: /* lar */
  401. case 3: /* lsl */
  402. default:
  403. }
  404. #endif
  405. break;
  406. case 9: /* byte set on condition */
  407. ModRMF(memWrite);
  408. return;
  409. case 0xa:
  410. switch (op0 & 0xf) {
  411. case 0: return; /* "push fs"; */
  412. case 1:
  413. PopSeg(segFS);
  414. return; /* "pop fs"; */
  415. case 3: case 0xb: /* bts, bt */
  416. ModRMF(memRMW);
  417. return;
  418. case 4: case 0xc: /* shrd, shld */
  419. ModRMF(memRMW);
  420. GetImmData(0);
  421. return;
  422. case 5: case 0xd: /* shrd, shld */
  423. ModRMF(memRMW);
  424. return;
  425. case 6: /* cmpxchg */
  426. gpSafe = 1;
  427. ModRM(GetByte(), 0, memRMW);
  428. return;
  429. case 7: /* cmpxchg */
  430. ModRMF(memRMW);
  431. return;
  432. case 8: return; /*"push gs";*/
  433. case 9:
  434. PopSeg(segGS);
  435. return; /*"pop gs";*/
  436. case 0xf: /* imul */
  437. ModRMF(memRead);
  438. return;
  439. }
  440. break;
  441. case 0xb:
  442. switch (op0 & 0xf) {
  443. case 2: case 4: case 5:
  444. if (op0 & 2) {
  445. /* "lss"*/
  446. } else { /* : (op0 &1) ? "lgs" : "lfs"; */
  447. ModRMF(memRead);
  448. }
  449. return;
  450. case 3: case 0xb: /* btc, btr */
  451. ModRMF(memRMW);
  452. return;
  453. case 6: case 7: case 0xe: case 0xf: /* movsx, movzx */
  454. dataSize = 0;
  455. ModRMF(memRead);
  456. return;
  457. case 0xa:
  458. ModRMF(memRMW);
  459. GetImmData(0);
  460. return;
  461. case 0xc: case 0xd: /* bsr, bsf */
  462. ModRMF(memRead);
  463. return;
  464. }
  465. break;
  466. case 0xc:
  467. if (op0 > 0xc7) { /* bswap */
  468. return;
  469. }
  470. if (op0 < 0xc2) { /* xadd */
  471. ModRMF(memRMW);
  472. return;
  473. }
  474. break;
  475. default:
  476. break;
  477. }
  478. return;
  479. } /* DisAsmF */
  480. int IsPrefix(byte op0) {
  481. switch (op0) { /* check for prefix bytes */
  482. #define CSEG 0x2e
  483. #define DSEG 0x3e
  484. #define ESEG 0x26
  485. #define SSEG 0x36
  486. #define FSEG 0x64
  487. #define GSEG 0x65
  488. #define REP 0xf3
  489. #define REPNE 0xf2
  490. #define DATA32 0x66
  491. #define ADR32 0x67
  492. case CSEG: SetMemSeg(memCS); break;
  493. case DSEG: SetMemSeg(memDS); break;
  494. case ESEG: SetMemSeg(memES); break;
  495. case SSEG: SetMemSeg(memSS); break;
  496. case FSEG: SetMemSeg(memFS); break;
  497. case GSEG: SetMemSeg(memGS); break;
  498. case REP: gpRegs |= strCX; break;
  499. case REPNE: gpRegs |= strCX; break;
  500. case ADR32: adrSize = !adrSize; break;
  501. case DATA32:dataSize = !dataSize; break;
  502. default:
  503. return 0;
  504. }
  505. return 1;
  506. } /* IsPrefix */
  507. /* like, call this with a pointer to the instruction, it will return */
  508. /* the opcode bytes used in *len, and a pointer to the disassembled insn */
  509. int FAR DisAsm86(byte far *codeParm) {
  510. byte far *oldcode;
  511. byte op0, op1;
  512. byte opclass;
  513. static int init =0;
  514. if (!init) {
  515. InitDisAsm86();
  516. init = 1;
  517. }
  518. adrSize = dataSize = segSize;
  519. gpSafe = gpRegs = gpStack = 0;
  520. code = oldcode = codeParm;
  521. do {
  522. op0 = GetByte();
  523. } while (IsPrefix(op0));
  524. opclass = lookup[op0];
  525. StMemOp(memNOP);
  526. if (opclass >= simpleBase) { /* is it special */
  527. if (opclass >= stringOpBase) { /* string operations? */
  528. char cmd;
  529. opclass -= stringOpBase;
  530. cmd = stringOp[opclass].flag;
  531. if (cmd & STR_S) {
  532. gpRegs |= strSI;
  533. StMemOp(memRead);
  534. /* DS already set */
  535. SetMemLinear(memReg);
  536. if (cmd & STR_D) {
  537. gpRegs |= strDI;
  538. StMemOp2(cmd & STR_D_Read ? memRead : memWrite);
  539. SetMemSeg2(memES);
  540. SetMemLinear2(memReg);
  541. /* memDouble = 1; */
  542. }
  543. } else {
  544. gpRegs |= strDI;
  545. StMemOp(cmd & STR_D_Read ? memRead : memWrite);
  546. SetMemSeg(memES);
  547. SetMemLinear(memReg);
  548. }
  549. if (op0 & 1) {
  550. if (dataSize) SetMemSize(4);
  551. else SetMemSize(2);
  552. } else SetMemSize(1);
  553. } else if (opclass >= dSimpleBase) {
  554. opclass -= dSimpleBase;
  555. } else {
  556. if (op0 == 7)
  557. PopSeg(segES); /* pop ES */
  558. else if (op0 == 0x1f)
  559. PopSeg(segDS); /* pop DS */
  560. }
  561. goto DisAsmDone;
  562. }
  563. if (op0 == 0x0f) { /* is it an extended opcode? */
  564. DisAsmF();
  565. goto DisAsmDone;
  566. }
  567. switch (ops[opclass].operand) {
  568. case BWI: /* byte/word/immediate */
  569. gpSafe = 1;
  570. if (op0 & 4) {
  571. GetImmData(op0&1);
  572. } else {
  573. int i;
  574. op1 = GetByte();
  575. /* if ((op0 & 0xf8) == 0x38) i = memRead;
  576. else if ((op0 & 0xfe) == 0x88) i = memWrite;
  577. else Read_RMW(op0 & 2); */
  578. ModRM(op1, op0&1, i);
  579. }
  580. break;
  581. case Grp1: /* group 1 instructions */
  582. gpSafe = 1;
  583. op1 = GetByte();
  584. ModRMInfo(op1, op0&1, Mid(op1) == 7 ? memRead : memRMW);
  585. GetImmData((op0&3)==1);
  586. break;
  587. case Grp2: /* group 2 instructions */
  588. gpSafe = 1;
  589. op1 = GetByte();
  590. ModRMInfo(op1, op0&1, memRMW);
  591. if (!(op0 & 0x10)) GetImmData(0);
  592. break;
  593. case Grp3: /* group 3 instructions */
  594. gpSafe = 1;
  595. op1 = GetByte();
  596. ModRMInfo(op1, op0&1, Read_RMW(Mid(op1) <2 || Mid(op1) >3));
  597. if (Mid(op1) < 2) GetImmData(op0&1);
  598. break;
  599. case Grp4: /* group 4 instructions */
  600. op1 = GetByte();
  601. if (Mid(op1) > 1) ;
  602. else {
  603. ModRMInfo(op1, op0&1, memRMW);
  604. gpSafe = 1;
  605. }
  606. break;
  607. case Grp5: /* group 5 instructions */
  608. op1 = GetByte();
  609. if (Mid(op1) < 3) {
  610. gpSafe = 1;
  611. if (Mid(op1) == 2) {
  612. gpStack = -1 << dataSize;
  613. }
  614. }
  615. ModRMInfo(op1, op0&1, Read_RMW(Mid(op1) >= 2));
  616. break;
  617. case SMOV: /* segment move */
  618. gpSafe = 1;
  619. op1 = GetByte();
  620. dataSize = 0;
  621. ModRM(op1, 1, Read_RMW(op0&2));
  622. if (op0 & 2) { /* if moving _to_ SREG */
  623. switch (Mid(op1)) {
  624. case 0: gpRegs = segES; break;
  625. case 3: gpRegs = segDS; break;
  626. case 4: gpRegs = segFS; break;
  627. case 5: gpRegs = segGS; break;
  628. default: gpSafe = 0;
  629. }
  630. }
  631. break;
  632. case IMOV: /* immediate move to reg/mem */
  633. gpSafe = 1;
  634. op1 = GetByte();
  635. ModRMInfo(op1, op0&1, memWrite);
  636. GetImmData(op0&1);
  637. break;
  638. case MOVABS: /* move between accum and abs mem address */
  639. gpSafe = 1;
  640. GetImmAdr(1);
  641. StMemOp(op0&2 ? memWrite : memRead);
  642. break;
  643. case POPMEM:
  644. gpSafe = 1;
  645. gpStack = 1 << dataSize;
  646. ModRMInfo(GetByte(), 1, memWrite);
  647. break;
  648. case RRM: /* test and xchg */
  649. gpSafe = 1;
  650. op1 = GetByte();
  651. ModRM(op1, op0&1, memRMW);
  652. break;
  653. case RRMW: /* bound, les, lds */
  654. op1 = GetByte();
  655. switch (op0) {
  656. case 0xc4: /* les reg, [mem] */
  657. gpRegs = segES;
  658. gpSafe = 1;
  659. break;
  660. case 0xc5: /* lds reg, [mem] */
  661. gpRegs = segDS;
  662. gpSafe = 1;
  663. break;
  664. }
  665. ModRM(op1, 1, memRead);
  666. break;
  667. case XLAT:
  668. gpSafe = 1;
  669. StMemOp(memRead);
  670. break;
  671. default: ;
  672. }
  673. DisAsmDone:
  674. return (int)(code - oldcode);
  675. } /* DisAsm86 */
  676. #endif /* SHERLOCK */