/* ia32-decode.c - ia32 decoding library * * by scut * * 2002/12/16 */ #include #include #include #include #include #include #include #include /* from ia32_opcodes.c */ extern unsigned int ia32_opnum_table[]; char * ia32_regs_wide[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; char * ia32_regs_half[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; char * ia32_regs_half_addr[] = { "bx + si", "bx + di", "bp + si", "bp + di", "si", "di", "disp16:", "bx" }; char * ia32_regs_small[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; char * ia32_regs_spec_cr[] = { "cr0", "cr_invalid", "cr2", "cr3", "cr4", "cr_invalid", "cr_invalid", "cr_invalid" }; char * ia32_regs_spec_dr[] = { "dr0", "dr1", "dr2", "dr3", "dr_invalid", "dr_invalid", "dr6", "dr7" }; char * ia32_regs_spec_seg[] = { "es", "cs", "ss", "ds", "fs", "gs", "seg_invalid", "seg_invalid" }; char * ia32_regs_spec_mmx[] = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }; ia32_prefix_e ia32_prefix_table[] = { { "lock", IA32_PREFIX_CODE_LOCK, RELACT_OVERRIDE, PFX_RELOFS (lock), 1 }, { "repne", IA32_PREFIX_CODE_REPNE, RELACT_OVERRIDE, PFX_RELOFS (rep), IA32_PREFIX_REPNE }, { "rep", IA32_PREFIX_CODE_REP, RELACT_OVERRIDE, PFX_RELOFS (rep), IA32_PREFIX_REP }, { "cs", IA32_PREFIX_CODE_CS, RELACT_COMBINE, PFX_RELOFS (seg), IA32_SEG_CS }, { "ss", IA32_PREFIX_CODE_SS, RELACT_COMBINE, PFX_RELOFS (seg), IA32_SEG_SS }, { "ds", IA32_PREFIX_CODE_DS, RELACT_COMBINE, PFX_RELOFS (seg), IA32_SEG_DS }, { "es", IA32_PREFIX_CODE_ES, RELACT_COMBINE, PFX_RELOFS (seg), IA32_SEG_ES }, { "fs", IA32_PREFIX_CODE_FS, RELACT_COMBINE, PFX_RELOFS (seg), IA32_SEG_FS }, { "gs", IA32_PREFIX_CODE_GS, RELACT_COMBINE, PFX_RELOFS (seg), IA32_SEG_GS }, { "oper", IA32_PREFIX_CODE_OPER, RELACT_OVERRIDE, PFX_RELOFS (oper_size), 1 }, { "addr", IA32_PREFIX_CODE_ADDR, RELACT_OVERRIDE, PFX_RELOFS (addr_size), 1 }, { NULL, 0, 0, 0, 0 }, }; unsigned int ia32_prefix_tabsize = (sizeof (ia32_prefix_table) / sizeof (ia32_prefix_e)) - 1; ia32_opcode_e ia32_opcode_table[] = { { IA32_OP (aaa), OD_REG_HARD_EAX, { OD_FIX | 0x37, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFAF | IA32_EFLAGS_PFZFSFOF), IA32_DF_USE (EAX) }, { IA32_OP (aad), OD_REG_HARD_EAX, { OD_FIX | 0xd5, OD_FIX | 0x0a, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_PFZFSF) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFAFOF), IA32_DF_USE (EAX) }, { IA32_OP (aam), OD_REG_HARD_EAX, { OD_FIX | 0xd4, OD_FIX | 0x0a, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_PFZFSF) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFAFOF), IA32_DF_USE (EAX) }, { IA32_OP (aas), OD_REG_HARD_EAX, { OD_FIX | 0x3f, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFAF | IA32_EFLAGS_PFZFSFOF), IA32_DF_USE (EAX) }, { IA32_OP (adc), 0, { OD_FIX_6 | OD_D | OD_W | 0x10, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (adc), OD_IMM, { OD_FIX_6 | OD_S | OD_W | 0x80, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (adc), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x14, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (add), 0, { OD_FIX_6 | OD_D | OD_W | 0x00, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (add), OD_IMM, { OD_FIX_6 | OD_S | OD_W | 0x80, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (add), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x04, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (and), 0, { OD_FIX_6 | OD_D | OD_W | 0x20, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (and), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x24, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (and), OD_IMM, { OD_FIX_6 | OD_S | OD_W | 0x80, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (arpl), 0, { OD_FIX | 0x63, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_ZF), 0 }, { IA32_OP (bound), 0, { OD_FIX | 0x62, OD_MODREGRM, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (bsf), OD_WIDTH_WIDE | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xbc, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (bsr), OD_WIDTH_WIDE | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xbd, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (bswap), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX_5 | OD_LREG | 0xc8, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, 0, 0 }, { IA32_OP (bt), OD_WIDTH_WIDE | OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x0f, OD_FIX | 0xba, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (bt), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xa3, OD_MODREGRM, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (btc), OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x0f, OD_FIX | 0xba, OD_FIX_543 | OD_MODRM | 0x38, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (btc), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xbb, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (btr), OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x0f, OD_FIX | 0xba, OD_FIX_543 | OD_MODRM | 0x30, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (btr), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xb3, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (bts), OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x0f, OD_FIX | 0xba, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (bts), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xab, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (call), OD_CONTROL | OD_IMM_DISPL | OD_IMM_DISPL_WORD, { OD_FIX | 0xe8, OD_END }, IA32_DF_USE_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (call), OD_WIDTH_WIDE | OD_CONTROL, { OD_FIX | 0xff, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_USE_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (call), OD_CONTROL | OD_IMM_OFFSET | OD_IMMSIZE_WORD | OD_IMM_SELECT, { OD_FIX | 0x9a, OD_END }, IA32_DF_USE_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (call), OD_CONTROL, { OD_FIX | 0xff, OD_FIX_543 | OD_MODRM | 0x18, OD_END }, IA32_DF_USE_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (cbw), OD_REG_HARD_EAX, { OD_FIX | 0x98, OD_END }, 0, IA32_DF_DEF (EAX), IA32_DF_USE (EAX) }, { IA32_OP (cdq), OD_REG_HARD_EAX, { OD_FIX | 0x99, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF (EDX), IA32_DF_USE (EAX) }, { IA32_OP (clc), 0, { OD_FIX | 0xf8, OD_END }, 0, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CF), 0 }, /* we do not deal with non-status flags in dataflow analysis */ { IA32_OP (cld), 0, { OD_FIX | 0xfc, OD_END }, 0, 0, 0 }, { IA32_OP (cli), 0, { OD_FIX | 0xfa, OD_END }, 0, 0, 0 }, { IA32_OP (clts), 0, { OD_FIX | 0x0f, OD_FIX | 0x06, OD_END }, 0, 0, 0 }, { IA32_OP (cmc), 0, { OD_FIX | 0xf5, OD_END }, 0, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CF), 0 }, { IA32_OP (cmov), OD_WIDTH_WIDE | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_4 | OD_TTTN | 0x40, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE | IA32_DF_USE_FLAGS_COND, 0, 0 }, { IA32_OP (cmp), 0, { OD_FIX_6 | OD_D | OD_W | 0x38, OD_MODREGRM, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (cmp), OD_IMM, { OD_FIX_6 | OD_S | OD_W | 0x80, OD_MODRM | OD_FIX_543 | 0x38, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (cmp), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x3c, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (cmps), 0, { OD_FIX_7 | OD_W | 0xa6, OD_END }, 0, IA32_DF_DEF (ESI) | IA32_DF_DEF (EDI) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (ESI) | IA32_DF_USE (EDI) }, { IA32_OP (cmpxchg), 0, { OD_FIX | 0x0f, OD_FIX_7 | OD_W | 0xb0, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EAX) }, { IA32_OP (cmpxchg8b), OD_WIDTH_DWIDE, { OD_FIX | 0x0f, OD_FIX | 0xc7, OD_MODRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF (EDX) | IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_ZF), IA32_DF_USE (EDX) | IA32_DF_USE (EAX) | IA32_DF_USE (ECX) | IA32_DF_USE (EBX) }, { IA32_OP (cpuid), 0, { OD_FIX | 0x0f, OD_FIX | 0xa2, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF (EBX) | IA32_DF_DEF (ECX) | IA32_DF_DEF (EDX), IA32_DF_USE (EAX) }, /* cwd == cdq, cwde == cbw */ { IA32_OP (daa), OD_REG_HARD_EAX, { OD_FIX | 0x27, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EAX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_CF | IA32_EFLAGS_AF) }, { IA32_OP (das), OD_REG_HARD_EAX, { OD_FIX | 0x2f, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EAX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_CF | IA32_EFLAGS_AF) }, { IA32_OP (dec), 0, { OD_FIX_7 | OD_W | 0xfe, OD_FIX_543 | OD_MODRM | 0x08, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_PFAFZFSFOF), 0 }, { IA32_OP (dec), OD_WIDTH_WIDE, { OD_FIX_5 | OD_LREG | 0x48, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_PFAFZFSFOF), 0 }, /* FIXME: IA32_DF_USE/DEF (EDX) is bogus when 0xf6 opcode is * used, fix this either by splitting into two structures * (ugly), or by adding additional logic and flags to the * dataflow stuff. */ { IA32_OP (div), OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0xf6, OD_FIX_543 | OD_MODRM | 0x30, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (EDX) | IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EDX) | IA32_DF_USE (EAX) }, { IA32_OP (enter), OD_IMM | OD_IMMSIZE_8 | OD_IMM_DISPL | OD_IMM_DISPL_16, { OD_FIX | 0xc8, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (ESP) | IA32_DF_DEF (EBP), IA32_DF_USE (ESP) | IA32_DF_USE (EBP) }, { IA32_OP (hlt), OD_CONTROL, { OD_FIX | 0xf4, OD_END }, 0, 0, 0 }, /* FIXME: see div */ { IA32_OP (idiv), OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0xf6, OD_FIX_543 | OD_MODRM | 0x38, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (EDX) | IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EDX) | IA32_DF_USE (EAX) }, { IA32_OP (imul), OD_REG12_REV | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0xf6, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (EDX) | IA32_DF_DEF (EAX) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EAX) }, { IA32_OP (imul), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xaf, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (imul), OD_REG12_REV | OD_WIDTH_WIDE | OD_IMM /*| OD_IMMSIZE_WORD*/, { OD_FIX_68 | OD_S | 0x69, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (in), OD_WTONLY | OD_REG_HARD_EAX | OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xe4, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF (EAX), 0 }, { IA32_OP (in), OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0xec, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF (EAX), IA32_DF_USE (EDX) }, { IA32_OP (inc), 0, { OD_FIX_7 | OD_W | 0xfe, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_PFAFZFSFOF), 0 }, { IA32_OP (inc), OD_WIDTH_WIDE, { OD_FIX_5 | OD_LREG | 0x40, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_PFAFZFSFOF), 0 }, { IA32_OP (ins), 0, { OD_FIX_7 | OD_W | 0x6c, OD_END }, 0, IA32_DF_DEF (EDI), IA32_DF_USE (EDI) | IA32_DF_USE (EDX) }, { IA32_OP (int), OD_CONTROL | OD_IMM | OD_REG12_REV | OD_IMMSIZE_8, { OD_FIX | 0xcd, OD_END }, 0, 0, 0 }, { IA32_OP (int3), OD_CONTROL, { OD_FIX | 0xcc, OD_END }, 0, 0, 0 }, { IA32_OP (into), OD_CONTROL, { OD_FIX | 0xce, OD_END }, 0, 0, 0 }, { IA32_OP (invd), 0, { OD_FIX | 0x0f, OD_FIX | 0x08, OD_END }, 0, 0, 0 }, { IA32_OP (invlpg), 0, { OD_FIX | 0x0f, OD_FIX | 0x01, OD_FIX_543 | OD_MODRM | 0x38, OD_END }, 0, 0, 0 }, { IA32_OP (iret), OD_CONTROL, { OD_FIX | 0xcf, OD_END }, 0, IA32_DF_DEF_FLAGS (IA32_EFLAGS_PFAFZFSFOF), 0 }, { IA32_OP (j), OD_CONTROL | OD_JUMP | OD_IMM_DISPL | OD_IMM_DISPL_8, { OD_FIX_4 | OD_TTTN | 0x70, OD_END }, IA32_DF_USE_FLAGS_COND, 0, 0 }, { IA32_OP (j), OD_CONTROL | OD_JUMP | OD_IMM_DISPL | OD_IMM_DISPL_WORD, { OD_FIX | 0x0f, OD_FIX_4 | OD_TTTN | 0x80, OD_END }, IA32_DF_USE_FLAGS_COND, 0, 0 }, { IA32_OP (jcxz), OD_CONTROL | OD_JUMP | OD_IMM_DISPL | OD_IMM_DISPL_8, { OD_FIX | 0xe3, OD_END }, 0, 0, IA32_DF_USE (ECX) }, { IA32_OP (jmp), OD_CONTROL | OD_JUMP | OD_IMM_DISPL | OD_IMM_DISPL_8, { OD_FIX | 0xeb, OD_END }, 0, 0, 0 }, { IA32_OP (jmp), OD_CONTROL | OD_JUMP | OD_IMM_DISPL | OD_IMM_DISPL_WORD, { OD_FIX | 0xe9, OD_END }, 0, 0, 0 }, { IA32_OP (jmp), OD_CONTROL | OD_JUMP | OD_WIDTH_WIDE, { OD_FIX | 0xff, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_USE_TARGET, 0, 0 }, { IA32_OP (ljmp), OD_CONTROL | OD_JUMP | OD_IMM_OFFSET | OD_IMMSIZE_WORD | OD_IMM_SELECT, { OD_FIX | 0xea, OD_END }, 0, 0, 0 }, { IA32_OP (ljmp), OD_CONTROL | OD_JUMP | OD_WIDTH_WIDE, { OD_FIX | 0xff, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_USE_TARGET, 0, 0 }, { IA32_OP (lahf), 0, { OD_FIX | 0x9f, OD_END }, 0, IA32_DF_DEF (EAX), IA32_DF_USE_FLAGS (IA32_EFLAGS_CFPFAFZFSF) }, { IA32_OP (lar), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x02, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_ZF), 0 }, { IA32_OP (lds), 0, { OD_FIX | 0xc5, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, /* FIXME: OD_REG12_REV is odd for lea, check why */ { IA32_OP (lea), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX | 0x8d, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (leave), 0, { OD_FIX | 0xc9, OD_END }, 0, IA32_DF_DEF (ESP) | IA32_DF_DEF (EBP), IA32_DF_USE (EBP) }, { IA32_OP (les), 0, { OD_FIX | 0xc4, OD_MODREGRM, OD_END }, 0, 0, 0 }, { IA32_OP (lfs), 0, { OD_FIX | 0x0f, OD_FIX | 0xb4, OD_MODREGRM, OD_END }, 0, 0, 0 }, { IA32_OP (lgdt), OD_WIDTH_WIDE | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0x01, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (lgs), 0, { OD_FIX | 0x0f, OD_FIX | 0xb5, OD_MODREGRM, OD_END }, 0, 0, 0 }, { IA32_OP (lldt), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x00, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (lmsw), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x01, OD_FIX_543 | OD_MODRM | 0x30, OD_END }, IA32_DF_USE_SOURCE, 0, 0 }, /* lock is a prefix */ { IA32_OP (lods), 0, { OD_FIX_7 | OD_W | 0xac, OD_END }, 0, IA32_DF_DEF (ESI) | IA32_DF_DEF (EAX), IA32_DF_USE (ESI) }, { IA32_OP (loop), OD_CONTROL | OD_IMM_DISPL | OD_IMM_DISPL_8, { OD_FIX | 0xe2, OD_END }, 0, IA32_DF_DEF (ECX), IA32_DF_USE (ECX) }, { IA32_OP (loopz), OD_CONTROL | OD_IMM_DISPL | OD_IMM_DISPL_8, { OD_FIX | 0xe1, OD_END }, 0, IA32_DF_DEF (ECX), IA32_DF_USE (ECX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_ZF) }, { IA32_OP (loopnz), OD_CONTROL | OD_IMM_DISPL | OD_IMM_DISPL_8, { OD_FIX | 0xe0, OD_END }, 0, IA32_DF_DEF (ECX), IA32_DF_USE (ECX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_ZF) }, { IA32_OP (lsl), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x03, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_ZF), 0 }, { IA32_OP (lss), 0, { OD_FIX | 0x0f, OD_FIX | 0xb2, OD_MODREGRM, OD_END }, 0, 0, 0 }, { IA32_OP (ltr), 0, { OD_FIX | 0x0f, OD_FIX | 0x00, OD_FIX_543 | OD_MODRM | 0x18, OD_END }, IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (mov), 0, { OD_FIX_6 | OD_D | OD_W | 0x88, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (mov), OD_IMM, { OD_FIX_7 | OD_W | 0xc6, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (mov), OD_IMM, { OD_FIX_4 | OD_W3 | OD_LREG | 0xb0, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (mov), OD_REG_HARD_EAX | OD_IMM_DISPL | OD_IMM_DISPL_WORD, { OD_FIX_6 | OD_D | OD_W | 0xa0, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (mov), OD_WIDTH_WIDE | OD_CR, { OD_FIX | 0x0f, OD_FIX_68 | OD_D | 0x20, OD_FIX_2 | OD_EEE | OD_LREG | 0xc0, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (mov), OD_WIDTH_WIDE | OD_DR, { OD_FIX | 0x0f, OD_FIX_68 | OD_D | 0x21, OD_FIX_2 | OD_EEE | OD_LREG | 0xc0, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (mov), OD_WIDTH_LOCK, { OD_FIX_68 | OD_D | 0x8c, OD_SREG3 | OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (movs), 0, { OD_FIX_7 | OD_W | 0xa4, OD_END }, 0, IA32_DF_DEF (EDI) | IA32_DF_DEF (ESI), IA32_DF_USE (EDI) | IA32_DF_USE (ESI) }, { IA32_OP (movsx), OD_REG12_REV | OD_WIDTH_LWIDE, { OD_FIX | 0x0f, OD_FIX_7 | OD_W | 0xbe, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (movzx), OD_REG12_REV | OD_WIDTH_LWIDE, { OD_FIX | 0x0f, OD_FIX_7 | OD_W | 0xb6, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, /* FIXME: see div */ { IA32_OP (mul), OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0xf6, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (neg), 0, { OD_FIX_7 | OD_W | 0xf6, OD_FIX_543 | OD_MODRM | 0x18, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, /* ORDER: alias of xchg eax, eax */ { IA32_OP (nop), 0, { OD_FIX | 0x90, OD_END }, 0, 0, 0 }, { IA32_OP (not), 0, { OD_FIX_7 | OD_W | 0xf6, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, 0, 0 }, { IA32_OP (or), 0, { OD_FIX_6 | OD_D | OD_W | 0x08, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (or), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x0c, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (or), OD_IMM, { OD_FIX_6 | OD_S | OD_W | 0x80, OD_FIX_543 | OD_MODRM | 0x08, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (out), OD_REG12_REV | OD_WTONLY | OD_REG_HARD_EAX | OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xe6, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (out), OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0xee, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (outs), 0, { OD_FIX_7 | OD_W | 0x6e, OD_END }, 0, IA32_DF_DEF (ESI), IA32_DF_USE (ESI) | IA32_DF_USE (EDX) }, { IA32_OP (pop), OD_WIDTH_WIDE, { OD_FIX | 0x8f, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (pop), OD_WIDTH_WIDE, { OD_FIX_5 | OD_LREG | 0x58, OD_END }, IA32_DF_DEF_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, /* XXX: this is broken in the intel documentation, where "pop cs" would * result in a "0x0f" opcode, which is a extend-opcode. we work around * this bug in the documentation(?) by splitting the opcode into its * pieces: 000s.s111, s are the sreg bits. so we go for two choices: * mask: 1111.0111 => 0001.0111, * mask: 1110.1111 => 0000.0111, * mask: 1111.1111 => 0001.1111, * ignored: => 0000.1111, as this would be 0x0f (extend-opcode) * * if the intel documentation would be correct, this line would * suffice: * IA32_OP ("pop", OD_WIDTH_LOCK, { OD_CMASK_SET(0xe7) | OD_SREG2 | 0x07, * OD_END } */ { IA32_OP (pop), OD_WIDTH_LOCK, { OD_CMASK_SET(0xf7) | OD_SREG2 | 0x17, OD_END }, IA32_DF_DEF_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (pop), OD_WIDTH_LOCK, { OD_CMASK_SET(0xef) | OD_SREG2 | 0x07, OD_END }, IA32_DF_DEF_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (pop), OD_WIDTH_LOCK, { OD_CMASK_SET(0xff) | OD_SREG2 | 0x1f, OD_END }, IA32_DF_DEF_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (pop), OD_WIDTH_LOCK, { OD_FIX | 0x0f, OD_CMASK_SET(0xc7) | OD_SREG3 | 0x81, OD_END }, IA32_DF_DEF_TARGET, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (popa), 0, { OD_FIX | 0x61, OD_END }, 0, IA32_DF_DEF (EAX) | IA32_DF_DEF (EBX) | IA32_DF_DEF (ECX) | IA32_DF_DEF (EDX) | IA32_DF_DEF (ESI) | IA32_DF_DEF (EDI) | IA32_DF_DEF (EBP) | IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (popf), 0, { OD_FIX | 0x9d, OD_END }, 0, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF) | IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (push), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX | 0xff, OD_FIX_543 | OD_MODRM | 0x30, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (push), OD_REG12_REV | OD_WIDTH_WIDE, { OD_FIX_5 | OD_LREG | 0x50, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (push), OD_IMM | OD_IMMSIZE_WORD, { OD_FIX | 0x68, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (push), OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x6a, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (push), OD_REG12_REV | OD_WIDTH_LOCK, { OD_CMASK_SET(0xe7) | OD_SREG2 | 0x06, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, /* kludge: the intel instruction format list is wrong here. from the * sreg3 field that is encoded in the instruction, only the * lsb can be choosen, the upper two bits are fixed: 10x, 100 for * the fs segment register, 101 for gs. without this unwritten * exception, the set instruction encoding would collide. * * intel: 0000 1111 : 10 sreg3 000 * fixed: 0000 1111 : 1010 x 000 * * where x makes up the lsb of sreg3: 10x */ { IA32_OP (push), OD_REG12_REV | OD_WIDTH_LOCK, { OD_FIX | 0x0f, OD_CMASK_SET(0xf7) | OD_SREG3 | 0xa0, OD_END }, IA32_DF_USE_SOURCE, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (pusha), 0, { OD_FIX | 0x60, OD_END }, 0, IA32_DF_DEF (ESP), IA32_DF_USE (EAX) | IA32_DF_USE (EBX) | IA32_DF_USE (ECX) | IA32_DF_USE (EDX) | IA32_DF_USE (ESI) | IA32_DF_USE (EDI) | IA32_DF_USE (EBP) | IA32_DF_USE (ESP) }, { IA32_OP (pushf), 0, { OD_FIX | 0x9c, OD_END }, 0, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) | IA32_DF_USE_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF) }, { IA32_OP (rcl1), 0, { OD_FIX_7 | OD_W | 0xd0, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rclcl), 0, { OD_FIX_7 | OD_W | 0xd2, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE (ECX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rcl), OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xc0, OD_FIX_543 | OD_MODRM | 0x10, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rcr1), 0, { OD_FIX_7 | OD_W | 0xd0, OD_FIX_543 | OD_MODRM | 0x18, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rcrcl), 0, { OD_FIX_7 | OD_W | 0xd2, OD_FIX_543 | OD_MODRM | 0x18, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE (ECX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rcr), OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xc0, OD_FIX_543 | OD_MODRM | 0x18, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rdmsr), 0, { OD_FIX | 0x0f, OD_FIX | 0x32, OD_END }, 0, IA32_DF_DEF (EDX) | IA32_DF_DEF (EAX), IA32_DF_USE (ECX) }, { IA32_OP (rdpmc), 0, { OD_FIX | 0x0f, OD_FIX | 0x33, OD_END }, 0, IA32_DF_DEF (EDX) | IA32_DF_DEF (EAX), IA32_DF_USE (ECX) }, { IA32_OP (rdtsc), 0, { OD_FIX | 0x0f, OD_FIX | 0x31, OD_END }, 0, IA32_DF_DEF (EDX) | IA32_DF_DEF (EAX), 0 }, { IA32_OP (ret), OD_CONTROL, { OD_FIX | 0xc3, OD_END }, 0, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (ret), OD_CONTROL | OD_IMM_DISPL | OD_IMM_DISPL_16, { OD_FIX | 0xc2, OD_END }, 0, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (retf), OD_CONTROL, { OD_FIX | 0xcb, OD_END }, 0, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (retf), OD_CONTROL | OD_IMM_DISPL | OD_IMM_DISPL_16, { OD_FIX | 0xca, OD_END }, 0, IA32_DF_DEF (ESP), IA32_DF_USE (ESP) }, { IA32_OP (rol1), 0, { OD_FIX_7 | OD_W | 0xd0, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rolcl), 0, { OD_FIX_7 | OD_W | 0xd2, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE (ECX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rol), OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xc0, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (ror1), 0, { OD_FIX_7 | OD_W | 0xd0, OD_FIX_543 | OD_MODRM | 0x08, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rorcl), 0, { OD_FIX_7 | OD_W | 0xd2, OD_FIX_543 | OD_MODRM | 0x08, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE (ECX) | IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (ror), OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xc0, OD_FIX_543 | OD_MODRM | 0x08, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (rsm), 0, { OD_FIX | 0x0f, OD_FIX | 0xaa, OD_END }, 0, 0, 0 }, { IA32_OP (sahf), 0, { OD_FIX | 0x9e, OD_END }, 0, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EAX) }, /* sal = shl */ { IA32_OP (sar1), 0, { OD_FIX_7 | OD_W | 0xd0, OD_FIX_543 | OD_MODRM | 0x38, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (sarcl), 0, { OD_FIX_7 | OD_W | 0xd2, OD_FIX_543 | OD_MODRM | 0x38, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (ECX) }, { IA32_OP (sar), OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xc0, OD_FIX_543 | OD_MODRM | 0x38, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (sbb), 0, { OD_FIX_6 | OD_D | OD_W | 0x18, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (sbb), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x1c, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, { IA32_OP (sbb), OD_IMM, { OD_FIX_6 | OD_S | OD_W | 0x80, OD_FIX_543 | OD_MODRM | 0x18, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE_FLAGS (IA32_EFLAGS_CF) }, /* XXX: intel docs are plain wrong about this, they put scas as * 1101.111w, while it is 1010.111w infact. doh! */ { IA32_OP (scas), 0, { OD_FIX_7 | OD_W | 0xae, OD_END }, 0, IA32_DF_DEF (EDI) | IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (EDI) | IA32_DF_USE (EAX) }, { IA32_OP (set), 0, { OD_FIX | 0x0f, OD_FIX_4 | OD_TTTN | 0x90, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_USE_FLAGS_COND | IA32_DF_DEF_TARGET, 0, 0 }, { IA32_OP (sgdt), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x01, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET, 0, 0 }, { IA32_OP (shl1), 0, { OD_FIX_7 | OD_W | 0xd0, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (shlcl), 0, { OD_FIX_7 | OD_W | 0xd2, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (ECX) }, { IA32_OP (shl), OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xc0, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (shld), OD_IMM | OD_IMMSIZE_8 | OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xa4, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_DEF_SOURCE | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (shldcl), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xa5, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_DEF_SOURCE | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (ECX) }, { IA32_OP (shr1), 0, { OD_FIX_7 | OD_W | 0xd0, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (shrcl), 0, { OD_FIX_7 | OD_W | 0xd2, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (ECX) }, { IA32_OP (shr), OD_IMM | OD_IMMSIZE_8, { OD_FIX_7 | OD_W | 0xc0, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (shrd), OD_IMM | OD_IMMSIZE_8 | OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xac, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_DEF_SOURCE | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (shrdcl), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0xad, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_DEF_SOURCE | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), IA32_DF_USE (ECX) }, { IA32_OP (sidt), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x01, OD_FIX_543 | OD_MODRM | 0x08, OD_END }, IA32_DF_DEF_TARGET, 0, 0 }, { IA32_OP (sldt), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x00, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_DEF_TARGET, 0, 0 }, { IA32_OP (smsw), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x01, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_DEF_TARGET, 0, 0 }, { IA32_OP (stc), 0, { OD_FIX | 0xf9, OD_END }, 0, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CF), 0 }, /* we do not handle non-status flags (yet?) */ { IA32_OP (std), 0, { OD_FIX | 0xfd, OD_END }, 0, 0, 0 }, { IA32_OP (sti), 0, { OD_FIX | 0xfb, OD_END }, 0, 0, 0 }, { IA32_OP (stos), 0, { OD_FIX_7 | OD_W | 0xaa, OD_END }, 0, IA32_DF_DEF (EDI), IA32_DF_USE (EDI) | IA32_DF_USE (EAX) }, { IA32_OP (str), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x00, OD_FIX_543 | OD_MODRM | 0x08, OD_END }, IA32_DF_DEF_TARGET, 0, 0 }, { IA32_OP (sub), 0, { OD_FIX_6 | OD_D | OD_W | 0x28, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (sub), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x2c, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (sub), OD_IMM, { OD_FIX_6 | OD_S | OD_W | 0x80, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (test), 0, { OD_FIX_7 | OD_W | 0x84, OD_MODREGRM, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (test), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0xa8, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (test), OD_IMM, { OD_FIX_7 | OD_W | 0xf6, OD_FIX_543 | OD_MODRM | 0x00, OD_END }, IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (ud2), 0, { OD_FIX | 0x0f, OD_FIX | 0x0b, OD_END }, 0, 0 }, { IA32_OP (verr), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x00, OD_FIX_543 | OD_MODRM | 0x20, OD_END }, IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_ZF), 0 }, { IA32_OP (verw), OD_WIDTH_WIDE, { OD_FIX | 0x0f, OD_FIX | 0x00, OD_FIX_543 | OD_MODRM | 0x28, OD_END }, IA32_DF_USE_TARGET, IA32_DF_DEF_FLAGS (IA32_EFLAGS_ZF), 0 }, { IA32_OP (wait), 0, { OD_FIX | 0x9b, OD_END }, 0, 0, 0 }, { IA32_OP (wbinvd), 0, { OD_FIX | 0x0f, OD_FIX | 0x09, OD_END }, 0, 0, 0 }, { IA32_OP (wrmsr), 0, { OD_FIX | 0x0f, OD_FIX | 0x30, OD_END }, 0, 0, IA32_DF_USE (EDX) | IA32_DF_USE (EAX) | IA32_DF_USE (ECX) }, { IA32_OP (xadd), 0, { OD_FIX | 0x0f, OD_FIX_7 | OD_W | 0xc0, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_DEF_SOURCE | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (xchg), 0, { OD_FIX_7 | OD_W | 0x86, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_DEF_SOURCE | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (xchg), OD_REG_HARD_EAX | OD_WIDTH_WIDE, { OD_FIX_5 | OD_LREG | 0x90, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_DEF_SOURCE | IA32_DF_USE_SOURCE, 0, 0 }, { IA32_OP (xlat), 0, { OD_FIX | 0xd7, OD_END }, 0, IA32_DF_DEF (EAX), IA32_DF_USE (EBX) | IA32_DF_USE (EAX) }, { IA32_OP (xor), 0, { OD_FIX_6 | OD_D | OD_W | 0x30, OD_MODREGRM, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (xor), OD_IMM | OD_REG_HARD_EAX, { OD_FIX_7 | OD_W | 0x34, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, { IA32_OP (xor), OD_IMM , { OD_FIX_6 | OD_S | OD_W | 0x80, OD_FIX_543 | OD_MODRM | 0x30, OD_END }, IA32_DF_DEF_TARGET | IA32_DF_USE_TARGET | IA32_DF_USE_SOURCE, IA32_DF_DEF_FLAGS (IA32_EFLAGS_CFPFAFZFSFOF), 0 }, /*** TODO: implement dataflow analysis for mmx and fpu instructions */ /*** MMX */ { IA32_OP (emms), OD_MMX, { OD_FIX | 0x0f, OD_FIX | 0x77, OD_END } }, { IA32_OP (movd), OD_MMX | OD_GG_D | OD_REGNOMMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0x6e, OD_MODREGRM, OD_END } }, { IA32_OP (movd), OD_MMX | OD_GG_D | OD_WIDTH_WIDE | OD_REGNOMMX, { OD_FIX | 0x0f, OD_FIX | 0x7e, OD_MODREGRM, OD_END } }, { IA32_OP (movq), OD_WIDTH_LOCK | OD_MMX | OD_GG_Q | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0x6f, OD_MODREGRM, OD_END } }, { IA32_OP (movq), OD_WIDTH_LOCK | OD_MMX | OD_GG_Q, { OD_FIX | 0x0f, OD_FIX | 0x7f, OD_MODREGRM, OD_END } }, { IA32_OP (packssdw), OD_MMX | OD_GG_D | OD_GG_IN_HI | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0x6b, OD_MODREGRM, OD_END } }, { IA32_OP (packsswb), OD_MMX | OD_GG_W | OD_GG_IN_HI | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0x63, OD_MODREGRM, OD_END } }, { IA32_OP (packuswb), OD_MMX | OD_GG_W | OD_GG_IN_HI | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0x67, OD_MODREGRM, OD_END } }, { IA32_OP (padd), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xfc, OD_MODREGRM, OD_END } }, { IA32_OP (padds), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xec, OD_MODREGRM, OD_END } }, { IA32_OP (paddus), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xdc, OD_MODREGRM, OD_END } }, { IA32_OP (pand), OD_MMX | OD_GG_Q | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xdb, OD_MODREGRM, OD_END } }, { IA32_OP (pandn), OD_MMX | OD_GG_Q | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xdf, OD_MODREGRM, OD_END } }, { IA32_OP (pcmpeq), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0x74, OD_MODREGRM, OD_END } }, { IA32_OP (pcmpgt), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0x64, OD_MODREGRM, OD_END } }, { IA32_OP (pmadd), OD_MMX | OD_GG_W | OD_GG_IN_LOW | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xf5, OD_MODREGRM, OD_END } }, { IA32_OP (pmulh), OD_MMX | OD_GG_W | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xe5, OD_MODREGRM, OD_END } }, { IA32_OP (pmull), OD_MMX | OD_GG_W | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xd5, OD_MODREGRM, OD_END } }, { IA32_OP (por), OD_MMX | OD_GG_Q | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xeb, OD_MODREGRM, OD_END } }, { IA32_OP (psll), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xf0, OD_MODREGRM, OD_END } }, { IA32_OP (psll), OD_MMX | OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0x70, OD_FIX_5 | OD_LREG | 0xf0, OD_END } }, { IA32_OP (psra), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xe0, OD_MODREGRM, OD_END } }, { IA32_OP (psra), OD_MMX | OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0x70, OD_FIX_5 | OD_LREG | 0xe0, OD_END } }, { IA32_OP (psrl), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xd0, OD_MODREGRM, OD_END } }, { IA32_OP (psrl), OD_MMX | OD_IMM | OD_IMMSIZE_8, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0x70, OD_FIX_5 | OD_LREG | 0xd0, OD_END } }, { IA32_OP (psub), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xf8, OD_MODREGRM, OD_END } }, { IA32_OP (psubs), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xe8, OD_MODREGRM, OD_END } }, { IA32_OP (psubus), OD_MMX | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0xd8, OD_MODREGRM, OD_END } }, { IA32_OP (punpckh), OD_MMX | OD_GG_IN_LOW | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0x68, OD_MODREGRM, OD_END } }, { IA32_OP (punpckl), OD_MMX | OD_GG_IN_LOW | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX_6 | OD_GG | 0x60, OD_MODREGRM, OD_END } }, { IA32_OP (pxor), OD_MMX | OD_GG_Q | OD_REG12_REV, { OD_FIX | 0x0f, OD_FIX | 0xef, OD_MODREGRM, OD_END } }, /*** i387 FPU opcodes * * XXX: here we rely on the order of instruction decoding, in that we * have explicit forms for modbytes with mod = 11. see fadd for * example. */ /* ORDER: would clash with fbstp */ { IA32_OP (fcomip), OD_FPU, { OD_FIX | 0xdf, OD_FIX_5 | OD_FPU_STI | 0xf0, OD_END } }, /* ORDER: before fldcw */ { IA32_OP (fldl2e), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xea, OD_END } }, { IA32_OP (fldl2t), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xe9, OD_END } }, { IA32_OP (fldlg2), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xec, OD_END } }, { IA32_OP (fldln2), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xed, OD_END } }, { IA32_OP (fldpi), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xeb, OD_END } }, { IA32_OP (fldz), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xee, OD_END } }, /* ORDER: before fimul */ { IA32_OP (fmulp), OD_FPU, { OD_FIX | 0xde, OD_FIX_5 | OD_FPU_STI | 0xc8, OD_END } }, /* ORDER: before fbld */ { IA32_OP (fstsw), OD_FPU, { OD_FIX | 0xdf, OD_FIX | 0xe0, OD_END } }, /* ORDER: before fisubr */ { IA32_OP (fsubp), OD_FPU, { OD_FIX | 0xde, OD_FIX_5 | OD_FPU_STI | 0xe8, OD_END } }, /* ORDER: before fldenv */ { IA32_OP (ftst), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xe4, OD_END } }, /* ORDER: before any modbyte with possibly mod = 11 */ { IA32_OP (fucom), OD_FPU, { OD_FIX | 0xdd, OD_FIX_5 | OD_FPU_STI | 0xe0, OD_END } }, { IA32_OP (fucomp), OD_FPU, { OD_FIX | 0xdd, OD_FIX_5 | OD_FPU_STI | 0xe8, OD_END } }, { IA32_OP (fucompp), OD_FPU, { OD_FIX | 0xda, OD_FIX | 0xe9, OD_END } }, { IA32_OP (fucomi), OD_FPU, { OD_FIX | 0xdb, OD_FIX_5 | OD_FPU_STI | 0xe8, OD_END } }, { IA32_OP (fucomip), OD_FPU, { OD_FIX | 0xdf, OD_FIX_5 | OD_FPU_STI | 0xe8, OD_END } }, { IA32_OP (fxam), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xe5, OD_END } }, { IA32_OP (fxch), OD_FPU, { OD_FIX | 0xd9, OD_FIX_5 | OD_FPU_STI | 0xc8, OD_END } }, { IA32_OP (fxtract), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf4, OD_END } }, { IA32_OP (fyl2x), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf1, OD_END } }, { IA32_OP (fyl2xp1), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf9, OD_END } }, /* normal order */ { IA32_OP (f2xm1), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf0, OD_END } }, { IA32_OP (fabs), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xe1, OD_END } }, { IA32_OP (fadd), OD_FPU | OD_FPU_WITH_ST0, { OD_FIX_N2 | OD_FPU_D | 0xd8, OD_FIX_5 | OD_FPU_STI | 0xc0, OD_END } }, { IA32_OP (fadd), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (fadd), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (faddp), OD_FPU, { OD_FIX | 0xde, OD_FIX_5 | OD_FPU_STI | 0xc0, OD_END } }, { IA32_OP (fbld), OD_FPU | OD_WIDTH_FPU, { OD_FIX | 0xdf, OD_FIX_543 | OD_MODRM | 0x20, OD_END } }, { IA32_OP (fbstp), OD_FPU | OD_WIDTH_FPU, { OD_FIX | 0xdf, OD_FIX_543 | OD_MODRM | 0x30, OD_END } }, { IA32_OP (fchs), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xe0, OD_END } }, { IA32_OP (fclex), OD_FPU, { OD_FIX | 0xdb, OD_FIX | 0xe2, OD_END } }, { IA32_OP (fcmovb), OD_FPU, { OD_FIX | 0xda, OD_FIX_5 | OD_FPU_STI | 0xc0, OD_END } }, { IA32_OP (fcmove), OD_FPU, { OD_FIX | 0xda, OD_FIX_5 | OD_FPU_STI | 0xc8, OD_END } }, { IA32_OP (fcmovbe), OD_FPU, { OD_FIX | 0xda, OD_FIX_5 | OD_FPU_STI | 0xd0, OD_END } }, { IA32_OP (fcmovu), OD_FPU, { OD_FIX | 0xda, OD_FIX_5 | OD_FPU_STI | 0xd8, OD_END } }, { IA32_OP (fcmovnb), OD_FPU, { OD_FIX | 0xdb, OD_FIX_5 | OD_FPU_STI | 0xc0, OD_END } }, { IA32_OP (fcmovne), OD_FPU, { OD_FIX | 0xdb, OD_FIX_5 | OD_FPU_STI | 0xc8, OD_END } }, { IA32_OP (fcmovnbe), OD_FPU, { OD_FIX | 0xdb, OD_FIX_5 | OD_FPU_STI | 0xd0, OD_END } }, { IA32_OP (fcmovnu), OD_FPU, { OD_FIX | 0xdb, OD_FIX_5 | OD_FPU_STI | 0xd8, OD_END } }, { IA32_OP (fcom), OD_FPU, { OD_FIX | 0xd8, OD_FIX_5 | OD_FPU_STI | 0xd0, OD_END } }, { IA32_OP (fcom), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (fcom), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (fcomp), OD_FPU, { OD_FIX | 0xd8, OD_FIX_5 | OD_FPU_STI | 0xd8, OD_END } }, { IA32_OP (fcomp), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (fcomp), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (fcompp), OD_FPU, { OD_FIX | 0xde, OD_FIX | 0xd9, OD_END } }, { IA32_OP (fcomi), OD_FPU, { OD_FIX | 0xdb, OD_FIX_5 | OD_FPU_STI | 0xf0, OD_END } }, { IA32_OP (fcos), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xff, OD_END } }, { IA32_OP (fdecstp), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf6, OD_END } }, { IA32_OP (fdiv), OD_FPU | OD_FPU_WITH_ST0, { OD_FIX_N2 | OD_FPU_D | 0xd8, OD_FIX_4 | OD_FPU_R | OD_FPU_STI | 0xf0, OD_END } }, { IA32_OP (fdiv), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x30, OD_END } }, { IA32_OP (fdiv), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x30, OD_END } }, { IA32_OP (fdivp), OD_FPU, { OD_FIX | 0xde, OD_FIX_5 | OD_FPU_STI | 0xf8, OD_END } }, /* fdivr ST(d) <- ST(i) % ST(0) is already encoded in fdiv */ { IA32_OP (fdivr), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fdivr), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fdivrp), OD_FPU, { OD_FIX | 0xde, OD_FIX_5 | OD_FPU_STI | 0xf0, OD_END } }, { IA32_OP (ffree), OD_FPU, { OD_FIX | 0xdd, OD_FIX_5 | OD_FPU_STI | 0xc0, OD_END } }, { IA32_OP (fiadd), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (fiadd), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (ficom), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (ficom), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (ficomp), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (ficomp), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (fidiv), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x30, OD_END } }, { IA32_OP (fidiv), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x30, OD_END } }, { IA32_OP (fidivr), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fidivr), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fild), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xdf, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (fild), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xdb, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (fild), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdf, OD_FIX_543 | OD_MODRM | 0x28, OD_END } }, { IA32_OP (fimul), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x08, OD_END } }, { IA32_OP (fimul), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x08, OD_END } }, { IA32_OP (fincstp), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf7, OD_END } }, { IA32_OP (finit), OD_FPU, { OD_FIX | 0xdb, OD_FIX | 0xe3, OD_END } }, { IA32_OP (fist), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xdf, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (fist), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xdb, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (fistp), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xdf, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (fistp), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xdb, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (fistp), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdf, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fisub), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x20, OD_END } }, { IA32_OP (fisub), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x20, OD_END } }, { IA32_OP (fisubr), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xde, OD_FIX_543 | OD_MODRM | 0x28, OD_END } }, { IA32_OP (fisubr), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xda, OD_FIX_543 | OD_MODRM | 0x28, OD_END } }, { IA32_OP (fld), OD_FPU, { OD_FIX | 0xd9, OD_FIX_5 | OD_FPU_STI | 0xc0, OD_END } }, { IA32_OP (fld), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd9, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (fld), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdd, OD_FIX_543 | OD_MODRM | 0x00, OD_END } }, { IA32_OP (fld), OD_FPU | OD_WIDTH_FPU, { OD_FIX | 0xdb, OD_FIX_543 | OD_MODRM | 0x28, OD_END } }, { IA32_OP (fld1), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xe8, OD_END } }, { IA32_OP (fldcw), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xd9, OD_FIX_543 | OD_MODRM | 0x28, OD_END } }, { IA32_OP (fldenv), OD_FPU, { OD_FIX | 0xd9, OD_FIX_543 | OD_MODRM | 0x20, OD_END } }, { IA32_OP (fmul), OD_FPU | OD_FPU_WITH_ST0, { OD_FIX_N2 | OD_FPU_D | 0xd8, OD_FIX_5 | OD_FPU_STI | 0xc8, OD_END } }, { IA32_OP (fmul), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x08, OD_END } }, { IA32_OP (fmul), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x08, OD_END } }, { IA32_OP (fnop), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xd0, OD_END } }, { IA32_OP (fpatan), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf3, OD_END } }, { IA32_OP (fprem), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf8, OD_END } }, { IA32_OP (fprem1), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf5, OD_END } }, { IA32_OP (fptan), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xf2, OD_END } }, { IA32_OP (frndint), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xfc, OD_END } }, { IA32_OP (frstor), OD_FPU, { OD_FIX | 0xdd, OD_FIX_543 | OD_MODRM | 0x20, OD_END } }, { IA32_OP (fsave), OD_FPU, { OD_FIX | 0xdd, OD_FIX_543 | OD_MODRM | 0x30, OD_END } }, { IA32_OP (fscale), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xfd, OD_END } }, { IA32_OP (fsin), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xfe, OD_END } }, { IA32_OP (fsincos), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xfb, OD_END } }, { IA32_OP (fsqrt), OD_FPU, { OD_FIX | 0xd9, OD_FIX | 0xfa, OD_END } }, { IA32_OP (fst), OD_FPU, { OD_FIX | 0xdd, OD_FIX_5 | OD_FPU_STI | 0xd0, OD_END } }, { IA32_OP (fst), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd9, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (fst), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdd, OD_FIX_543 | OD_MODRM | 0x10, OD_END } }, { IA32_OP (fstcw), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xd9, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fstenv), OD_FPU, { OD_FIX | 0xd9, OD_FIX_543 | OD_MODRM | 0x30, OD_END } }, { IA32_OP (fstp), OD_FPU, { OD_FIX | 0xdd, OD_FIX_5 | OD_FPU_STI | 0xd8, OD_END } }, { IA32_OP (fstp), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd9, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (fstp), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdd, OD_FIX_543 | OD_MODRM | 0x18, OD_END } }, { IA32_OP (fstp), OD_FPU | OD_WIDTH_FPU, { OD_FIX | 0xdb, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fstsw), OD_FPU | OD_WIDTH_16, { OD_FIX | 0xdd, OD_FIX_543 | OD_MODRM | 0x38, OD_END } }, { IA32_OP (fsub), OD_FPU | OD_FPU_WITH_ST0, { OD_FIX_N2 | OD_FPU_D | 0xd8, OD_FIX_4 | OD_FPU_R | OD_FPU_STI | 0xe0, OD_END } }, { IA32_OP (fsub), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x20, OD_END } }, { IA32_OP (fsub), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x20, OD_END } }, /* fsubr ST(d) <- ST(i) - ST(0) : already encoded in fsubp */ { IA32_OP (fsubr), OD_FPU | OD_WIDTH_WIDE, { OD_FIX | 0xd8, OD_FIX_543 | OD_MODRM | 0x28, OD_END } }, { IA32_OP (fsubr), OD_FPU | OD_WIDTH_DWIDE, { OD_FIX | 0xdc, OD_FIX_543 | OD_MODRM | 0x28, OD_END } }, { IA32_OP (fsubrp), OD_FPU, { OD_FIX | 0xde, OD_FIX_5 | OD_FPU_STI | 0xe0, OD_END } }, /* fwait == wait */ { 0, 0, 0, { OD_END } }, }; unsigned int ia32_opcode_tabsize = (sizeof (ia32_opcode_table) / sizeof (ia32_opcode_e)) - 1; /*** local function prototypes */ static void ia32_extend (int sflag, unsigned int *value, unsigned int size); static void ia32_decode_opcode_mod (unsigned char *input, unsigned int bp, ia32_opcode_e *oel, ia32_opcode *opc, unsigned int reg_width, unsigned int addr_width); static ia32_opcode_e * ia32_decode_opcode_find (unsigned char *input); static void ia32_decode_opcode_sib (unsigned char *input, unsigned int bp, ia32_opcode *opc); static void ia32_sprint_operand (char *tbuf, ia32_instruction *inst, unsigned int type, unsigned int width, unsigned int reg); /*** public functions */ ia32_instruction * ia32_decode_instruction (unsigned char *input, ia32_instruction *new) { int new_malloc = 0; ia32_prefix * pfx; ia32_opcode * opc; if (new == NULL) { new = malloc (sizeof (ia32_instruction)); new_malloc = 1; } memset (new, 0x00, sizeof (ia32_instruction)); pfx = ia32_decode_prefix (input, &new->pfx); opc = ia32_decode_opcode (input + pfx->length, &new->opc, pfx); if (opc == NULL) { fprintf (stderr, "error, no opc structure found :(\n"); if (new_malloc) free (new); return (NULL); } new->user = NULL; new->length = pfx->length + opc->length; return (new); } ia32_prefix * ia32_decode_prefix (unsigned char *input, ia32_prefix *new) { int pw; ia32_prefix_e * pewlk; if (new == NULL) new = malloc (sizeof (ia32_prefix)); memset (new, 0x00, sizeof (ia32_prefix)); for (pw = 0 ; pw < IA32_PREFIX_MAX ; ++pw) { for (pewlk = ia32_prefix_table ; pewlk->name != NULL ; ++pewlk) { if (pewlk->code != input[pw]) continue; if (pewlk->relact == RELACT_OVERRIDE) *PFX_ABS (new, pewlk->relptr) = pewlk->relval; else if (pewlk->relact == RELACT_COMBINE) *PFX_ABS (new, pewlk->relptr) |= pewlk->relval; new->prefix[pw] = pewlk; break; } if (pewlk->name == NULL) break; } new->prefix[pw] = NULL; new->length = pw; return (new); } ia32_opcode * ia32_decode_opcode (unsigned char *input, ia32_opcode *new, ia32_prefix *pfx) { int bp; /* byte pointer into opcode */ int mmx_gg = -1, fpu_d = -1, fpu_r = -1; int sflag = 0; /* has the s flag occured ? */ ia32_opcode_e * oel; /* helper variables for decoding */ int wide = 0; /* FIXME: do this to runtime with a cpu state structure */ int wide_cur = IA32_WIDTH_32, wide_addr_cur = IA32_WIDTH_32; int short_cur = IA32_WIDTH_8; /* try to locate the appropiate decoding structure from the opcode * table. if there is no matching one, bail out early. */ oel = ia32_decode_opcode_find (input); if (oel == NULL) return (NULL); if (new == NULL) new = malloc (sizeof (ia32_opcode)); memset (new, 0x00, sizeof (ia32_opcode)); new->opcode = oel; if (OD_TEST (oel->flags, OD_IMM)) { new->used |= OP_IMMEDIATE | OP_SOURCE; new->source_type = OP_TYPE_IMM; } if (OD_TEST (oel->flags, OD_JUMP)) new->used |= OP_JUMP; if (OD_TEST (oel->flags, OD_CONTROL)) new->used |= OP_CONTROL; /* when there are size prefixes, modify the operand and address size * attributes. XXX: the intel docs make a huge difference as to whether * operands or addressing is concerned, we share it in one flag (wide). */ if (pfx != NULL) { if (pfx->oper_size) wide_cur = IA32_WIDTH_16; if (pfx->addr_size) wide_addr_cur = IA32_WIDTH_16; } for (bp = 0 ; oel->opc[bp] != OD_END ; ++bp) { unsigned int oc; unsigned char ob; oc = oel->opc[bp]; ob = input[bp]; /* width flag (bit 0 or bit 3) */ if (OD_TEST (oc, OD_W)) new->wide = wide = OD_SET_COND (ob, OD_W_MASK); else if (OD_TEST (oc, OD_W3)) new->wide = wide = OD_SET_COND (ob, OD_W3_MASK); /* s sign-extension flag (bit 1) */ if (OD_TEST (oc, OD_S)) sflag = OD_SET_COND (ob, OD_S_MASK); /* direction flag (bit 1) */ if (OD_TEST (oc, OD_D)) new->reversed = OD_SET_COND (ob, OD_S_MASK); if (OD_TEST (oc, OD_GG)) mmx_gg = ob & OD_GG_MASK; /* tttn condition codes (bits 3210) */ if (OD_TEST (oc, OD_TTTN)) { new->used |= OP_COND; new->cond = ob & OD_TTTN_MASK; } /* low register encoded (bits 210) */ if (OD_TEST (oc, OD_LREG)) { /* when there is another hardcoded register, assume * this lreg to be the source, otherwise target */ if (OD_TEST (oel->flags, OD_REG_HARD_EAX)) { new->source_reg = ob & OD_LREG_MASK; new->source_type = OP_TYPE_REG; new->used |= OP_SOURCE; fprintf (stderr, "ia32: lreg to source\n"); } else { new->target_reg = ob & OD_LREG_MASK; new->target_type = OP_TYPE_REG; new->used |= OP_TARGET; } } if (OD_TEST (oc, OD_EEE)) { new->source_reg = (ob & OD_EEE_MASK) >> OD_EEE_SHIFT; new->used |= OP_SOURCE; if (OD_TEST (oel->flags, OD_CR)) { new->source_type = OP_TYPE_SPEC_CR; } else if (OD_TEST (oel->flags, OD_DR)) { new->source_type = OP_TYPE_SPEC_DR; } else { fprintf (stderr, "ia32: no special eee type given.\n"); } } /* FPU decoding * source_width is set later, after normal width propagation */ if (OD_TEST (oc, OD_FPU_STI)) { new->source_type = OP_TYPE_FPU; new->source_reg = ob & OD_FPU_STI_MASK; new->used |= OP_SOURCE; } if (OD_TEST (oc, OD_FPU_D)) fpu_d = (ob & OD_FPU_D_MASK) >> OD_FPU_D_SHIFT; if (OD_TEST (oc, OD_FPU_R)) fpu_r = (ob & OD_FPU_R_MASK) >> OD_FPU_R_SHIFT; /* modbyte encoding (bits 76, possible 543, possible 210) */ if (OD_TEST (oc, OD_MOD)) ia32_decode_opcode_mod (input, bp, oel, new, wide_cur, wide_addr_cur); /* for sreg3 we use the mod decoding facility and later make * up the register type. when we have a register-to-register * move, sreg3 is always the target (or source, but then it * will be reversed). for non-register transfers, it is the * register-type. XXX: note, that any sreg3 instruction must * have a OD_MOD at the same byte as the eee field for this * to work. */ if (OD_TEST (oc, OD_SREG3) && OD_TEST (oc, OD_MOD)) { /* register to register */ if ((ob & OD_MOD_MASK) == OD_MOD_MASK) { new->source_type = OP_TYPE_SPEC_SEG; new->source_width = IA32_WIDTH_16; new->target_width = wide_cur; } else { if (new->target_type == OP_TYPE_REG) { new->target_type = OP_TYPE_SPEC_SEG; } else if (new->source_type == OP_TYPE_REG) { new->source_type = OP_TYPE_SPEC_SEG; } new->source_width = new->target_width = IA32_SEG_SIZE; } /* second case, for more simpler instructions, such as push * and pop, which do not make use of modbytes. */ } else if (OD_TEST (oc, OD_SREG3) || OD_TEST (oc, OD_SREG2)) { new->used |= OP_TARGET; new->target_width = IA32_SEG_SIZE; new->target_type = OP_TYPE_SPEC_SEG; new->target_reg = (ob & (OD_TEST (oc, OD_SREG3) ? OD_SREG3_MASK : OD_SREG2_MASK)) >> OD_SREG3_SHIFT; } } if (OD_TEST (oel->flags, OD_FPU) == 0 && OD_TEST (oel->flags, OD_REG_HARD_EAX)) { new->target_type = OP_TYPE_REG; new->target_reg = IA32_REG_EAX; new->used |= OP_TARGET; } /* fix width of operands */ if (OD_TEST (oel->flags, OD_WIDTH_LOCK) == 0) { new->source_width = new->target_width = short_cur; if (OD_TEST (oel->flags, OD_WIDTH_16)) { wide_cur = IA32_WIDTH_16; /* XXX: kludge, we set wide to 1 to enforce setting * the length below */ wide = 1; } if (OD_TEST (oel->flags, OD_WIDTH_WIDE) || wide == 1) { new->target_width = wide_cur; if (sflag == 0 && OD_TEST (oel->flags, OD_WTONLY) == 0) new->source_width = wide_cur; } } if (OD_TEST (oel->flags, OD_FPU)) { if (new->source_type == OP_TYPE_FPU) new->source_width = IA32_FPU_SIZE; if (OD_TEST (oel->flags, OD_FPU_WITH_ST0)) { new->target_type = OP_TYPE_FPU; new->target_width = IA32_FPU_SIZE; new->target_reg = IA32_FPU_ST0; new->used |= OP_TARGET; } else if (OD_TEST (oel->flags, OD_WIDTH_FPU)) { new->target_width = IA32_FPU_SIZE; } if (fpu_d != -1) { new->target_type = OP_TYPE_FPU; new->target_width = IA32_FPU_SIZE; new->target_reg = (fpu_d == 0) ? IA32_FPU_ST0 : new->source_reg; new->used |= OP_TARGET; } if (OD_TEST (oel->flags, OD_FPU_WITH_ST0) && new->target_type == OP_TYPE_FPU && new->target_reg != IA32_FPU_ST0) { new->source_reg = IA32_FPU_ST0; } /* XXX: kludge. FPU instructions never operate on single bytes, * so this is a "fallthrough" case, were the memory * operation size is unknown (such as saving FPU state), and we * only want to print the memory reference, not its size */ if (new->target_type == OP_TYPE_MEMABS && new->target_width == IA32_FPU_BYTE) { new->target_width = 0; } /* R XOR d = 0 : destination OP source * R XOR d = 1 : source OP destination */ if (fpu_r != -1 && fpu_d != -1) new->reversed = fpu_r ^ fpu_d; } if (OD_TEST (oel->flags, OD_MMX)) { /* gg field encoding */ unsigned int mmx_sizes[] = { 8, 16, 32, 64 }; unsigned int mmx_length; /* get length depending on the instruction format: * * 1. if there is a gg field, decode length * 2. else fetch from instruction */ if (mmx_gg == -1) mmx_length = mmx_sizes[OD_GG_GET (oel->flags)]; else mmx_length = mmx_sizes[mmx_gg]; #ifdef TESTING printf ("\tmmx_length = %d, mmx_gg = %d, OD_GG_GET (oel->flags) = %d\n", mmx_length, mmx_gg, OD_GG_GET (oel->flags)); #endif new->target_width = mmx_length; if (new->target_type == OP_TYPE_REG && OD_TEST (oel->flags, OD_REGNOMMX) == 0) { new->target_type = OP_TYPE_SPEC_MMX; } new->source_width = mmx_length; if (new->source_type == OP_TYPE_REG) new->source_type = OP_TYPE_SPEC_MMX; if (OD_TEST (oel->flags, OD_GG_IN_LOW)) new->source_width = 2 * new->target_width; if (OD_TEST (oel->flags, OD_GG_IN_HI)) new->source_width = new->target_width / 2; } /* edx:eax combinations */ if (OD_TEST (oel->flags, OD_WIDTH_DWIDE)) new->target_width = 2 * wide_cur; /* decode the SIB byte (which can result in displacement modification) */ if (OD_TEST (new->used, OP_SIB)) { ia32_decode_opcode_sib (input, bp, new); bp += 1; } /* decode possible displacement after mod r/m or SIB byte * in case this is a immediate-target instruction (jump, call, ..) * instruct the displacement properly. also appears as explicit 16 bit * displacement in the enter instruction. also decode selectors. */ if (OD_TEST (oel->flags, OD_IMM_DISPL)) { new->used |= OP_DISPLACE; if (OD_TEST (oel->flags, OD_IMM_DISPL_8)) { new->displ_size = 8; } else if (OD_TEST (oel->flags, OD_IMM_DISPL_16)) { new->displ_size = 16; } else if (OD_TEST (oel->flags, OD_IMM_DISPL_WORD)) { new->displ_size = wide_addr_cur; } /* an immediate displacement has to belong either to the * source or destination operand */ if (OD_TEST (new->used, OP_TARGET) == 0) { new->used |= OP_TARGET; new->target_type = OP_TYPE_DISPL; /* new->target_width = new->displ_size; */ new->target_width = wide_cur; } else { new->used |= OP_SOURCE; new->source_type = OP_TYPE_MEM; /* new->source_width = new->displ_size; */ new->source_width = wide_cur; } } if (OD_TEST (new->used, OP_DISPLACE)) { new->displ_value = 0; bp += ia32_decode_value (&input[bp], new->displ_size, &new->displ_value); /* always extend displacements */ ia32_extend (1, &new->displ_value, new->displ_size); } /* immediate selector and offsets */ if (OD_TEST (oel->flags, OD_IMM_OFFSET)) { new->used |= OP_TARGET; new->target_type = OP_TYPE_OFFSET; new->target_width = new->imm_size = wide_cur; bp += ia32_decode_value (&input[bp], new->imm_size, &new->imm_value); } if (OD_TEST (oel->flags, OD_IMM_SELECT)) { unsigned int selector; new->used |= OP_TARGET | OP_SELECTOR; bp += ia32_decode_value (&input[bp], 16, &selector); new->selector = (unsigned short) selector; } if (OD_TEST (new->used, OP_IMMEDIATE)) { new->imm_value = 0; if (OD_TEST (oel->flags, OD_IMMSIZE_WORD)) { new->imm_size = wide_cur; } else { switch (OD_IMMSIZE_GET (oel->flags)) { case (OD_IMMSIZE_8): new->imm_size = IA32_WIDTH_8; break; case (OD_IMMSIZE_16): new->imm_size = IA32_WIDTH_16; break; case (OD_IMMSIZE_32): new->imm_size = IA32_WIDTH_32; break; default: new->imm_size = new->source_width; #ifdef TESTING fprintf (stderr, "imm_size from source: %d\n", new->imm_size); #endif break; } } bp += ia32_decode_value (&input[bp], new->imm_size, &new->imm_value); /* extend when there was a sign-extension flag */ ia32_extend (sflag, &new->imm_value, new->imm_size); } new->length = bp; /* XXX: there are cases (such as the bsf and bsr instructions, where * the order of registers is reversed by default. in that case, flip) */ if (OD_TEST (oel->flags, OD_REG12_REV)) new->reversed = (new->reversed == 0) ? 1 : 0; /* when the order was reversed, then swap source and target now. * let reversed bit stick, though, since source_* is always source, * and target_* always target (to the user of this function). so * we provide the extra information about the original encoding through * the reversed bit. */ if (new->reversed) { int source_used = OD_TEST (new->used, OP_SOURCE); if (OD_TEST (new->used, OP_TARGET)) new->used |= OP_SOURCE; else new->used &= ~OP_SOURCE; if (source_used) new->used |= OP_TARGET; else new->used &= ~OP_TARGET; #define swapui32(x,y) (x)^=(y);(y)^=(x);(x)^=(y); swapui32 (new->source_type, new->target_type); swapui32 (new->source_reg, new->target_reg); swapui32 (new->source_width, new->target_width); #undef swapui32 } if (OD_TEST (oel->flags, OD_WIDTH_LWIDE)) new->target_width = wide_cur; return (new); } unsigned int ia32_decode_value (unsigned char *input, unsigned int bits, unsigned int *value) { switch (bits) { case (32): *value = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); return (4); break; case (16): *value = input[0] | (input[1] << 8); return (2); break; case (8): *value = input[0]; return (1); break; default: return (0); } } void ia32_encode_value (unsigned char *output, unsigned int bits, unsigned int value) { switch (bits) { case (32): output[3] = (value >> 24) & 0xff; output[2] = (value >> 16) & 0xff; case (16): output[1] = (value >> 8) & 0xff; case (8): output[0] = value & 0xff; break; default: break; } return; } unsigned int ia32_has_immediate (ia32_instruction *inst, unsigned int *imm_size) { unsigned int imm_size_dummy; unsigned int pos; if (imm_size == NULL) imm_size = &imm_size_dummy; if (OD_TEST (inst->opc.used, OP_IMMEDIATE) == 0) return (0); *imm_size = inst->opc.imm_size; pos = inst->length; pos -= ia32_bit_to_byte (inst->opc.imm_size); assert (pos > 0 && pos < 16); return (pos); } unsigned int ia32_has_displacement (ia32_instruction *inst, unsigned int *displ_size) { unsigned int displ_size_dummy; unsigned int pos; if (displ_size == NULL) displ_size = &displ_size_dummy; if (OD_TEST (inst->opc.used, OP_DISPLACE) == 0) return (0); *displ_size = inst->opc.displ_size; pos = inst->length; if (OD_TEST (inst->opc.used, OP_IMMEDIATE)) pos -= ia32_bit_to_byte (inst->opc.imm_size); pos -= ia32_bit_to_byte (inst->opc.displ_size); assert (pos > 0 && pos < 16); return (pos); } unsigned int ia32_extend_signed (unsigned int value, unsigned int value_bits) { unsigned int res = 0; unsigned int sign = 0; if (value_bits == 32) return (value); /* do a simple sign extension */ sign = value & (1 << (value_bits - 1)); if (sign != 0) res -= 1; res &= ~((1 << value_bits) - 1); res |= ((1 << value_bits) - 1) & value; return (res); } unsigned int ia32_eflags_mask_from_cond (unsigned int cond) { unsigned int mask = 0; assert ((cond & ~0x0f) == 0); switch (cond >> 1) { case (IA32_COND_O / 2): mask = IA32_EFLAGS_OF; break; case (IA32_COND_B / 2): mask = IA32_EFLAGS_CF; break; case (IA32_COND_E / 2): mask = IA32_EFLAGS_ZF; break; case (IA32_COND_BE / 2): mask = IA32_EFLAGS_CF | IA32_EFLAGS_ZF; break; case (IA32_COND_S / 2): mask = IA32_EFLAGS_SF; break; case (IA32_COND_P / 2): mask = IA32_EFLAGS_PF; break; case (IA32_COND_L / 2): mask = IA32_EFLAGS_SF | IA32_EFLAGS_OF; break; case (IA32_COND_LE / 2): mask = IA32_EFLAGS_ZF | IA32_EFLAGS_SF | IA32_EFLAGS_OF; break; default: break; } return (mask); } int ia32_eflags_eval (unsigned int eflags, unsigned int cond) { int result = 0; int negate = cond & 0x01; struct { unsigned int cf : 1, pf : 1, zf : 1, sf : 1, of : 1; } es; es.cf = (eflags & IA32_EFLAGS_CF) ? 1 : 0; es.pf = (eflags & IA32_EFLAGS_PF) ? 1 : 0; es.zf = (eflags & IA32_EFLAGS_ZF) ? 1 : 0; es.sf = (eflags & IA32_EFLAGS_SF) ? 1 : 0; es.of = (eflags & IA32_EFLAGS_OF) ? 1 : 0; cond >>= 1; switch (cond) { case (IA32_COND_O / 2): result = es.of; break; case (IA32_COND_B / 2): result = es.cf; break; case (IA32_COND_E / 2): result = es.zf; break; case (IA32_COND_BE / 2): result = es.cf | es.zf; break; case (IA32_COND_S / 2): result = es.sf; break; case (IA32_COND_P / 2): result = es.pf; break; case (IA32_COND_L / 2): result = es.sf ^ es.of; break; case (IA32_COND_LE / 2): result = (es.sf ^ es.of) | es.zf; break; default: fprintf (stderr, "ia32_eflags_eval: invalid condition code\n"); _exit (1); break; } if (negate) result = (result == 1) ? 0 : 1; return (result); } unsigned int ia32_bit_to_byte (unsigned int bits) { switch (bits) { case (32): return (4); case (16): return (2); case (8): return (1); default: fprintf (stderr, "ia32_bit_to_byte: invalid bitcount\n"); break; } return (0); } /*** private functions */ static void ia32_extend (int sflag, unsigned int *value, unsigned int size) { int hi_bit; unsigned int or_mask; if (sflag == 0 || size == 32) return; hi_bit = (*value >> (size - 1)) & 0x01; or_mask = (unsigned int) -1; or_mask -= (1 << size) - 1; if (hi_bit) *value |= or_mask; return; } /* ia32_decode_opcode_sib * * decode the SIB byte found at input[bp] into the opcode structure `opc'. * * return in any case */ static void ia32_decode_opcode_sib (unsigned char *input, unsigned int bp, ia32_opcode *opc) { unsigned char sib = input[bp]; opc->sibbyte = sib; opc->scale = (sib & 0xc0) >> 6; opc->index_reg = (sib & 0x38) >> 3; opc->base_reg = sib & 0x07; /* special case: no scaled index used (index = 0x04) */ if (opc->index_reg == 0x04) { opc->index = 0; opc->index_reg = 0; } else opc->index = 1; /* special case: mod was 00, sib base is 101 (ebp normally) * then: no base used, but a disp32 (see, ia32 vol.2, pp 36-660) */ if (((opc->modbyte & 0xc0) >> 6) == 0x0 && opc->base_reg == 0x5) { opc->base = 0; opc->base_reg = 0; opc->used |= OP_DISPLACE; opc->displ_size = 32; } else opc->base = 1; return; } /* ia32_decode_opcode_mod * * decode the mod (possibly reg, possibly r/m) byte found at input[bp], with * the opcode structure `oel' into the decode structure `opc' * * return in any case */ static void ia32_decode_opcode_mod (unsigned char *input, unsigned int bp, ia32_opcode_e *oel, ia32_opcode *opc, unsigned int reg_width, unsigned int addr_width) { /* FIXME: assume 32 bit for now * TODO: add a cpu-state structure, to support 32/16 bit decisions and * such */ unsigned char modbyte = input[bp]; unsigned int mod; unsigned int reg, rm = modbyte & OD_RM_MASK; unsigned int oc = oel->opc[bp]; opc->modbyte = modbyte; if (OD_TEST (oc, OD_REG)) { reg = (modbyte & OD_REG_MASK) >> OD_REG_SHIFT; opc->used |= OP_SOURCE; opc->source_type = OP_TYPE_REG; opc->source_reg = reg; opc->source_width = reg_width; } mod = (modbyte & 0xc0) >> 6; /* mod = 11 = register to register */ if (mod == 0x3) { opc->used |= OP_TARGET; opc->target_type = OP_TYPE_REG; opc->target_reg = rm; opc->target_width = reg_width; /* there is no sib */ return; } /* 0, 8 or 32 bit displacements plus reg indirect, without SIB */ opc->used |= OP_TARGET; opc->target_type = OP_TYPE_MEMREG; opc->target_reg = rm; opc->target_width = addr_width; /* switch three addressing modes, disp0, disp8 and disp32 * displacement size equals address size */ switch (mod) { case (0x00): opc->displ_size = 0; if (rm == IA32_MOD00_RM_DIRECT) { opc->displ_size = addr_width; opc->used |= OP_DISPLACE; opc->target_type = OP_TYPE_MEMABS; opc->target_reg = 0; } break; case (0x01): opc->displ_size = 8; opc->used |= OP_DISPLACE; break; case (0x02): opc->displ_size = addr_width; opc->used |= OP_DISPLACE; break; } /* in case this is an SIB mod r/m byte, mark it as such */ if (rm == IA32_RM_SIB) { opc->used |= OP_SIB; opc->target_type = OP_TYPE_MEM; opc->target_reg = 0; } return; } /* ia32_decode_opcode_find * * try to find an appropiate opcode structure matching the opcode found at * `input'. * * return NULL on failure * return pointer to opcode description structure on success */ static ia32_opcode_e * ia32_decode_opcode_find (unsigned char *input) { unsigned int n; ia32_opcode_e * opcwlk; for (opcwlk = ia32_opcode_table ; #ifdef IA32_OP_NUMERIC opcwlk->opcode_num != 0 ; #else opcwlk->name != NULL ; #endif ++opcwlk) { for (n = 0 ; opcwlk->opc[n] != OD_END ; ++n) { if ((input[n] & OD_CMASK_GET (opcwlk->opc[n])) != OD_CVAL_GET (opcwlk->opc[n])) break; } if (opcwlk->opc[n] == OD_END) return (opcwlk); } return (NULL); } ia32_opcode_e * ia32_opcode_find_bynum (unsigned int opcode) { unsigned int in; for (in = 0 ; ia32_opcode_table[in].opcode_num != 0 ; ++in) { if (ia32_opcode_table[in].opcode_num == opcode) return (&ia32_opcode_table[in]); } return (NULL); } unsigned int ia32_instruction_count (unsigned int opcode) { unsigned int in, count = 0; for (in = 0 ; ia32_opcode_table[in].opcode_num != 0 ; ++in) { if (ia32_opcode_table[in].opcode_num != opcode) continue; count += 1; } return (count); } unsigned int ia32_instruction_length (unsigned char *mem) { ia32_instruction * inst, inst_s; inst = ia32_decode_instruction (mem, &inst_s); assert (inst != NULL); return (inst->length); } unsigned char * ia32_instruction_advance (unsigned char *mem, unsigned int count) { ia32_instruction * inst, inst_s; while (count > 0) { inst = ia32_decode_instruction (mem, &inst_s); assert (inst != NULL); mem += inst->length; count -= 1; } return (mem); } int ia32_opnum_index (unsigned int opcode) { unsigned int idx; /* TODO: put a binary search in here ;) */ for (idx = 0 ; ia32_opnum_table[idx] != 0 ; ++idx) { if (ia32_opnum_table[idx] == opcode) return (idx); } return (-1); } int ia32_opcode_has_immediate (unsigned int opcode, unsigned int min_size, unsigned int max_size) { ia32_opcode_e * opcwlk; unsigned int fix_size; for (opcwlk = ia32_opcode_table ; opcwlk->opcode_num != 0 ; ++opcwlk) { if (opcwlk->opcode_num != opcode) continue; if (OD_TEST (opcwlk->flags, OD_IMM) == 0) continue; switch (OD_IMMSIZE_GET (opcwlk->flags)) { case (OD_IMMSIZE_8): fix_size = IA32_WIDTH_8; break; case (OD_IMMSIZE_16): fix_size = IA32_WIDTH_16; break; default: case (OD_IMMSIZE_32): fix_size = IA32_WIDTH_32; break; } if (fix_size >= min_size && fix_size <= max_size) return (1); } return (0); } #ifndef IA32_OP_NUMERIC const char * ia32_opnum_name (unsigned int opnum) { ia32_opcode_e * opcwlk; for (opcwlk = ia32_opcode_table ; opcwlk->name != NULL ; ++opcwlk) { if (ia32_opnum_table[opnum] == opcwlk->opcode_num) return (opcwlk->name); } return (NULL); } #endif #ifndef IA32_OP_NUMERIC /*** OUTPUT functions */ int ia32_print (ia32_instruction *inst) { char buf[128]; ia32_sprint (inst, buf, sizeof (buf)); return (printf ("%s\n", buf)); } unsigned int ia32_sprint (ia32_instruction *inst, char *buf, unsigned int buf_len) { char tbuf[256]; ia32_opcode * opc = &inst->opc; int used_immediate = 0; char * condstr[] = { "o", "no", "b,nae", "nb,ae", "e,z", "ne,nz", "be,na", "nbe,a", "s", "ns", "p,pe", "np,po", "l,nge", "nl,ge", "le,ng", "nle,g" }; memset (tbuf, '\x00', sizeof (tbuf)); sprintf (tbuf, "%s", opc->opcode->name); if (OD_TEST (opc->used, OP_COND)) sprintf (tbuf + strlen (tbuf), "(%s)", condstr[opc->cond]); /* when this is a no-operand instruction with a width flag, show this */ if (OD_TEST (opc->used, OP_TARGET) == 0 && OD_TEST (opc->used, OP_SOURCE) == 0) { unsigned int owlk; for (owlk = 0 ; opc->opcode->opc[owlk] != OD_END ; ++owlk) { if (OD_TEST (opc->opcode->opc[owlk], OD_W)) sprintf (tbuf + strlen (tbuf), "(%s)", (opc->wide) ? "d" : "b"); } } /* print target operand */ if (OD_TEST (opc->used, OP_TARGET)) { sprintf (tbuf + strlen (tbuf), "\t"); ia32_sprint_operand (tbuf, inst, opc->target_type, opc->target_width, opc->target_reg); /* when we used the immediate value, mark it for following code */ if (opc->target_type == OP_TYPE_IMM || opc->target_type == OP_TYPE_OFFSET) { used_immediate = 1; } } /* print source operand */ if (OD_TEST (opc->used, OP_SOURCE)) { if (OD_TEST (opc->used, OP_TARGET)) sprintf (tbuf + strlen (tbuf), ", "); else sprintf (tbuf + strlen (tbuf), "\t"); ia32_sprint_operand (tbuf, inst, opc->source_type, opc->source_width, opc->source_reg); if (opc->source_type == OP_TYPE_IMM) used_immediate = 1; } if (OD_TEST (opc->used, OP_IMMEDIATE) && used_immediate == 0) sprintf (tbuf + strlen (tbuf), ", (%u)0x%08x", opc->imm_size, opc->imm_value); snprintf (buf, buf_len, "%s", tbuf); buf[buf_len - 1] = '\0'; return (strlen (buf)); } /* ia32_sprint operand * * merged code of source and target operand output functionality. print one * operand of the instruction `inst' to `tbuf', without boundary checking. the * operand to be printed is specified by `type', `width' and `reg', which can * be source_* or target_* respectivly. * * return in any case */ static void ia32_sprint_operand (char *tbuf, ia32_instruction *inst, unsigned int type, unsigned int width, unsigned int reg) { char ** regs = ia32_regs_wide; char * scalestr[] = { "", "*2", "*4", "*8" }; char * opersize = NULL; ia32_opcode * opc = &inst->opc; switch (width) { case (IA32_WIDTH_SPECIAL): opersize = ""; break; case (IA32_WIDTH_8): opersize = "byte"; regs = ia32_regs_small; break; case (IA32_WIDTH_16): opersize = "word"; regs = ia32_regs_half; break; case (IA32_WIDTH_32): opersize = "dword"; regs = ia32_regs_wide; break; case (IA32_WIDTH_64): opersize = "qword"; break; case (IA32_WIDTH_80): opersize = "tword"; break; default: fprintf (stderr, "invalid operand width: %u\n", width); return; } /* conventionally, print operand size when it may be ambiguous */ switch (type) { /* not for fixed registers */ case (OP_TYPE_REG): case (OP_TYPE_SPEC_CR): case (OP_TYPE_SPEC_DR): case (OP_TYPE_SPEC_SEG): case (OP_TYPE_FPU): case (OP_TYPE_IMM): break; default: sprintf (tbuf + strlen (tbuf), "%s", opersize); if (strlen (opersize) != 0) sprintf (tbuf + strlen (tbuf), " "); break; } if (OD_TEST (opc->used, OP_SELECTOR)) sprintf (tbuf + strlen (tbuf), "0x%04hx:", opc->selector); /* output main operand */ switch (type) { case (OP_TYPE_SPEC_CR): sprintf (tbuf + strlen (tbuf), "%s", ia32_regs_spec_cr[reg]); break; case (OP_TYPE_SPEC_DR): sprintf (tbuf + strlen (tbuf), "%s", ia32_regs_spec_dr[reg]); break; case (OP_TYPE_SPEC_SEG): sprintf (tbuf + strlen (tbuf), "%s", ia32_regs_spec_seg[reg]); break; case (OP_TYPE_SPEC_MMX): sprintf (tbuf + strlen (tbuf), "%s", ia32_regs_spec_mmx[reg]); break; case (OP_TYPE_FPU): sprintf (tbuf + strlen (tbuf), "st%d", reg); break; case (OP_TYPE_REG): sprintf (tbuf + strlen (tbuf), "%s", regs[reg]); break; case (OP_TYPE_MEMABS): if (OD_TEST (opc->used, OP_DISPLACE)) { sprintf (tbuf + strlen (tbuf), "[0x%08x]", opc->displ_value); } else { fprintf (stderr, "error, OP_TYPE_MEMABS, no displ\n"); return; } break; case (OP_TYPE_MEMREG): if (inst->pfx.addr_size) regs = ia32_regs_half_addr; else regs = ia32_regs_wide; sprintf (tbuf + strlen (tbuf), "[%s", regs[reg]); if (OD_TEST (opc->used, OP_DISPLACE)) { sprintf (tbuf + strlen (tbuf), " + (%u)0x%08x]", opc->displ_size, opc->displ_value); } else sprintf (tbuf + strlen (tbuf), "]"); break; case (OP_TYPE_MEM): /* print base, index, scale, displacement */ regs = ia32_regs_wide; sprintf (tbuf + strlen (tbuf), "["); if (opc->base) sprintf (tbuf + strlen (tbuf), "%s", regs[opc->base_reg]); if (opc->base && opc->index) sprintf (tbuf + strlen (tbuf), " + "); if (opc->index) sprintf (tbuf + strlen (tbuf), "%s%s", regs[opc->index_reg], scalestr[opc->scale]); if (OD_TEST (opc->used, OP_DISPLACE)) { sprintf (tbuf + strlen (tbuf), "%s(%u)0x%08x", (opc->base || opc->index) ? " + " : "", opc->displ_size, opc->displ_value); } sprintf (tbuf + strlen (tbuf), "]"); break; /* an immediate target means something special, such as a port * number. */ case (OP_TYPE_IMM): { unsigned int imm_val = 0xffffffff; switch (opc->imm_size) { case (IA32_WIDTH_8): imm_val = (signed char) opc->imm_value; break; case (IA32_WIDTH_16): imm_val = (signed short int) opc->imm_value; break; case (IA32_WIDTH_32): imm_val = (signed int) opc->imm_value; break; default: break; } sprintf (tbuf + strlen (tbuf), "(%u)0x%08x", opc->imm_size, imm_val); /* TODO: find a better way to signal this back */ break; } case (OP_TYPE_DISPL): sprintf (tbuf + strlen (tbuf), "(%u)0x%08x", opc->displ_size, opc->displ_value); break; case (OP_TYPE_OFFSET): sprintf (tbuf + strlen (tbuf), "0x%08x", opc->imm_value); break; default: fprintf (stderr, "invalid operand type\n"); return; break; } return; } #endif #ifdef TESTING int main (int argc, char *argv[]) { ia32_instruction inst_s; ia32_instruction * inst; int n; unsigned int amount; FILE * bfp; unsigned char buf[4096]; ia32_df_set df; printf ("ia32 decoder "IA32_VERSION"\n"); /* open a binary file "test" with ia32 instructions, decode them and * try to output the pretty disassembling */ bfp = fopen ("test", "rb"); if (bfp == NULL) { perror ("fopen"); exit (EXIT_FAILURE); } amount = fread (buf, 1, sizeof (buf), bfp); n = 0; do { inst = ia32_decode_instruction (&buf[n], &inst_s); if (inst == NULL) { fprintf (stderr, "failed to decode\n"); exit (EXIT_FAILURE); } if (OD_TEST (inst->opc.used, OP_CONTROL)) printf ("CT "); else printf (" "); ia32_df_set_from_instruction (inst, &df); ia32_df_set_print (&df); printf (" 0x%04x:\t", n); ia32_print (inst); n += inst->length; } while (n < amount); exit (EXIT_SUCCESS); } #endif