Home | History | Annotate | Download | only in libdisasm
      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->type);
    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 = existing->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 }
    423