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