/**************************************************************** * * * Copyright 2007, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include #include "gtm_fcntl.h" #include "gtm_stat.h" #include "gtm_stdio.h" #include "opcode.h" #include "mdq.h" #include "rtnhdr.h" #include "vxi.h" #include "vxt.h" #include "cgp.h" #include "compiler.h" #include "emit_code.h" GBLDEF struct emit_base_info emit_base_info; #define SET_OBPT_STR(str, len) \ memcpy(obpt, str, len); \ obpt += len; #define SET_OBPT_INT4(value) \ obpt = i2asc(obpt, value); #define SET_OBPT_INT8(value) \ obpt = i2asclx(obpt, value); /* Possible values for instruction Byte's Meaning */ #define one_byte_opcode 0 #define two_byte_opcode 1 #define modrm_sib_bytes 2 #define one_byte_immediate 3 #define double_word_immediate 4 #define quad_word_immediate 5 #define one_byte_offset 6 #define double_word_offset 7 #define quad_word_offset 8 /* Now Define The Instruction Structure .... */ #define grp_prefix 4 /* flags to be used by "operand_class" */ #define undefined_class 0 #define register_class 1 #define memory_class 2 #define immediate_class 3 struct instruction_mnemonics { char *opcode_mnemonic; char opcode_suffix; short reg_rip; char reg_prefix; short num_operands; /* Some instructions have one, some two and some None operands.. one operand will be taken in source.. num_operands = 4 would mean that modrm reg_opcode will denote opcode extension */ short source_operand_class; char *source_operand_reg; short destination_operand_class; char *destination_operand_reg; long offset; short has_immediate; long immediate; } instruction; #undef I386_OP #define I386_OP(opcode, operand, num) #opcode , LITDEF char *mnemonic_list[] = { #include "i386_ops.h" }; LITDEF char *mnemonic_list_2b[] = { #include "i386_ops_2b.h" }; LITDEF char *mnemonic_list_g1[] = { #include "i386_ops_g1.h" }; LITDEF char *mnemonic_list_g2[] = { #include "i386_ops_g2.h" }; LITDEF char *mnemonic_list_g3[] = { #include "i386_ops_g3.h" }; LITDEF char *mnemonic_list_g4[] = { #include "i386_ops_g4.h" }; LITDEF char *mnemonic_list_g5[] = { #include "i386_ops_g5.h" }; /* Structures and unions for different Bytes .. */ struct Rex { short Base; short Index; short Reg; short Word64; } rex_prefix; static modrm_byte_type modrm_byte; static sib_byte_type sib_byte; GBLREF int call_4lcldo_variant; GBLREF int jmp_offset; /* Offset to jump target */ GBLREF char cg_phase; /* code generation phase */ GBLREF char code_buf[]; GBLREF int code_idx; GBLREF unsigned char *obpt; /* output buffer index */ GBLREF unsigned char outbuf[]; GBLREF int curr_addr; GBLDEF int instidx, prev_idx; #define REG_RIP 16 LITDEF char *register_list[] = { "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", "8", "9", "10", "11", "12", "13", "14", "15", "RIP" }; GBLREF boolean_t force_32; /* We want to generate 4 byte offets even for an offset lesser than 8bits long, to keep things consistent between CGP_APPROX_ADDR phase and CGP_MACHINE phase */ int x86_64_arg_reg(int indx) { switch(indx) { case 0: return I386_REG_RDI ; case 1: return I386_REG_RSI ; case 2: return I386_REG_RDX ; case 3: return I386_REG_RCX ; case 4: return I386_REG_R8 ; case 5: return I386_REG_R9 ; default: GTMASSERT ; break ; } /* Control will never reach here */ return - 1 ; } void emit_jmp(uint4 branch_op, short **instp, int reg) /* Note that the 'reg' parameter is ignored */ { assert (jmp_offset != 0); force_32 = TRUE; jmp_offset -= code_idx * SIZEOF(code_buf[0]); /* size of this particular instruction */ switch (cg_phase) { #ifdef DEBUG case CGP_ASSEMBLY: *obpt++ = 'x'; *obpt++ = '^'; *obpt++ = '0'; *obpt++ = 'x'; obpt += i2hex_nofill(jmp_offset, (uchar_ptr_t)obpt, 8); *obpt++ = ','; *obpt++ = ' '; /***** WARNING - FALL THRU *****/ #endif case CGP_ADDR_OPT: case CGP_APPROX_ADDR: case CGP_MACHINE: assert (**instp == VXT_JMP); *instp += 1; assert (**instp == 1); *instp += 1; if (jmp_offset == 0) { /*code_buf[code_idx++] = I386_INS_NOP__; */ } else if (((jmp_offset - 2) >= -128 && (jmp_offset - 2) <= 127 && JMP_LONG_INST_SIZE != call_4lcldo_variant) && (force_32 == FALSE)) { jmp_offset -= 2; switch (branch_op) { case GENERIC_OPCODE_BEQ: code_buf[code_idx++] = I386_INS_JZ_Jb; break; case GENERIC_OPCODE_BGE: code_buf[code_idx++] = I386_INS_JNL_Jb; break; case GENERIC_OPCODE_BGT: code_buf[code_idx++] = I386_INS_JNLE_Jb; break; case GENERIC_OPCODE_BLE: code_buf[code_idx++] = I386_INS_JLE_Jb; break; case GENERIC_OPCODE_BLT: code_buf[code_idx++] = I386_INS_JL_Jb; break; case GENERIC_OPCODE_BNE: code_buf[code_idx++] = I386_INS_JNZ_Jb; break; case GENERIC_OPCODE_BR: assert(0 == call_4lcldo_variant || BRB_INST_SIZE == call_4lcldo_variant); code_buf[code_idx++] = I386_INS_JMP_Jb; break; default: GTMASSERT; break; } code_buf[code_idx++] = jmp_offset & 0xff; } else { if (branch_op == GENERIC_OPCODE_BR) { assert(0 == call_4lcldo_variant || JMP_LONG_INST_SIZE == call_4lcldo_variant || force_32); jmp_offset -= SIZEOF(int4) + 1; code_buf[code_idx++] = I386_INS_JMP_Jv; } else { jmp_offset -= SIZEOF(int4) + 2; code_buf[code_idx++] = I386_INS_Two_Byte_Escape_Prefix; switch (branch_op) { case GENERIC_OPCODE_BEQ: code_buf[code_idx++] = I386_INS_JZ_Jv; break; case GENERIC_OPCODE_BGE: code_buf[code_idx++] = I386_INS_JNL_Jv; break; case GENERIC_OPCODE_BGT: code_buf[code_idx++] = I386_INS_JNLE_Jv; break; case GENERIC_OPCODE_BLE: code_buf[code_idx++] = I386_INS_JLE_Jv; break; case GENERIC_OPCODE_BLT: code_buf[code_idx++] = I386_INS_JL_Jv; break; case GENERIC_OPCODE_BNE: code_buf[code_idx++] = I386_INS_JNZ_Jv; break; default: GTMASSERT; break; } } *((int4 *)&code_buf[code_idx]) = jmp_offset; code_idx += SIZEOF(int4); } } force_32 = FALSE; } void emit_base_offset(int base_reg, int offset) { memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); emit_base_info.rex = REX_OP; /* All instructions that we generate need to set the REX prefix */ emit_base_info.modrm_byte_set = 1; /* * if (offset == 0) * emit_base_info.modrm_byte.modrm.mod = I386_MOD32_BASE; * else */ if ((offset >= -128 && offset <= 127) && force_32 == FALSE) emit_base_info.modrm_byte.modrm.mod = I386_MOD32_BASE_DISP_8; else emit_base_info.modrm_byte.modrm.mod = I386_MOD32_BASE_DISP_32; if (((base_reg & 0x7) == I386_REG_ESP ) || ((base_reg & 0x7) == I386_REG_EBP && offset == 0)) { emit_base_info.modrm_byte.modrm.r_m = I386_REG_SIB_FOLLOWS; /* Refer to the comment in emit_code_sp.h before SET_REX_PREFIX */ emit_base_info.sib_byte.sib.base = base_reg & 0x7; /* Need only the bottom 3 bits */ SET_REX_PREFIX(0, REX_B, base_reg) emit_base_info.sib_byte.sib.ss = I386_SS_TIMES_1; emit_base_info.sib_byte.sib.index = I386_REG_NO_INDEX; emit_base_info.sib_byte_set = 1; } else { emit_base_info.modrm_byte.modrm.r_m = base_reg & 0x7; /* Need only the bottom 3 bits */ SET_REX_PREFIX(0, REX_B, base_reg) } if ((offset >= -128 && offset <= 127) && force_32 == FALSE) { emit_base_info.offset8 = offset & 0xff; emit_base_info.offset8_set = 1; } else { emit_base_info.offset32 = offset; emit_base_info.offset32_set = 1; } } #ifdef DEBUG void reset_instruction() { rex_prefix.Base = 0; rex_prefix.Index = 0; rex_prefix.Reg = 0; rex_prefix.Word64 = 0; instruction.opcode_mnemonic = NULL; instruction.opcode_suffix = 'l'; instruction.reg_rip = FALSE; instruction.reg_prefix = 'e'; instruction.num_operands = 0; instruction.source_operand_class = undefined_class; instruction.source_operand_reg = NULL; instruction.destination_operand_class = undefined_class; instruction.destination_operand_reg = NULL; instruction.offset = 0; instruction.has_immediate = 0; instruction.immediate = 0; } /* Now the functions which will print the actual instruction(mnemonics).. */ void print_source_operand() { switch(instruction.source_operand_class) { case undefined_class : GTMASSERT; break; case register_class : assert(instruction.source_operand_reg != NULL); *obpt++ = '%'; *obpt++ = instruction.reg_prefix; SET_OBPT_STR(instruction.source_operand_reg, STRLEN(instruction.source_operand_reg)) break; case memory_class : assert(instruction.destination_operand_class != memory_class); if (instruction.source_operand_reg != NULL) { SET_OBPT_INT4(instruction.offset); *obpt++ = '('; *obpt++ = '%'; *obpt++ = instruction.reg_prefix; SET_OBPT_STR(instruction.source_operand_reg, STRLEN(instruction.source_operand_reg)) *obpt++ = ')'; } else { SET_OBPT_INT4(instruction.offset); } break; case immediate_class : *obpt++ = '0'; *obpt++ = 'x'; SET_OBPT_INT8(instruction.immediate); break; default : GTMASSERT; } } void print_destination_operand() { switch(instruction.destination_operand_class) { case undefined_class : GTMASSERT; break; case register_class : assert(instruction.destination_operand_reg != NULL); *obpt++ = '%'; *obpt++ = instruction.reg_prefix; SET_OBPT_STR(instruction.destination_operand_reg, STRLEN(instruction.destination_operand_reg)) break; case memory_class : assert(instruction.source_operand_class != memory_class); if (instruction.destination_operand_reg != NULL) { SET_OBPT_INT4(instruction.offset); *obpt++ = '('; *obpt++ = '%'; *obpt++ = instruction.reg_prefix; SET_OBPT_STR(instruction.destination_operand_reg, STRLEN(instruction.destination_operand_reg)) *obpt++ = ')'; } else { SET_OBPT_INT4(instruction.offset); } break; case immediate_class : *obpt++ = '0'; *obpt++ = 'x'; SET_OBPT_INT8(instruction.immediate); break; default : GTMASSERT; } } void print_instruction() { list_chkpage(); obpt = &outbuf[0]; memset(obpt, SP, ASM_OUT_BUFF); obpt += 10; i2hex((curr_addr - SIZEOF(rhdtyp)), obpt, 8); curr_addr += (instidx - prev_idx); obpt += 10; for( ; prev_idx < instidx; prev_idx++) { i2hex(code_buf[prev_idx], obpt, 2); obpt += 2; } obpt += 10; *obpt++ = '\n'; *obpt++ = '\t'; *obpt++ = '\t'; *obpt++ = '\t'; *obpt++ = '\t'; *obpt++ = '\t'; *obpt++ = '\t'; assert( instruction.opcode_mnemonic != NULL ); SET_OBPT_STR(instruction.opcode_mnemonic, STRLEN(instruction.opcode_mnemonic)) *obpt++ = instruction.opcode_suffix; *obpt++ = '\t'; instruction.num_operands = (instruction.num_operands > grp_prefix) ? \ (instruction.num_operands - grp_prefix) : instruction.num_operands; switch (instruction.num_operands) { case 0 : break; case 1 : /* single operand assumed to be in the source operand only.. */ assert(instruction.destination_operand_class == undefined_class); print_source_operand(); break; case 2 : print_source_operand(); *obpt++ = ','; print_destination_operand(); break; default : GTMASSERT; } /* Now reset the instruction structure */ emit_eoi(); reset_instruction(); } void set_memory_reg() { instruction.reg_prefix = 'r'; if (instruction.source_operand_class == memory_class) instruction.source_operand_reg =(char *) register_list[modrm_byte.modrm.r_m + 8 * rex_prefix.Base]; else if (instruction.destination_operand_class == memory_class) instruction.destination_operand_reg =(char *) register_list[modrm_byte.modrm.r_m + 8 * rex_prefix.Base]; /* Printing of RIP has to be handled differently */ if (instruction.reg_rip) if (instruction.source_operand_class == memory_class) instruction.source_operand_reg =(char *) register_list[REG_RIP]; else if (instruction.destination_operand_class == memory_class) instruction.destination_operand_reg =(char *) register_list[REG_RIP]; else GTMASSERT; } void set_register_reg() { if (instruction.source_operand_class == register_class) instruction.source_operand_reg =(char *) register_list[modrm_byte.modrm.reg_opcode + 8 * rex_prefix.Reg]; else if (instruction.destination_operand_class == register_class) instruction.destination_operand_reg = (char *)register_list[modrm_byte.modrm.reg_opcode + 8 * rex_prefix.Reg]; } void clear_memory_reg() { if (instruction.source_operand_class == memory_class) instruction.source_operand_reg = NULL; else if (instruction.destination_operand_class == memory_class) instruction.destination_operand_reg = NULL; } void format_machine_inst() { short next_inst_byte_meaning = one_byte_opcode; int i, tot_inst_len = 0; unsigned char inst_curr_byte; short lock_prefix_seen; short rep_e_prefix_seen; short repne_prefix_seen; short operand_size_prefix_seen; short address_size_prefix_seen; /* Start Parsing the Instruction Buffer */ instidx = 0; prev_idx = 0; while(instidx < code_idx) { switch(next_inst_byte_meaning) { /* Can be a Prefix, or opcode !! */ case one_byte_opcode : inst_curr_byte = code_buf[instidx++]; instruction.opcode_mnemonic =(char *) mnemonic_list[inst_curr_byte]; switch(inst_curr_byte) { /* If Prefixes, set corresponding Flag and continue... */ case I386_INS_Two_Byte_Escape_Prefix : next_inst_byte_meaning = two_byte_opcode; break; case I386_INS_REX_PREFIX_None : case I386_INS_REX_PREFIX__B : case I386_INS_REX_PREFIX__X : case I386_INS_REX_PREFIX__X_B : case I386_INS_REX_PREFIX__R : case I386_INS_REX_PREFIX__R_B : case I386_INS_REX_PREFIX__R_X : case I386_INS_REX_PREFIX__R_X_B : case I386_INS_REX_PREFIX__W : case I386_INS_REX_PREFIX__W_B : case I386_INS_REX_PREFIX__W_X : case I386_INS_REX_PREFIX__W_X_B : case I386_INS_REX_PREFIX__W_R : case I386_INS_REX_PREFIX__W_R_B : case I386_INS_REX_PREFIX__W_R_X : case I386_INS_REX_PREFIX__W_R_X_B : rex_prefix.Base = (inst_curr_byte & 0x01); rex_prefix.Index = (inst_curr_byte & 0x02) ? 1 : 0; rex_prefix.Reg = (inst_curr_byte & 0x04) ? 1 : 0; rex_prefix.Word64 = (inst_curr_byte & 0x08) ? 1 : 0; if (rex_prefix.Word64) { instruction.opcode_suffix = 'q'; instruction.reg_prefix = 'r'; } else { instruction.opcode_suffix = 'l'; instruction.reg_prefix = 'e'; } break; case I386_INS_LOCK_Prefix : lock_prefix_seen = TRUE; break; case I386_INS_REPNE_Prefix : repne_prefix_seen = TRUE; break; case I386_INS_REP_E_Prefix : rep_e_prefix_seen = TRUE; break; case I386_INS_Operand_Size_Prefix : operand_size_prefix_seen = TRUE; break; case I386_INS_Address_Size_Prefix : address_size_prefix_seen = TRUE; break; /* now the instructions having Opcode Extension in the modrm.reg field.. */ case I386_INS_Grp1_Ev_Iv_Prefix : case I386_INS_Grp2_Ev_Iv_Prefix : instruction.destination_operand_class = memory_class; instruction.source_operand_class = immediate_class; instruction.has_immediate = double_word_immediate; instruction.num_operands = grp_prefix + 2; next_inst_byte_meaning = modrm_sib_bytes; break; case I386_INS_Grp1_Eb_Ib_Prefix : case I386_INS_Grp1_Ev_Ib_Prefix : case I386_INS_Grp2_Eb_Ib_Prefix : instruction.opcode_suffix = 'b'; instruction.destination_operand_class = memory_class; instruction.source_operand_class = immediate_class; instruction.has_immediate = one_byte_immediate; instruction.num_operands = grp_prefix + 2; next_inst_byte_meaning = modrm_sib_bytes; break; case I386_INS_Grp2_Eb_1_Prefix : case I386_INS_Grp2_Ev_1_Prefix : case I386_INS_Grp2_Eb_CL_Prefix : case I386_INS_Grp2_Ev_CL_Prefix : next_inst_byte_meaning = modrm_sib_bytes; GTMASSERT; /* Not taking care of this case for now - not used!! */ break; case I386_INS_Grp3_Eb_Prefix : modrm_byte.byte = code_buf[instidx + 1]; if (modrm_byte.modrm.reg_opcode < 2) { instruction.destination_operand_class = memory_class; instruction.source_operand_class = immediate_class; instruction.has_immediate = one_byte_immediate; instruction.num_operands = grp_prefix + 2; } else { instruction.source_operand_class = memory_class; instruction.opcode_suffix = 'b'; instruction.num_operands = grp_prefix + 1; } next_inst_byte_meaning = modrm_sib_bytes; break; case I386_INS_Grp3_Ev_Prefix : modrm_byte.byte = code_buf[instidx + 1]; if (modrm_byte.modrm.reg_opcode < 2) { instruction.destination_operand_class = memory_class; instruction.source_operand_class = immediate_class; instruction.has_immediate = double_word_immediate; instruction.num_operands = grp_prefix + 2; } else { instruction.source_operand_class = memory_class; instruction.num_operands = grp_prefix + 1; } next_inst_byte_meaning = modrm_sib_bytes; break; case I386_INS_Grp4_Prefix : case I386_INS_Grp5_Prefix : instruction.source_operand_class = memory_class; instruction.num_operands = grp_prefix + 1; next_inst_byte_meaning = modrm_sib_bytes; break; /* Now the instructions : Mainly those who have been used in the code generation in .c * files. */ /* Ins :: OPCODE */ case (I386_INS_PUSH_eAX + I386_REG_RAX) : case (I386_INS_PUSH_eAX + I386_REG_RCX) : case (I386_INS_PUSH_eAX + I386_REG_RDX) : case (I386_INS_PUSH_eAX + I386_REG_RBX) : case (I386_INS_PUSH_eAX + I386_REG_RSP) : case (I386_INS_PUSH_eAX + I386_REG_RBP) : case (I386_INS_PUSH_eAX + I386_REG_RSI) : case (I386_INS_PUSH_eAX + I386_REG_RDI) : instruction.opcode_suffix = ' '; instruction.reg_prefix = 'r'; instruction.num_operands = 1; instruction.source_operand_class = register_class; instruction.source_operand_reg = (char *)\ register_list[8 * rex_prefix.Base + inst_curr_byte - I386_INS_PUSH_eAX]; print_instruction(); break; case (I386_INS_POP_eAX + I386_REG_RAX) : case (I386_INS_POP_eAX + I386_REG_RCX) : case (I386_INS_POP_eAX + I386_REG_RDX) : case (I386_INS_POP_eAX + I386_REG_RBX) : case (I386_INS_POP_eAX + I386_REG_RSP) : case (I386_INS_POP_eAX + I386_REG_RBP) : case (I386_INS_POP_eAX + I386_REG_RSI) : case (I386_INS_POP_eAX + I386_REG_RDI) : instruction.opcode_suffix = ' '; instruction.reg_prefix = 'r'; instruction.num_operands = 1; instruction.source_operand_class = register_class; instruction.source_operand_reg =(char *) \ register_list[8 * rex_prefix.Base + inst_curr_byte - I386_INS_POP_eAX]; print_instruction(); break; case I386_INS_NOP__ : case I386_INS_MOVSB_Xb_Yb : print_instruction(); break; /* Ins :: OPCODE disp8(%rip) */ case I386_INS_JZ_Jb : case I386_INS_JNL_Jb : case I386_INS_JNLE_Jb : case I386_INS_JLE_Jb : case I386_INS_JL_Jb : case I386_INS_JMP_Jb : case I386_INS_JNZ_Jb : instruction.opcode_suffix = ' '; instruction.reg_rip = TRUE; instruction.source_operand_class = memory_class; set_memory_reg(); instruction.num_operands = 1; next_inst_byte_meaning = one_byte_offset; break; /* Ins :: OPCODE disp32(%rip) */ case I386_INS_CALL_Jv : case I386_INS_JMP_Jv : instruction.opcode_suffix = ' '; instruction.reg_rip = TRUE; instruction.source_operand_class = memory_class; set_memory_reg(); instruction.num_operands = 1; next_inst_byte_meaning = double_word_offset; break; /* Ins :: OPCODE IMM8 */ case I386_INS_PUSH_Ib : instruction.opcode_suffix = 'b'; instruction.num_operands = 1; instruction.source_operand_class = immediate_class; next_inst_byte_meaning = one_byte_immediate; break; /* Ins :: OPCODE IMM32/64 */ case I386_INS_PUSH_Iv : instruction.opcode_suffix = 'l'; instruction.num_operands = 1; instruction.source_operand_class = immediate_class; if (rex_prefix.Word64 == 0) next_inst_byte_meaning = double_word_immediate; else next_inst_byte_meaning = quad_word_immediate; break; case I386_INS_CMP_eAX_Iv : instruction.num_operands = 2; instruction.destination_operand_class = register_class; instruction.destination_operand_reg =(char *) register_list[I386_REG_RAX]; instruction.source_operand_class = immediate_class; if (rex_prefix.Word64 == 0) next_inst_byte_meaning = double_word_immediate; else next_inst_byte_meaning = quad_word_immediate; break; case (I386_INS_MOV_eAX + I386_REG_RAX) : case (I386_INS_MOV_eAX + I386_REG_RCX) : case (I386_INS_MOV_eAX + I386_REG_RDX) : case (I386_INS_MOV_eAX + I386_REG_RBX) : case (I386_INS_MOV_eAX + I386_REG_RSP) : case (I386_INS_MOV_eAX + I386_REG_RBP) : case (I386_INS_MOV_eAX + I386_REG_RSI) : case (I386_INS_MOV_eAX + I386_REG_RDI) : instruction.num_operands = 2; instruction.destination_operand_class = register_class; instruction.destination_operand_reg =(char *) \ register_list[8 * rex_prefix.Base + inst_curr_byte - I386_INS_MOV_eAX]; instruction.source_operand_class = immediate_class; if (rex_prefix.Word64 == 0) next_inst_byte_meaning = double_word_immediate; else next_inst_byte_meaning = quad_word_immediate; break; /* Ins :: OPCODE ModRM (Reg, Mem)/(No_IMM) */ case I386_INS_LEA_Gv_M : case I386_INS_MOV_Gv_Ev : case I386_INS_CMP_Gv_Ev : case I386_INS_XOR_Gv_Ev : case I386_INS_MOVSXD_Gv_Ev : instruction.num_operands = 2; instruction.source_operand_class = memory_class; instruction.destination_operand_class = register_class; next_inst_byte_meaning = modrm_sib_bytes; break; /* Ins :: OPCODE ModRM (Mem, Reg)/(No_IMM) */ case I386_INS_MOV_Ev_Gv : instruction.num_operands = 2; instruction.source_operand_class = register_class; instruction.destination_operand_class = memory_class; next_inst_byte_meaning = modrm_sib_bytes; break; /* Ins :: OPCODE ModRM (Mem, IMM) */ case I386_INS_MOV_Ev_Iv : instruction.num_operands = 2; instruction.destination_operand_class = memory_class; instruction.has_immediate = double_word_immediate; instruction.source_operand_class = immediate_class; next_inst_byte_meaning = modrm_sib_bytes; break; default : GTMASSERT; } break; case two_byte_opcode : inst_curr_byte = code_buf[instidx++]; switch(inst_curr_byte) { case I386_INS_JO_Jv : case I386_INS_JNO_Jv : case I386_INS_JB_Jv : case I386_INS_JNB_Jv : case I386_INS_JZ_Jv : case I386_INS_JNZ_Jv : case I386_INS_JBE_Jv : case I386_INS_JNBE_Jv : case I386_INS_JS_Jv : case I386_INS_JNS_Jv : case I386_INS_JP_Jv : case I386_INS_JNP_Jv : case I386_INS_JL_Jv : case I386_INS_JNL_Jv : case I386_INS_JLE_Jv : case I386_INS_JNLE_Jv : instruction.reg_rip = TRUE; instruction.opcode_mnemonic =(char *) mnemonic_list_2b[inst_curr_byte]; instruction.source_operand_class = memory_class; set_memory_reg(); instruction.num_operands = 1; next_inst_byte_meaning = double_word_offset; break; default : GTMASSERT; } break; case modrm_sib_bytes : inst_curr_byte = code_buf[instidx++]; modrm_byte.byte = inst_curr_byte; if (instruction.num_operands >= grp_prefix) /* Means reg_opcode = op ext */ { switch((unsigned char) code_buf[instidx - 2]) { case I386_INS_Grp1_Eb_Ib_Prefix : case I386_INS_Grp1_Ev_Iv_Prefix : case I386_INS_Grp1_Ev_Ib_Prefix : instruction.opcode_mnemonic =(char *) \ mnemonic_list_g1[modrm_byte.modrm.reg_opcode]; break; case I386_INS_Grp2_Eb_Ib_Prefix : case I386_INS_Grp2_Ev_Iv_Prefix : case I386_INS_Grp2_Eb_1_Prefix : case I386_INS_Grp2_Ev_1_Prefix : case I386_INS_Grp2_Eb_CL_Prefix : case I386_INS_Grp2_Ev_CL_Prefix : instruction.opcode_mnemonic = (char *)\ mnemonic_list_g2[modrm_byte.modrm.reg_opcode]; break; case I386_INS_Grp3_Eb_Prefix : case I386_INS_Grp3_Ev_Prefix : instruction.opcode_mnemonic =(char *) \ mnemonic_list_g3[modrm_byte.modrm.reg_opcode]; break; case I386_INS_Grp4_Prefix : instruction.opcode_mnemonic =(char *) \ mnemonic_list_g4[modrm_byte.modrm.reg_opcode]; break; case I386_INS_Grp5_Prefix : instruction.opcode_suffix = ' '; instruction.opcode_mnemonic =(char *) \ mnemonic_list_g5[modrm_byte.modrm.reg_opcode]; break; } } else set_register_reg(); set_memory_reg(); /* Handle the SIB byte ! */ if ((modrm_byte.modrm.mod != I386_MOD32_REGISTER) && (modrm_byte.modrm.r_m == I386_REG_SIB_FOLLOWS)) { inst_curr_byte = code_buf[instidx++]; sib_byte.byte = inst_curr_byte; /* Assert that the SIB is not used for any complex addressing but is actually a dummy */ assert((sib_byte.sib.base == I386_REG_ESP) || (sib_byte.sib.base == I386_REG_EBP)); assert(sib_byte.sib.ss == I386_SS_TIMES_1); assert(sib_byte.sib.index == I386_REG_NO_INDEX); if (instruction.source_operand_class == memory_class) instruction.source_operand_reg = (char *) register_list[sib_byte.sib.base + 8 * rex_prefix.Base]; else if (instruction.destination_operand_class == memory_class) instruction.destination_operand_reg = (char *) register_list[sib_byte.sib.base + 8 * rex_prefix.Base]; switch(modrm_byte.modrm.mod) { case I386_MOD32_BASE : if (sib_byte.sib.base == I386_REG_disp32_NO_BASE) { clear_memory_reg(); next_inst_byte_meaning = double_word_offset; } else if (instruction.has_immediate) next_inst_byte_meaning = instruction.has_immediate; else { print_instruction(); next_inst_byte_meaning = one_byte_opcode; } break; case I386_MOD32_BASE_DISP_8 : next_inst_byte_meaning = one_byte_offset; break; case I386_MOD32_BASE_DISP_32 : next_inst_byte_meaning = double_word_offset; break; default : GTMASSERT; } } else /* No SIB */ { switch(modrm_byte.modrm.mod) { case I386_MOD32_BASE : if (modrm_byte.modrm.r_m == I386_REG_disp32_FROM_RIP) { instruction.reg_rip = TRUE; set_memory_reg(); next_inst_byte_meaning = double_word_offset; } else { instruction.offset = 0; if (instruction.has_immediate) next_inst_byte_meaning = instruction.has_immediate; else { print_instruction(); next_inst_byte_meaning = one_byte_opcode; } } break; case I386_MOD32_BASE_DISP_8 : next_inst_byte_meaning = one_byte_offset; break; case I386_MOD32_BASE_DISP_32 : next_inst_byte_meaning = double_word_offset; break; case I386_MOD32_REGISTER : if (instruction.source_operand_class == memory_class) instruction.source_operand_class = register_class; else if (instruction.destination_operand_class == memory_class) instruction.destination_operand_class = register_class; if (instruction.has_immediate) next_inst_byte_meaning = instruction.has_immediate; else { print_instruction(); next_inst_byte_meaning = one_byte_opcode; } break; default : GTMASSERT; } } break; case one_byte_immediate : instruction.immediate = code_buf[instidx++]; print_instruction(); next_inst_byte_meaning = one_byte_opcode; break; case double_word_immediate : instruction.immediate = *((int *)&code_buf[instidx]); instidx += 4; print_instruction(); next_inst_byte_meaning = one_byte_opcode; break; case quad_word_immediate : instruction.immediate = *((long *)&code_buf[instidx]); instidx += 8; print_instruction(); next_inst_byte_meaning = one_byte_opcode; break; case one_byte_offset : instruction.offset = code_buf[instidx++]; if (instruction.has_immediate) next_inst_byte_meaning = instruction.has_immediate; else { print_instruction(); next_inst_byte_meaning = one_byte_opcode; } break; case double_word_offset : instruction.offset = *((int *)&code_buf[instidx]); instidx += 4; if (instruction.has_immediate) next_inst_byte_meaning = instruction.has_immediate; else { print_instruction(); next_inst_byte_meaning = one_byte_opcode; } break; case quad_word_offset : instruction.offset = *((long *)&code_buf[instidx]); instidx += 8; if (instruction.has_immediate) next_inst_byte_meaning = instruction.has_immediate; else { print_instruction(); next_inst_byte_meaning = one_byte_opcode; } break; default : GTMASSERT; } } } #endif /* DEBUG */