1020 lines
30 KiB
C
1020 lines
30 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2007, 2012 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 "list_file.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 */
|