fis-gtm/sr_x86_64/emit_code_sp.c

1019 lines
30 KiB
C

/****************************************************************
* *
* 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 <sys/types.h>
#include "gtm_string.h"
#include <errno.h>
#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 */