ia32_implicit.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. #include <stdlib.h>
  2. #include "libdis.h"
  3. #include "ia32_implicit.h"
  4. #include "ia32_insn.h"
  5. #include "ia32_reg.h"
  6. #include "x86_operand_list.h"
  7. /* Conventions: Register operands which are aliases of another register
  8. * operand (e.g. AX in one operand and AL in another) assume that the
  9. * operands are different registers and that alias tracking will resolve
  10. * data flow. This means that something like
  11. * mov ax, al
  12. * would have 'write only' access for AX and 'read only' access for AL,
  13. * even though both AL and AX are read and written */
  14. typedef struct {
  15. uint32_t type;
  16. uint32_t operand;
  17. } op_implicit_list_t;
  18. static op_implicit_list_t list_aaa[] =
  19. /* 37 : AAA : rw AL */
  20. /* 3F : AAS : rw AL */
  21. {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0,0}}; /* aaa */
  22. static op_implicit_list_t list_aad[] =
  23. /* D5 0A, D5 (ib) : AAD : rw AX */
  24. /* D4 0A, D4 (ib) : AAM : rw AX */
  25. {{ OP_R | OP_W, REG_WORD_OFFSET }, {0,0}}; /* aad */
  26. static op_implicit_list_t list_call[] =
  27. /* E8, FF, 9A, FF : CALL : rw ESP, rw EIP */
  28. /* C2, C3, CA, CB : RET : rw ESP, rw EIP */
  29. {{ OP_R | OP_W, REG_EIP_INDEX },
  30. { OP_R | OP_W, REG_ESP_INDEX }, {0,0}}; /* call, ret */
  31. static op_implicit_list_t list_cbw[] =
  32. /* 98 : CBW : r AL, rw AX */
  33. {{ OP_R | OP_W, REG_WORD_OFFSET },
  34. { OP_R, REG_BYTE_OFFSET}, {0,0}}; /* cbw */
  35. static op_implicit_list_t list_cwde[] =
  36. /* 98 : CWDE : r AX, rw EAX */
  37. {{ OP_R | OP_W, REG_DWORD_OFFSET },
  38. { OP_R, REG_WORD_OFFSET }, {0,0}}; /* cwde */
  39. static op_implicit_list_t list_clts[] =
  40. /* 0F 06 : CLTS : rw CR0 */
  41. {{ OP_R | OP_W, REG_CTRL_OFFSET}, {0,0}}; /* clts */
  42. static op_implicit_list_t list_cmpxchg[] =
  43. /* 0F B0 : CMPXCHG : rw AL */
  44. {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0,0}}; /* cmpxchg */
  45. static op_implicit_list_t list_cmpxchgb[] =
  46. /* 0F B1 : CMPXCHG : rw EAX */
  47. {{ OP_R | OP_W, REG_DWORD_OFFSET }, {0,0}}; /* cmpxchg */
  48. static op_implicit_list_t list_cmpxchg8b[] =
  49. /* 0F C7 : CMPXCHG8B : rw EDX, rw EAX, r ECX, r EBX */
  50. {{ OP_R | OP_W, REG_DWORD_OFFSET },
  51. { OP_R | OP_W, REG_DWORD_OFFSET + 2 },
  52. { OP_R, REG_DWORD_OFFSET + 1 },
  53. { OP_R, REG_DWORD_OFFSET + 3 }, {0,0}}; /* cmpxchg8b */
  54. static op_implicit_list_t list_cpuid[] =
  55. /* 0F A2 : CPUID : rw EAX, w EBX, w ECX, w EDX */
  56. {{ OP_R | OP_W, REG_DWORD_OFFSET },
  57. { OP_W, REG_DWORD_OFFSET + 1 },
  58. { OP_W, REG_DWORD_OFFSET + 2 },
  59. { OP_W, REG_DWORD_OFFSET + 3 }, {0,0}}; /* cpuid */
  60. static op_implicit_list_t list_cwd[] =
  61. /* 99 : CWD/CWQ : rw EAX, w EDX */
  62. {{ OP_R | OP_W, REG_DWORD_OFFSET },
  63. { OP_W, REG_DWORD_OFFSET + 2 }, {0,0}}; /* cwd */
  64. static op_implicit_list_t list_daa[] =
  65. /* 27 : DAA : rw AL */
  66. /* 2F : DAS : rw AL */
  67. {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0,0}}; /* daa */
  68. static op_implicit_list_t list_idiv[] =
  69. /* F6 : DIV, IDIV : r AX, w AL, w AH */
  70. /* FIXED: first op was EAX, not Aw. TODO: verify! */
  71. {{ OP_R, REG_WORD_OFFSET },
  72. { OP_W, REG_BYTE_OFFSET },
  73. { OP_W, REG_BYTE_OFFSET + 4 }, {0,0}}; /* div */
  74. static op_implicit_list_t list_div[] =
  75. /* F7 : DIV, IDIV : rw EDX, rw EAX */
  76. {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 },
  77. { OP_R | OP_W, REG_DWORD_OFFSET }, {0,0}}; /* div */
  78. static op_implicit_list_t list_enter[] =
  79. /* C8 : ENTER : rw ESP w EBP */
  80. {{ OP_R | OP_W, REG_DWORD_OFFSET + 4 },
  81. { OP_R, REG_DWORD_OFFSET + 5 }, {0,0}}; /* enter */
  82. static op_implicit_list_t list_f2xm1[] =
  83. /* D9 F0 : F2XM1 : rw ST(0) */
  84. /* D9 E1 : FABS : rw ST(0) */
  85. /* D9 E0 : FCHS : rw ST(0) */
  86. /* D9 FF : FCOS : rw ST(0)*/
  87. /* D8, DA : FDIV : rw ST(0) */
  88. /* D8, DA : FDIVR : rw ST(0) */
  89. /* D9 F2 : FPTAN : rw ST(0) */
  90. /* D9 FC : FRNDINT : rw ST(0) */
  91. /* D9 FB : FSINCOS : rw ST(0) */
  92. /* D9 FE : FSIN : rw ST(0) */
  93. /* D9 FA : FSQRT : rw ST(0) */
  94. /* D9 F4 : FXTRACT : rw ST(0) */
  95. {{ OP_R | OP_W, REG_FPU_OFFSET }, {0,0}}; /* f2xm1 */
  96. static op_implicit_list_t list_fcom[] =
  97. /* D8, DC, DE D9 : FCOM : r ST(0) */
  98. /* DE, DA : FICOM : r ST(0) */
  99. /* DF, D8 : FIST : r ST(0) */
  100. /* D9 E4 : FTST : r ST(0) */
  101. /* D9 E5 : FXAM : r ST(0) */
  102. {{ OP_R, REG_FPU_OFFSET }, {0,0}}; /* fcom */
  103. static op_implicit_list_t list_fpatan[] =
  104. /* D9 F3 : FPATAN : r ST(0), rw ST(1) */
  105. {{ OP_R, REG_FPU_OFFSET }, {0,0}}; /* fpatan */
  106. static op_implicit_list_t list_fprem[] =
  107. /* D9 F8, D9 F5 : FPREM : rw ST(0) r ST(1) */
  108. /* D9 FD : FSCALE : rw ST(0), r ST(1) */
  109. {{ OP_R | OP_W, REG_FPU_OFFSET },
  110. { OP_R, REG_FPU_OFFSET + 1 }, {0,0}}; /* fprem */
  111. static op_implicit_list_t list_faddp[] =
  112. /* DE C1 : FADDP : r ST(0), rw ST(1) */
  113. /* DE E9 : FSUBP : r ST(0), rw ST(1) */
  114. /* D9 F1 : FYL2X : r ST(0), rw ST(1) */
  115. /* D9 F9 : FYL2XP1 : r ST(0), rw ST(1) */
  116. {{ OP_R, REG_FPU_OFFSET },
  117. { OP_R | OP_W, REG_FPU_OFFSET + 1 }, {0,0}}; /* faddp */
  118. static op_implicit_list_t list_fucompp[] =
  119. /* DA E9 : FUCOMPP : r ST(0), r ST(1) */
  120. {{ OP_R, REG_FPU_OFFSET },
  121. { OP_R, REG_FPU_OFFSET + 1 }, {0,0}}; /* fucompp */
  122. static op_implicit_list_t list_imul[] =
  123. /* F6 : IMUL : r AL, w AX */
  124. /* F6 : MUL : r AL, w AX */
  125. {{ OP_R, REG_BYTE_OFFSET },
  126. { OP_W, REG_WORD_OFFSET }, {0,0}}; /* imul */
  127. static op_implicit_list_t list_mul[] =
  128. /* F7 : IMUL : rw EAX, w EDX */
  129. /* F7 : MUL : rw EAX, w EDX */
  130. {{ OP_R | OP_W, REG_DWORD_OFFSET },
  131. { OP_W, REG_DWORD_OFFSET + 2 }, {0,0}}; /* imul */
  132. static op_implicit_list_t list_lahf[] =
  133. /* 9F : LAHF : r EFLAGS, w AH */
  134. {{ OP_R, REG_FLAGS_INDEX },
  135. { OP_W, REG_BYTE_OFFSET + 4 }, {0,0}}; /* lahf */
  136. static op_implicit_list_t list_ldmxcsr[] =
  137. /* 0F AE : LDMXCSR : w MXCSR SSE Control Status Reg */
  138. {{ OP_W, REG_MXCSG_INDEX }, {0,0}}; /* ldmxcsr */
  139. static op_implicit_list_t list_leave[] =
  140. /* C9 : LEAVE : rw ESP, w EBP */
  141. {{ OP_R | OP_W, REG_ESP_INDEX },
  142. { OP_W, REG_DWORD_OFFSET + 5 }, {0,0}}; /* leave */
  143. static op_implicit_list_t list_lgdt[] =
  144. /* 0F 01 : LGDT : w GDTR */
  145. {{ OP_W, REG_GDTR_INDEX }, {0,0}}; /* lgdt */
  146. static op_implicit_list_t list_lidt[] =
  147. /* 0F 01 : LIDT : w IDTR */
  148. {{ OP_W, REG_IDTR_INDEX }, {0,0}}; /* lidt */
  149. static op_implicit_list_t list_lldt[] =
  150. /* 0F 00 : LLDT : w LDTR */
  151. {{ OP_W, REG_LDTR_INDEX }, {0,0}}; /* lldt */
  152. static op_implicit_list_t list_lmsw[] =
  153. /* 0F 01 : LMSW : w CR0 */
  154. {{ OP_W, REG_CTRL_OFFSET }, {0,0}}; /* lmsw */
  155. static op_implicit_list_t list_loop[] =
  156. /* E0, E1, E2 : LOOP : rw ECX */
  157. {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0,0}};/* loop */
  158. static op_implicit_list_t list_ltr[] =
  159. /* 0F 00 : LTR : w Task Register */
  160. {{ OP_W, REG_TR_INDEX }, {0,0}}; /* ltr */
  161. static op_implicit_list_t list_pop[] =
  162. /* 8F, 58, 1F, 07, 17, 0F A1, 0F A9 : POP : rw ESP */
  163. /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */
  164. {{ OP_R | OP_W, REG_ESP_INDEX }, {0,0}}; /* pop, push */
  165. static op_implicit_list_t list_popad[] =
  166. /* 61 : POPAD : rw esp, w edi esi ebp ebx edx ecx eax */
  167. {{ OP_R | OP_W, REG_ESP_INDEX },
  168. { OP_W, REG_DWORD_OFFSET + 7 },
  169. { OP_W, REG_DWORD_OFFSET + 6 },
  170. { OP_W, REG_DWORD_OFFSET + 5 },
  171. { OP_W, REG_DWORD_OFFSET + 3 },
  172. { OP_W, REG_DWORD_OFFSET + 2 },
  173. { OP_W, REG_DWORD_OFFSET + 1 },
  174. { OP_W, REG_DWORD_OFFSET }, {0,0}}; /* popad */
  175. static op_implicit_list_t list_popfd[] =
  176. /* 9D : POPFD : rw esp, w eflags */
  177. {{ OP_R | OP_W, REG_ESP_INDEX },
  178. { OP_W, REG_FLAGS_INDEX }, {0,0}}; /* popfd */
  179. static op_implicit_list_t list_pushad[] =
  180. /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */
  181. /* 60 : PUSHAD : rw esp, r eax ecx edx ebx esp ebp esi edi */
  182. {{ OP_R | OP_W, REG_ESP_INDEX },
  183. { OP_R, REG_DWORD_OFFSET },
  184. { OP_R, REG_DWORD_OFFSET + 1 },
  185. { OP_R, REG_DWORD_OFFSET + 2 },
  186. { OP_R, REG_DWORD_OFFSET + 3 },
  187. { OP_R, REG_DWORD_OFFSET + 5 },
  188. { OP_R, REG_DWORD_OFFSET + 6 },
  189. { OP_R, REG_DWORD_OFFSET + 7 }, {0,0}}; /* pushad */
  190. static op_implicit_list_t list_pushfd[] =
  191. /* 9C : PUSHFD : rw esp, r eflags */
  192. {{ OP_R | OP_W, REG_ESP_INDEX },
  193. { OP_R, REG_FLAGS_INDEX }, {0,0}}; /* pushfd */
  194. static op_implicit_list_t list_rdmsr[] =
  195. /* 0F 32 : RDMSR : r ECX, w EDX, w EAX */
  196. {{ OP_R, REG_DWORD_OFFSET + 1 },
  197. { OP_W, REG_DWORD_OFFSET + 2 },
  198. { OP_W, REG_DWORD_OFFSET }, {0,0}}; /* rdmsr */
  199. static op_implicit_list_t list_rdpmc[] =
  200. /* 0F 33 : RDPMC : r ECX, w EDX, w EAX */
  201. {{ OP_R, REG_DWORD_OFFSET + 1 },
  202. { OP_W, REG_DWORD_OFFSET + 2 },
  203. { OP_W, REG_DWORD_OFFSET }, {0,0}}; /* rdpmc */
  204. static op_implicit_list_t list_rdtsc[] =
  205. /* 0F 31 : RDTSC : rw EDX, rw EAX */
  206. {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 },
  207. { OP_R | OP_W, REG_DWORD_OFFSET }, {0,0}}; /* rdtsc */
  208. static op_implicit_list_t list_rep[] =
  209. /* F3, F2 ... : REP : rw ECX */
  210. {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0,0}};/* rep */
  211. static op_implicit_list_t list_rsm[] =
  212. /* 0F AA : RSM : r CR4, r CR0 */
  213. {{ OP_R, REG_CTRL_OFFSET + 4 },
  214. { OP_R, REG_CTRL_OFFSET }, {0,0}}; /* rsm */
  215. static op_implicit_list_t list_sahf[] =
  216. /* 9E : SAHF : r ah, rw eflags (set SF ZF AF PF CF) */
  217. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* sahf */
  218. static op_implicit_list_t list_sgdt[] =
  219. /* 0F : SGDT : r gdtr */
  220. /* TODO: finish this! */
  221. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* sgdt */
  222. static op_implicit_list_t list_sidt[] =
  223. /* 0F : SIDT : r idtr */
  224. /* TODO: finish this! */
  225. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* sidt */
  226. static op_implicit_list_t list_sldt[] =
  227. /* 0F : SLDT : r ldtr */
  228. /* TODO: finish this! */
  229. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* sldt */
  230. static op_implicit_list_t list_smsw[] =
  231. /* 0F : SMSW : r CR0 */
  232. /* TODO: finish this! */
  233. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* smsw */
  234. static op_implicit_list_t list_stmxcsr[] =
  235. /* 0F AE : STMXCSR : r MXCSR */
  236. /* TODO: finish this! */
  237. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* stmxcsr */
  238. static op_implicit_list_t list_str[] =
  239. /* 0F 00 : STR : r TR (task register) */
  240. /* TODO: finish this! */
  241. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* str */
  242. static op_implicit_list_t list_sysenter[] =
  243. /* 0F 34 : SYSENTER : w cs, w eip, w ss, w esp, r CR0, w eflags
  244. * r sysenter_cs_msr, sysenter_esp_msr, sysenter_eip_msr */
  245. /* TODO: finish this! */
  246. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* sysenter */
  247. static op_implicit_list_t list_sysexit[] =
  248. /* 0F 35 : SYSEXIT : r edx, r ecx, w cs, w eip, w ss, w esp
  249. * r sysenter_cs_msr */
  250. /* TODO: finish this! */
  251. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* sysexit */
  252. static op_implicit_list_t list_wrmsr[] =
  253. /* 0F 30 : WRMST : r edx, r eax, r ecx */
  254. /* TODO: finish this! */
  255. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* wrmsr */
  256. static op_implicit_list_t list_xlat[] =
  257. /* D7 : XLAT : rw al r ebx (ptr) */
  258. /* TODO: finish this! */
  259. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* xlat */
  260. /* TODO:
  261. * monitor 0f 01 c8 eax OP_R ecx OP_R edx OP_R
  262. * mwait 0f 01 c9 eax OP_R ecx OP_R
  263. */
  264. static op_implicit_list_t list_monitor[] =
  265. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* monitor */
  266. static op_implicit_list_t list_mwait[] =
  267. {{ OP_R, REG_DWORD_OFFSET }, {0,0}}; /* mwait */
  268. op_implicit_list_t *op_implicit_list[] = {
  269. /* This is a list of implicit operands which are read/written by
  270. * various x86 instructions. Note that modifications to the stack
  271. * register are mentioned here, but that additional information on
  272. * the effect an instruction has on the stack is contained in the
  273. * x86_insn_t 'stack_mod' and 'stack_mod_val' fields. Use of the
  274. * eflags register, i.e. setting, clearing, and testing flags, is
  275. * not recorded here but rather in the flags_set and flags_tested
  276. * fields of the x86_insn_t.*/
  277. NULL,
  278. list_aaa, list_aad, list_call, list_cbw, /* 1 - 4 */
  279. list_cwde, list_clts, list_cmpxchg, list_cmpxchgb, /* 5 - 8 */
  280. list_cmpxchg8b, list_cpuid, list_cwd, list_daa, /* 9 - 12 */
  281. list_idiv, list_div, list_enter, list_f2xm1, /* 13 - 16 */
  282. list_fcom, list_fpatan, list_fprem, list_faddp, /* 17 - 20 */
  283. list_fucompp, list_imul, list_mul, list_lahf, /* 21 - 24 */
  284. list_ldmxcsr, list_leave, list_lgdt, list_lidt, /* 25 - 28 */
  285. list_lldt, list_lmsw, list_loop, list_ltr, /* 29 - 32 */
  286. list_pop, list_popad, list_popfd, list_pushad, /* 33 - 36 */
  287. list_pushfd, list_rdmsr, list_rdpmc, list_rdtsc, /* 37 - 40 */
  288. /* NOTE: 'REP' is a hack since it is a prefix: if its position
  289. * in the table changes, then change IDX_IMPLICIT_REP in the .h */
  290. list_rep, list_rsm, list_sahf, list_sgdt, /* 41 - 44 */
  291. list_sidt, list_sldt, list_smsw, list_stmxcsr, /* 45 - 48 */
  292. list_str, list_sysenter, list_sysexit, list_wrmsr, /* 49 - 52 */
  293. list_xlat, list_monitor, list_mwait, /* 53 - 55*/
  294. NULL /* end of list */
  295. };
  296. #define LAST_IMPL_IDX 55
  297. static void handle_impl_reg( x86_op_t *op, uint32_t val ) {
  298. x86_reg_t *reg = &op->data.reg;
  299. op->type = op_register;
  300. ia32_handle_register( reg, (unsigned int) val );
  301. switch (reg->size) {
  302. case 1:
  303. op->datatype = op_byte; break;
  304. case 2:
  305. op->datatype = op_word; break;
  306. case 4:
  307. op->datatype = op_dword; break;
  308. case 8:
  309. op->datatype = op_qword; break;
  310. case 10:
  311. op->datatype = op_extreal; break;
  312. case 16:
  313. op->datatype = op_dqword; break;
  314. }
  315. return;
  316. }
  317. /* 'impl_idx' is the value from the opcode table: between 1 and LAST_IMPL_IDX */
  318. /* returns number of operands added */
  319. unsigned int Ia32_Decoder::ia32_insn_implicit_ops( unsigned int impl_idx ) {
  320. op_implicit_list_t *list;
  321. x86_oplist_t * existing=0;
  322. x86_op_t *op;
  323. unsigned int num = 0;
  324. if (! impl_idx || impl_idx > LAST_IMPL_IDX ) {
  325. return 0;
  326. }
  327. for ( list = op_implicit_list[impl_idx]; list->type; list++, num++ ) {
  328. enum x86_op_access access = (enum x86_op_access) OP_PERM(list->type);
  329. x86_op_flags flags;
  330. flags.whole = (OP_FLAGS(list->type) >> 12);
  331. op = NULL;
  332. /* In some cases (MUL), EAX is an implicit operand hardcoded in
  333. * the instruction without being explicitly listed in assembly.
  334. * For this situation, find the hardcoded operand and add the
  335. * implied flag rather than adding a new implicit operand. */
  336. existing=0;
  337. if (ia32_true_register_id(list->operand) == REG_DWORD_OFFSET) {
  338. for ( existing = m_decoded->operands; existing; existing = existing->next ) {
  339. if (existing->op.type == op_register &&
  340. existing->op.data.reg.id == list->operand) {
  341. op = &existing->op;
  342. break;
  343. }
  344. }
  345. }
  346. if (!op) {
  347. op = m_decoded->x86_operand_new();
  348. /* all implicit operands are registers */
  349. handle_impl_reg( op, list->operand );
  350. /* decrement the 'explicit count' incremented by default in
  351. * x86_operand_new */
  352. m_decoded->explicit_count = m_decoded->explicit_count -1;
  353. }
  354. if (!op) {
  355. return num; /* gah! return early */
  356. }
  357. op->access = x86_op_access((int)op->access | (int)access);
  358. op->flags.whole |= flags.whole;
  359. op->flags.op_implied=true;
  360. }
  361. return num;
  362. }