#include "codegenv2.h"
#include <time.h>
#include "globals.h"
#include "parser.h"
#include "segment.h"
#include "extern.h"
#include "fixup.h"
#include "fastpass.h"
#include "myassert.h"
#include "types.h"
#include "macro.h"
#include "listing.h"
#include "fpfixup.h"
#define OutputCodeByte( x ) OutputByte( x )
const char szNullStr[] = { "<NULL>" };
struct Mem_Def* MemTable = NULL;
struct Instr_Def* InstrHash[16384];
#ifdef _WIN32
#else
#define INT_MIN (-2147483647 - 1)
#define INT_MAX 2147483647
#define UINT_MAX 0xffffffff
#define UCHAR_MAX 0xff
#endif
#include "MemTable32.h"
#include "MemTable64.h"
#include "InstrTableV2.h"
static unsigned int hash(const uint_8* data, int size)
{
uint_64 fnv_basis = 14695981039346656037;
uint_64 register fnv_prime = 1099511628211;
uint_64 h = fnv_basis;
int cnt = 0;
for (cnt = 0; cnt < size; cnt++) {
h ^= *data++;
h *= fnv_prime;
}
return((((h >> 49) ^ h) & 0x3fff));
}
struct Instr_Def* AllocInstruction()
{
return malloc(sizeof(struct Instr_Def));
}
void InsertInstruction(struct Instr_Def* pInstruction, uint_32 hash)
{
struct Instr_Def* curPtr = NULL;
curPtr = InstrHash[hash];
if (curPtr == NULL)
{
InstrHash[hash] = pInstruction;
return;
}
while (curPtr->next != NULL)
{
curPtr = curPtr->next;
}
curPtr->next = pInstruction;
}
uint_32 GenerateInstrHash(struct Instr_Def* pInstruction)
{
uint_8 hashBuffer[32];
int len = 0;
char* pDst = (char*)&hashBuffer;
strcpy(pDst, pInstruction->mnemonic);
for (int i = 0; i < strlen(pInstruction->mnemonic); i++)
{
hashBuffer[i] = tolower(hashBuffer[i]);
}
len += strlen(pInstruction->mnemonic);
pDst += len;
*(pDst + 0) = pInstruction->operand_types[0];
*(pDst + 1) = pInstruction->operand_types[1];
*(pDst + 2) = pInstruction->operand_types[2];
*(pDst + 3) = pInstruction->operand_types[3];
*(pDst + 4) = pInstruction->operand_types[4];
len += 4;
pDst += 4;
return hash(&hashBuffer, len);
}
void BuildInstructionTable(void)
{
uint_32 hash = 0;
struct Instr_Def* pInstrTbl = &InstrTableV2;
uint_32 i = 0;
uint_32 instrCount = sizeof(InstrTableV2) / sizeof(struct Instr_Def);
memset(InstrHash, 0, sizeof(InstrHash));
for (i = 0; i < instrCount; i++, pInstrTbl++)
{
struct Instr_Def* pInstr = AllocInstruction();
memcpy(pInstr, pInstrTbl, sizeof(struct Instr_Def));
hash = GenerateInstrHash(pInstr);
InsertInstruction(pInstr, hash);
}
}
enum op_type DemoteOperand(enum op_type op) {
enum op_type ret = op;
if (op == R8_AL)
ret = R8;
else if (op == R16_AX)
ret = R16;
else if (op == R32_EAX)
ret = R32;
else if (op == R64_RAX)
ret = R64;
else if (op == R8_CL)
ret = R8;
else if (op == R16_CX)
ret = R16;
else if (op == R32_ECX)
ret = R32;
else if (op == R64_RCX)
ret = R64;
else if (op == R16_DX)
ret = R16;
else if (op == M8 || op == M16 || op == M32 || op == M48 || op == M64 || op == M80 || op == M128 || op == M256 || op == M512)
ret = M_ANY;
return(ret);
}
enum op_type MatchOperand(struct code_info* CodeInfo, struct opnd_item op, struct expr opExpr) {
enum op_type result;
switch (op.type)
{
case OP_M:
result = M_ANY;
break;
case OP_M08:
result = M8;
break;
case OP_M16:
result = M16;
break;
case OP_M32:
result = M32;
break;
case OP_M64:
result = M64;
break;
case OP_M48:
result = M48;
break;
case OP_M80:
result = M80;
break;
case OP_M128:
result = M128;
break;
case OP_M256:
result = M256;
break;
case OP_M512:
result = M512;
break;
case OP_SR86:
result = R_SEG;
break;
case OP_SR:
result = R_SEG;
break;
case OP_SR386:
result = R_SEGE;
break;
case OP_RSPEC:
result = R_RIP;
if (strcasecmp(opExpr.base_reg->string_ptr, "cr0") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "cr2") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "cr3") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "cr4") == 0)
{
result = R_CR;
}
else if (strcasecmp(opExpr.base_reg->string_ptr, "cr8") == 0)
{
result = R_CR8;
}
else if (strcasecmp(opExpr.base_reg->string_ptr, "dr0") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr1") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr2") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr3") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr4") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr5") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr6") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr7") == 0)
{
result = R_DR;
}
break;
case OP_K:
result = R_K;
break;
case OP_RIP:
result = R_RIP;
if (strcasecmp(opExpr.base_reg->string_ptr, "cr0") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "cr2") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "cr3") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "cr4") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "cr8") == 0)
{
result = R_CR;
}
else if (strcasecmp(opExpr.base_reg->string_ptr, "cr8") == 0)
{
result = R_CR8;
}
else if (strcasecmp(opExpr.base_reg->string_ptr, "dr0") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr1") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr2") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr3") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr4") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr5") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr6") == 0 ||
strcasecmp(opExpr.base_reg->string_ptr, "dr7") == 0)
{
result = R_DR;
}
break;
case OP_AL:
result = R8_AL;
break;
case OP_CL:
result = R8_CL;
break;
case OP_AX:
result = R16_AX;
break;
case OP_DX:
result = R16_DX;
break;
case OP_EAX:
result = R32_EAX;
break;
case OP_RAX:
result = R64_RAX;
break;
case OP_NONE:
result = OP_N;
break;
case OP_R8:
result = R8;
if (opExpr.base_reg->tokval == T_AL)
result = R8_AL;
if (opExpr.base_reg->tokval >= T_AH && opExpr.base_reg->tokval <= T_BH)
result = R8H;
else if (opExpr.base_reg->tokval >= T_R8B && opExpr.base_reg->tokval <= T_R15B)
result = R8E;
else if (opExpr.base_reg->tokval >= T_SPL && opExpr.base_reg->tokval <= T_DIL)
result = R8U;
break;
case OP_R16:
result = R16;
if (opExpr.base_reg->tokval == T_AX)
result = R16_AX;
else if (opExpr.base_reg->tokval >= T_R8W && opExpr.base_reg->tokval <= T_R15W)
result = R16E;
break;
case OP_R32:
result = R32;
if (opExpr.base_reg->tokval == T_EAX)
result = R32_EAX;
else if (opExpr.base_reg->tokval >= T_R8D && opExpr.base_reg->tokval <= T_R15D)
result = R32E;
break;
case OP_R64:
result = R64;
if (opExpr.base_reg->tokval == T_RAX)
result = R64_RAX;
else if (opExpr.base_reg->tokval >= T_R8 && opExpr.base_reg->tokval <= T_R15)
result = R64E;
break;
case OP_I8:
if (CodeInfo->token >= T_RCL && CodeInfo->token <= T_SHR){
if (CodeInfo->opnd[OPND2].data32l == 1)
result = IMM_1;
else
result = IMM8;
}
else
result = IMM8;
break;
case OP_I16:
result = IMM16;
break;
case OP_I32:
result = IMM32;
break;
case OP_I48:
result = IMM48;
break;
case OP_I64:
result = IMM64;
break;
case OP_XMM:
result = R_XMM;
break;
case OP_YMM:
result = R_YMM;
break;
case OP_ZMM:
result = R_ZMM;
break;
case OP_MMX:
result = MMX64;
break;
case OP_ST_REG:
result = R_STI;
break;
case OP_ST:
result = R_ST;
break;
}
return result;
}
struct Instr_Def* LookupInstruction(struct Instr_Def* instr, bool memReg, unsigned char encodeMode, int srcRegNo, int dstRegNo, struct code_info* CodeInfo)
{
uint_32 hash;
struct Instr_Def* pInstruction = NULL;
bool matched = FALSE;
hash = GenerateInstrHash(instr);
pInstruction = InstrHash[hash];
while (pInstruction != NULL)
{
if (strcasecmp(pInstruction->mnemonic, instr->mnemonic) == 0 &&
pInstruction->operand_types[0] == instr->operand_types[0] &&
pInstruction->operand_types[1] == instr->operand_types[1] &&
pInstruction->operand_types[2] == instr->operand_types[2] &&
pInstruction->operand_types[3] == instr->operand_types[3] &&
(pInstruction->validModes & encodeMode) != 0)
{
if (memReg && ((pInstruction->flags & NO_MEM_REG) != 0))
goto nextInstr;
if ((((uint_32)pInstruction->flags & (uint_32)SRCHDSTL) != 0) && ((srcRegNo <= 7 && dstRegNo > 7) || (srcRegNo <= 7 && dstRegNo <= 7) || (srcRegNo > 7 && dstRegNo > 7) || CodeInfo->evex_flag))
goto nextInstr;
if (broadflags) {
if (CodeInfo->token == T_VCVTPD2PS || CodeInfo->token == T_VCVTTPD2DQ) {
if ((pInstruction->op_elements == 2) && (broadflags == 0x10)) {
if (broadflags == pInstruction->op_size)
;
}
else if ((pInstruction->op_elements == 4) && (broadflags == 0x20)) {
if (broadflags == pInstruction->op_size)
;
}
else if ((pInstruction->op_elements == 8) && (broadflags == 0x30)) {
if (pInstruction->op_size == 0X40)
;
}
else goto nextInstr;
}
}
if (pInstruction->group == GP4) {
if (ModuleInfo.Ofssize == USE32)
matched = TRUE;
else
goto nextInstr;
}
else
matched = TRUE;
break;
}
nextInstr:
pInstruction = pInstruction->next;
}
if (!matched)
pInstruction = NULL;
return pInstruction;
}
bool Require_OPND_Size_Override(struct Instr_Def* instr, struct code_info* CodeInfo)
{
if (instr->useOSO == OP_SIZE_OVERRIDE)
{
if (instr->op_size == 2 && (ModuleInfo.Ofssize == USE32 || ModuleInfo.Ofssize == USE64))
return TRUE;
if (instr->op_size == 4 && ModuleInfo.Ofssize == USE16)
return TRUE;
}
return FALSE;
}
bool Require_ADDR_Size_Override(struct Instr_Def* instr, struct code_info* CodeInfo)
{
return FALSE;
}
bool IsValidInCPUMode(struct Instr_Def* instr)
{
bool result = TRUE;
unsigned char cpuModes = instr->validModes;
if (ModuleInfo.Ofssize != USE64 && cpuModes == X64)
result = FALSE;
if (ModuleInfo.Ofssize == USE64 && (cpuModes & X64) == 0)
result = FALSE;
if ((instr->cpu & P_PM) > (ModuleInfo.curr_cpu & P_PM))
result = FALSE;
return result;
}
unsigned char GetRegisterNo(struct asm_tok* regTok)
{
unsigned char regNo = 17;
if (regTok)
{
if (regTok->tokval >= T_RAX && regTok->tokval <= T_RIP)
regNo = (unsigned char)(regTok->tokval - T_RAX);
else if (regTok->tokval >= T_EAX && regTok->tokval <= T_EDI)
regNo = (unsigned char)(regTok->tokval - T_EAX);
else if (regTok->tokval >= T_R8D && regTok->tokval <= T_R15D)
regNo = (unsigned char)((regTok->tokval - T_R8D) + 8);
else if (regTok->tokval >= T_R8W && regTok->tokval <= T_R15W)
regNo = (unsigned char)((regTok->tokval - T_R8W) + 8);
else if (regTok->tokval >= T_AL && regTok->tokval <= T_BH)
regNo = (unsigned char)(regTok->tokval - T_AL);
else if (regTok->tokval >= T_R8B && regTok->tokval <= T_R15B)
regNo = (unsigned char)((regTok->tokval - T_R8B) + 8);
else if (regTok->tokval >= T_AX && regTok->tokval <= T_DI)
regNo = (unsigned char)(regTok->tokval - T_AX);
else if (regTok->tokval >= T_MM0 && regTok->tokval <= T_MM7)
regNo = (unsigned char)(regTok->tokval - T_MM0);
else if (regTok->tokval >= T_XMM0 && regTok->tokval <= T_XMM7)
regNo = (unsigned char)(regTok->tokval - T_XMM0);
else if (regTok->tokval >= T_XMM8 && regTok->tokval <= T_XMM15)
regNo = (unsigned char)((regTok->tokval - T_XMM8) + 8);
else if (regTok->tokval >= T_XMM16 && regTok->tokval <= T_XMM23)
regNo = (unsigned char)((regTok->tokval - T_XMM16) + 16);
else if (regTok->tokval >= T_XMM24 && regTok->tokval <= T_XMM31)
regNo = (unsigned char)((regTok->tokval - T_XMM24) + 24);
else if (regTok->tokval >= T_YMM0 && regTok->tokval <= T_YMM7)
regNo = (unsigned char)(regTok->tokval - T_YMM0);
else if (regTok->tokval >= T_YMM8 && regTok->tokval <= T_YMM15)
regNo = (unsigned char)((regTok->tokval - T_YMM8) + 8);
else if (regTok->tokval >= T_YMM16 && regTok->tokval <= T_YMM23)
regNo = (unsigned char)((regTok->tokval - T_YMM16) + 16);
else if (regTok->tokval >= T_YMM24 && regTok->tokval <= T_YMM31)
regNo = (unsigned char)((regTok->tokval - T_YMM24) + 24);
else if (regTok->tokval >= T_ZMM0 && regTok->tokval <= T_ZMM7)
regNo = (unsigned char)(regTok->tokval - T_ZMM0);
else if (regTok->tokval >= T_ZMM8 && regTok->tokval <= T_ZMM31)
regNo = (unsigned char)((regTok->tokval - T_ZMM8) + 8);
else if (regTok->tokval >= T_K0 && regTok->tokval <= T_K7)
regNo = (unsigned char)(regTok->tokval - T_K0);
else
{
switch (regTok->tokval)
{
case T_SPL:
regNo = 4;
break;
case T_BPL:
regNo = 5;
break;
case T_SIL:
regNo = 6;
break;
case T_DIL:
regNo = 7;
break;
case T_CR0:
regNo = 0;
break;
case T_CR2:
regNo = 2;
break;
case T_CR3:
regNo = 3;
break;
case T_CR4:
regNo = 4;
break;
case T_CR8:
regNo = 8;
break;
case T_DR0:
regNo = 0;
break;
case T_DR1:
regNo = 1;
break;
case T_DR2:
regNo = 2;
break;
case T_DR3:
regNo = 3;
break;
case T_DR6:
regNo = 6;
break;
case T_DR7:
regNo = 7;
break;
case T_CS:
regNo = 1;
break;
case T_DS:
regNo = 3;
break;
case T_ES:
regNo = 0;
break;
case T_FS:
regNo = 4;
break;
case T_GS:
regNo = 5;
break;
case T_SS:
regNo = 2;
break;
case T_ST:
regNo = 0;
break;
}
}
}
return regNo;
}
unsigned char BuildModRM(unsigned char modRM, struct Instr_Def* instr, struct expr opnd[4], bool* needModRM, bool* needSIB, bool isVEX)
{
int sourceIdx = 1;
if (isVEX && (instr->vexflags & VEX_DUP_NDS) == 0 && (instr->vexflags & VEX_2OPND) == 0 && (instr->vexflags & VEX_3RD_OP) == 0)
sourceIdx = 2;
if (instr->flags & F_MODRM)
{
*needModRM |= TRUE;
if (instr->flags & OPCODE_EXT)
{
modRM |= (instr->opcode[(int)instr->opcode_bytes]) << 3;
}
if (instr->flags & F_MODRM_REG && instr->op_dir == REG_DST)
{
modRM |= (GetRegisterNo(opnd[0].base_reg) & 0x07) << 3;
}
else if (instr->flags & F_MODRM_REG && instr->op_dir == RM_DST)
{
modRM |= (GetRegisterNo(opnd[sourceIdx].base_reg) & 0x07) << 3;
}
if (instr->flags & F_MODRM_RM && instr->op_dir == REG_DST)
{
modRM |= (GetRegisterNo(opnd[sourceIdx].base_reg) & 0x07);
}
else if (instr->flags & F_MODRM_RM && instr->op_dir == RM_DST)
{
modRM |= (GetRegisterNo(opnd[0].base_reg) & 0x07);
}
}
return modRM;
}
unsigned char BuildREX(unsigned char RexByte, struct Instr_Def* instr, struct expr opnd[4])
{
if (((uint_32)instr->flags & (uint_32)REX) != 0)
{
RexByte |= 0x40;
if ((instr->flags & (uint_32)REXB) != 0)
RexByte |= 0x01;
if ((instr->flags & (uint_32)REXX) != 0)
RexByte |= 0x02;
if ((instr->flags & (uint_32)REXR) != 0)
RexByte |= 0x04;
if ((instr->flags & (uint_32)REXW) != 0)
RexByte |= 0x08;
}
else if (((uint_32)instr->flags & (uint_32)EREX) != 0)
{
if (instr->op_dir == REG_DST)
{
if (opnd[0].base_reg && GetRegisterNo(opnd[0].base_reg) > 7)
RexByte |= 0x44;
if (opnd[instr->srcidx].base_reg && GetRegisterNo(opnd[instr->srcidx].base_reg) > 7)
RexByte |= 0x41;
}
else
{
if (opnd[0].base_reg && GetRegisterNo(opnd[0].base_reg) > 7)
RexByte |= 0x41;
if (opnd[instr->srcidx].base_reg && GetRegisterNo(opnd[instr->srcidx].base_reg) > 7)
RexByte |= 0x44;
}
}
else if ((uint_32)(instr->flags & (uint_32)REXP_MEM) != 0)
{
if (ModuleInfo.Ofssize != USE64)
{
EmitError(SIGN64_PROMOTION_NOT_POSSIBLE);
}
if (SizeFromMemtype(opnd[instr->memOpnd].mem_type, ModuleInfo.Ofssize, opnd[instr->memOpnd].type) == 8)
RexByte |= 0x48;
}
return RexByte;
}
void BuildVEX(bool* needVex, unsigned char* vexSize, unsigned char* vexBytes, struct Instr_Def* instr, struct expr opnd[4], bool needB, bool needX, uint_32 opCount)
{
unsigned char VEXl = 0;
unsigned char VEXpp = 0;
unsigned char VEXwe = 0;
unsigned char VEXvvvv = 0;
unsigned char VEXr = 1;
unsigned char VEXb = 1;
unsigned char VEXx = 1;
unsigned char VEXmmmmm = 0;
*needVex = TRUE;
*vexSize = 0;
if ((instr->vexflags & VEX_3RD_OP) != 0)
VEXvvvv = GetRegisterNo(opnd[2].base_reg);
else if ((instr->vexflags & VEX_NDS) != 0)
VEXvvvv = GetRegisterNo(opnd[1].base_reg);
else if ((instr->vexflags & VEX_DDS) != 0)
VEXvvvv = GetRegisterNo(opnd[2].base_reg);
else if ((instr->vexflags & VEX_NDD) != 0)
VEXvvvv = GetRegisterNo(opnd[0].base_reg);
if ((instr->vexflags & VEX_DUP_NDS) != 0)
{
EmitWarn(1, AVX_REQUIRES_THREE_REGISTERS);
VEXvvvv = GetRegisterNo(opnd[0].base_reg);
}
if ((instr->vexflags & VEX_66) != 0)
VEXpp = 0x01;
else if ((instr->vexflags & VEX_F3) != 0)
VEXpp = 0x02;
else if ((instr->vexflags & VEX_F2) != 0)
VEXpp = 0x03;
if (instr->op_size == 16)
VEXl = 0;
else if (instr->op_size == 32)
VEXl = 1;
if ((instr->vexflags & VEX_W0) != 0)
VEXwe = 0;
else if ((instr->vexflags & VEX_W1) != 0)
{
VEXwe = 1;
*vexSize = 3;
}
if ((instr->vexflags & VEX_0F38) != 0 || (instr->vexflags & VEX_0F3A) != 0)
* vexSize = 3;
if ((instr->vexflags & VEX_0F) != 0)
VEXmmmmm = 1;
else if ((instr->vexflags & VEX_0F38) != 0)
VEXmmmmm = 2;
else if ((instr->vexflags & VEX_0F3A) != 0)
VEXmmmmm = 3;
if ((instr->vexflags & VEX_R) != 0)
VEXr = 0;
if ((instr->vexflags & VEX_X) != 0 || needX)
VEXx = 0;
if ((instr->vexflags & VEX_B) != 0 || needB)
VEXb = 0;
if (instr->op_dir == REG_DST)
{
if (opnd[0].base_reg && GetRegisterNo(opnd[0].base_reg) > 7)
VEXr = 0;
if (opnd[instr->srcidx].base_reg && !opnd[instr->srcidx].indirect && GetRegisterNo(opnd[instr->srcidx].base_reg) > 7)
VEXb = 0;
}
else if (instr->op_dir == RM_DST)
{
if (opnd[instr->srcidx].base_reg && GetRegisterNo(opnd[instr->srcidx].base_reg) > 7)
VEXr = 0;
if (opnd[0].base_reg && !opnd[0].indirect && GetRegisterNo(opnd[0].base_reg) > 7)
VEXb = 0;
}
if (((instr->vexflags & VEX_WIG) != 0 && VEXx == 1 && VEXb == 1 && VEXmmmmm == 1) ||
(*vexSize != 3 && VEXx == 1 && VEXb == 1))
* vexSize = 2;
if (VEXx == 0 || VEXb == 0)
* vexSize = 3;
VEXvvvv = ~VEXvvvv;
if (*vexSize == 2)
{
vexBytes[0] = 0xc5;
vexBytes[1] = (VEXpp) | (VEXl << 2) | ((VEXvvvv & 0xf) << 3) | (VEXr << 7);
}
else if (*vexSize == 3)
{
vexBytes[0] = 0xc4;
vexBytes[1] = (VEXr << 7) | (VEXx << 6) | (VEXb << 5) | (VEXmmmmm);
vexBytes[2] = (VEXwe << 7) | ((VEXvvvv & 0xf) << 3) | (VEXl << 2) | (VEXpp);
}
}
void BuildEVEX(bool* needEvex, unsigned char* evexBytes, struct Instr_Def* instr, struct expr opnd[4], bool needB, bool needX, bool needRR, uint_32 opCount, struct code_info* CodeInfo)
{
unsigned char EVEXpp = 0;
unsigned char EVEXmm = 0;
unsigned char EVEXr = 1;
unsigned char EVEXx = 1;
unsigned char EVEXb = 1;
unsigned char EVEXnr = 0;
unsigned char EVEXl = 0;
unsigned char EVEXnl = 1;
unsigned char EVEXw = 0;
unsigned char EVEXvvvv = 0;
unsigned char EVEXaaa = 0;
unsigned char EVEXz = 0;
unsigned char EVEXbr = 0;
unsigned char EVEXnv = 1;
unsigned char reg1 = 0xff;
unsigned char reg2 = 0xff;
EVEXz = (decoflags & 0x80) >> 7;
EVEXaaa = (decoflags & 7);
if ((instr->evexflags & EVEX_K) != 0 && EVEXaaa == 0)
EmitError(K_REGISTER_EXPECTED);
if (instr->op_elements == 16 && broadflags != 0x40 && broadflags != 0)
EmitError(MISMATCH_IN_THE_NUMBER_OF_BROADCASTING_ELEMENTS);
if (instr->op_elements == 8 && broadflags != 0x30 && broadflags != 0)
EmitError(MISMATCH_IN_THE_NUMBER_OF_BROADCASTING_ELEMENTS);
if (instr->op_elements == 4 && broadflags != 0x20 && broadflags != 0)
EmitError(MISMATCH_IN_THE_NUMBER_OF_BROADCASTING_ELEMENTS);
if (instr->op_elements == 2 && broadflags != 0x10 && broadflags != 0)
EmitError(MISMATCH_IN_THE_NUMBER_OF_BROADCASTING_ELEMENTS);
if (instr->op_elements == 1 && broadflags != 0x00)
EmitError(MISMATCH_IN_THE_NUMBER_OF_BROADCASTING_ELEMENTS);
if (broadflags != 0 && (instr->evexflags & EVEX_BRD) == 0)
EmitError(BROADCAST_DECORATORS_NOT_ALLOWED_FOR_THIS_INSTRUCTION);
if (broadflags != 0)
EVEXbr = 1;
if ((instr->evexflags & EVEX_MASK) == 0 && (EVEXaaa != 0))
EmitError(EVEX_DECORATOR_NOT_ALLOWED);
if ((instr->evexflags & EVEX_Z) == 0 && (EVEXz == 1))
EmitError(Z_MASK_NOT_PERMITTED_WHEN_FIRST_OPERATOR_IS_MEMORY);
if ((instr->vexflags & VEX_NDS) != 0)
{
EVEXvvvv = GetRegisterNo(opnd[1].base_reg);
if (GetRegisterNo(opnd[1].base_reg) > 15)
EVEXnv = 0;
}
else if ((instr->vexflags & VEX_DDS) != 0)
{
EVEXvvvv = GetRegisterNo(opnd[2].base_reg);
if (GetRegisterNo(opnd[2].base_reg) > 15)
EVEXnv = 0;
}
else if ((instr->vexflags & VEX_NDD) != 0)
{
EVEXvvvv = GetRegisterNo(opnd[0].base_reg);
if (GetRegisterNo(opnd[0].base_reg) > 15)
EVEXnv = 0;
}
EVEXvvvv = ~EVEXvvvv;
if ((instr->evexflags & EVEX_VSIB) != 0)
{
if ((opnd[instr->memOpnd].idx_reg && GetRegisterNo(opnd[instr->memOpnd].idx_reg) > 15) ||
(opnd[instr->memOpnd].base_reg && GetRegisterNo(opnd[instr->memOpnd].base_reg) > 15))
{
EVEXnv = 0;
}
else
EVEXnv = 1;
if ((opnd[instr->memOpnd].idx_reg && GetRegisterNo(opnd[instr->memOpnd].idx_reg) > 23) ||
(opnd[instr->memOpnd].base_reg && GetRegisterNo(opnd[instr->memOpnd].base_reg) > 23))
{
EVEXx = 0;
}
else
EVEXx = 1;
}
if (instr->op_size == 16)
EVEXl = 0;
else if (instr->op_size == 32)
EVEXl = 1;
else if (instr->op_size == 64)
{
EVEXl = 0;
EVEXnl = 0;
}
EVEXnl = ~EVEXnl;
if (CodeInfo->evex_sae != 0)
{
if ((instr->evexflags & EVEX_SAE) != 0) {
if (CodeInfo->evex_sae > 0x10)
EmitError(EMBEDDED_ROUNDING_IS_AVAILABLE_ONLY_WITH_REG_REG_OP);
}
else if ((instr->evexflags & EVEX_RND) != 0) {
if (CodeInfo->evex_sae == 0x10)
EmitError(EMBEDDED_ROUNDING_IS_AVAILABLE_ONLY_WITH_REG_REG_OP);
else if ((CodeInfo->opnd[OPND1].type & OP_M_ANY) || (CodeInfo->opnd[OPND2].type & OP_M_ANY) ||
(CodeInfo->opnd[OPND3].type & OP_M_ANY))
EmitError(EMBEDDED_ROUNDING_IS_AVAILABLE_ONLY_WITH_REG_REG_OP);
}
switch (CodeInfo->evex_sae)
{
case 0x10:
case 0x20:
{
EVEXnl = 0;
EVEXl = 0;
EVEXbr = 1;
break;
}
case 0x40:
{
EVEXnl = 0;
EVEXl = 1;
EVEXbr = 1;
break;
}
case 0x60:
{
EVEXnl = 1;
EVEXl = 0;
EVEXbr = 1;
break;
}
case 0x80:
{
EVEXnl = 1;
EVEXl = 1;
EVEXbr = 1;
}
}
}
if ((instr->evexflags & EVEX_W0) != 0)
EVEXw = 0;
else if ((instr->evexflags & EVEX_W1) != 0)
EVEXw = 1;
if ((instr->vexflags & VEX_66) != 0)
EVEXpp = 0x01;
else if ((instr->vexflags & VEX_F3) != 0)
EVEXpp = 0x02;
else if ((instr->vexflags & VEX_F2) != 0)
EVEXpp = 0x03;
if ((instr->vexflags & VEX_0F) != 0)
EVEXmm = 1;
else if ((instr->vexflags & VEX_0F38) != 0)
EVEXmm = 2;
else if ((instr->vexflags & VEX_0F3A) != 0)
EVEXmm = 3;
if (instr->op_dir == REG_DST)
{
if (!opnd[0].indirect)
{
if (GetRegisterNo(opnd[0].base_reg) > 15)
{
EVEXnr = 0;
if (GetRegisterNo(opnd[0].base_reg) > 23)
EVEXr = 0;
else
EVEXr = 1;
}
else
{
EVEXnr = 1;
if (GetRegisterNo(opnd[1].base_reg) > 7)
EVEXr = 0;
else
EVEXr = 1;
}
}
else
{
if (needRR)
EVEXnr = 1;
}
if (!opnd[instr->srcidx].indirect)
{
if ((instr->vexflags & VEX_NDD) != 0)
{
EVEXr = 1;
EVEXx = 1;
EVEXb = 1;
EVEXnr = 1;
}
else if (opnd[instr->srcidx].base_reg && GetRegisterNo(opnd[instr->srcidx].base_reg) > 15)
{
EVEXx = 0;
if (opnd[instr->srcidx].base_reg && GetRegisterNo(opnd[instr->srcidx].base_reg) > 23)
EVEXb = 0;
else
EVEXb = 1;
}
else
{
EVEXx = 1;
if (opnd[instr->srcidx].base_reg && GetRegisterNo(opnd[instr->srcidx].base_reg) > 7)
EVEXb = 0;
else
EVEXb = 1;
}
}
}
else if (instr->op_dir == RM_DST)
{
if (!opnd[instr->srcidx].indirect)
{
if (GetRegisterNo(opnd[instr->srcidx].base_reg) > 15)
{
EVEXnr = 0;
if (GetRegisterNo(opnd[instr->srcidx].base_reg) > 23)
EVEXr = 0;
else
EVEXr = 1;
}
else
{
EVEXnr = 1;
if (GetRegisterNo(opnd[instr->srcidx].base_reg) > 7)
EVEXr = 0;
else
EVEXr = 1;
}
}
if (!opnd[0].indirect)
{
if (GetRegisterNo(opnd[0].base_reg) > 15)
{
EVEXx = 0;
if (GetRegisterNo(opnd[0].base_reg) > 23)
EVEXb = 0;
else
EVEXb = 1;
}
else
{
EVEXx = 1;
if (GetRegisterNo(opnd[0].base_reg) > 7)
EVEXb = 0;
else
EVEXb = 1;
}
}
}
if ((instr->flags & OPCODE_EXT) != 0)
EVEXnr = 1;
if ((instr->vexflags & VEX_R) != 0)
EVEXr = 0;
if ((instr->vexflags & VEX_B) != 0 || needB)
EVEXb = 0;
if ((instr->vexflags & VEX_X) != 0 || needX)
EVEXx = 0;
evexBytes[0] = 0x62;
evexBytes[1] = ((EVEXr & 0x1) << 7) | ((EVEXx & 0x1) << 6) | ((EVEXb & 0x1) << 5) | ((EVEXnr & 0x1) << 4) | (EVEXmm & 0x3);
evexBytes[2] = ((EVEXw & 0x1) << 7) | ((EVEXvvvv & 0xf) << 3) | (0x04) | (EVEXpp & 0x3);
evexBytes[3] = ((EVEXz & 0x1) << 7) | ((EVEXnl & 0x1) << 6) | ((EVEXl & 0x1) << 5) | ((EVEXbr & 0x1) << 4) | ((EVEXnv & 0x1) << 3) | (EVEXaaa & 0x7);
*needEvex = TRUE;
}
bool CompDisp(struct expr* memOpnd, struct Instr_Def* instr, struct code_info* CodeInfo)
{
int_32 elements = (broadflags == 0 && (instr->evexflags & EVEX_BRD) != 0) ? 1 : instr->op_elements;
int_32 elemSize = (instr->op_size / elements);
if (CodeInfo->evex_flag)
{
if (memOpnd->value >= -(128 * elemSize) && memOpnd->value <= (127 * elemSize))
{
if (memOpnd->value % elemSize == 0)
{
memOpnd->value = (memOpnd->value / elemSize);
return TRUE;
}
}
return FALSE;
}
return TRUE;
}
bool IsSimdRegister(struct asm_tok* regTok)
{
bool result = FALSE;
if (regTok)
{
if (regTok->tokval >= T_XMM0 && regTok->tokval <= T_XMM7)
result = TRUE;
else if (regTok->tokval >= T_XMM8 && regTok->tokval <= T_XMM15)
result = TRUE;
else if (regTok->tokval >= T_XMM16 && regTok->tokval <= T_XMM23)
result = TRUE;
else if (regTok->tokval >= T_XMM24 && regTok->tokval <= T_XMM31)
result = TRUE;
else if (regTok->tokval >= T_YMM0 && regTok->tokval <= T_YMM7)
result = TRUE;
else if (regTok->tokval >= T_YMM8 && regTok->tokval <= T_YMM15)
result = TRUE;
else if (regTok->tokval >= T_YMM16 && regTok->tokval <= T_YMM23)
result = TRUE;
else if (regTok->tokval >= T_YMM24 && regTok->tokval <= T_YMM31)
result = TRUE;
else if (regTok->tokval >= T_ZMM0 && regTok->tokval <= T_ZMM7)
result = TRUE;
else if (regTok->tokval >= T_ZMM8 && regTok->tokval <= T_ZMM31)
result = TRUE;
}
return result;
}
int BuildMemoryEncoding(unsigned char* pmodRM, unsigned char* pSIB, unsigned char* pREX, bool* needModRM, bool* needSIB,
unsigned int* dispSize, uint_64* pDisp, struct Instr_Def* instr, struct expr opExpr[4], bool* needB,
bool* needX, bool* needRR, struct code_info* CodeInfo)
{
int returnASO = 0;
unsigned char sibScale = 0;
uint_32 memModeIdx = 0;
unsigned char baseRegNo = 17;
unsigned char idxRegNo = 17;
int baseRegSize = 0;
int idxRegSize = 0;
int symSize = 0;
bool skipSIB = FALSE;
if (instr->memOpnd != MEM_ABS_1 && instr->memOpnd != MEM_ABS_0)
{
baseRegNo = GetRegisterNo(opExpr[instr->memOpnd].base_reg);
idxRegNo = GetRegisterNo(opExpr[instr->memOpnd].idx_reg);
if ((instr->vexflags & VEX_VSIB) != 0 && IsSimdRegister(opExpr[instr->memOpnd].base_reg))
{
unsigned char temp = baseRegNo;
baseRegNo = idxRegNo;
idxRegNo = temp;
}
if ((instr->evexflags & EVEX_VSIB) != 0 && idxRegNo > 15)
{
idxRegNo &= 7;
*needRR = TRUE;
}
if (opExpr[instr->memOpnd].base_reg)
baseRegSize = SizeFromRegister(opExpr[instr->memOpnd].base_reg->tokval);
if (opExpr[instr->memOpnd].idx_reg)
idxRegSize = SizeFromRegister(opExpr[instr->memOpnd].idx_reg->tokval);
}
if (baseRegSize != idxRegSize && idxRegSize < 16 && idxRegSize > 0 && baseRegSize > 0)
{
EmitError(BASE_INDEX_MEMORY_SIZE_ERROR);
return returnASO;
}
if (ModuleInfo.Ofssize == USE64 && baseRegSize == 2)
{
EmitError(BITS16_MEM_NOT_ALLOWED_IN_LONG_MODE);
return returnASO;
}
if ((idxRegNo > 7 || baseRegNo > 7) && ModuleInfo.Ofssize != USE64 && idxRegNo < 16 && baseRegNo < 16)
{
EmitError(INVALID_ADDRESSING_MODE_WITH_CURRENT_CPU_SETTING);
return returnASO;
}
if (opExpr[instr->memOpnd].sym && opExpr[instr->memOpnd].kind == EXPR_ADDR)
{
symSize = SizeFromMemtype(opExpr[instr->memOpnd].mem_type, ModuleInfo.Ofssize, opExpr[instr->memOpnd].sym);
if (ModuleInfo.Ofssize == USE64 && opExpr[instr->memOpnd].sym->state != SYM_STACK && baseRegNo == 0x11)
{
baseRegNo = 16;
}
}
else
{
if ((ModuleInfo.Ofssize == USE64 && baseRegSize == 4) ||
(ModuleInfo.Ofssize == USE32 && baseRegSize == 2) ||
(ModuleInfo.Ofssize == USE16 && baseRegSize == 4))
returnASO = 1;
}
if (ModuleInfo.Ofssize == USE32 && baseRegSize == 2)
{
if (instr->memOpnd < NO_MEM)
{
if (opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].idx_reg &&
opExpr[instr->memOpnd].base_reg->tokval == T_BX && opExpr[instr->memOpnd].idx_reg->tokval == T_SI)
* pmodRM |= 0;
else if (opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].idx_reg &&
opExpr[instr->memOpnd].base_reg->tokval == T_BX && opExpr[instr->memOpnd].idx_reg->tokval == T_DI)
* pmodRM |= 1;
else if (opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].idx_reg &&
opExpr[instr->memOpnd].base_reg->tokval == T_BP && opExpr[instr->memOpnd].idx_reg->tokval == T_SI)
* pmodRM |= 2;
else if (opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].idx_reg &&
opExpr[instr->memOpnd].base_reg->tokval == T_BP && opExpr[instr->memOpnd].idx_reg->tokval == T_DI)
* pmodRM |= 3;
else if (opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].base_reg->tokval == T_SI)
* pmodRM |= 4;
else if (opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].base_reg->tokval == T_DI)
* pmodRM |= 5;
else if (!opExpr[instr->memOpnd].base_reg && !opExpr[instr->memOpnd].idx_reg)
* pmodRM |= 6;
else if (opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].base_reg->tokval == T_BX)
* pmodRM |= 7;
*needModRM |= TRUE;
skipSIB = TRUE;
}
}
else
{
memModeIdx = (baseRegNo * 18) + (idxRegNo % 18);
if (instr->memOpnd < NO_MEM)
{
if (MemTable[memModeIdx].flags & NO_ENCODE)
{
EmitError(INVALID_ADDRESSING_MODE_WITH_CURRENT_CPU_SETTING);
return returnASO;
}
if (MemTable[memModeIdx].flags & MEMF_MODRM)
{
*pmodRM |= MemTable[memModeIdx].modRM;
*needModRM |= TRUE;
}
if (MemTable[memModeIdx].flags & MEMF_SIB)
{
*pSIB |= MemTable[memModeIdx].SIB;
*needSIB |= TRUE;
}
}
}
if (instr->memOpnd > NO_MEM || opExpr[instr->memOpnd].value != 0 ||
(ModuleInfo.Ofssize == USE64 && opExpr[instr->memOpnd].base_reg && opExpr[instr->memOpnd].base_reg->token == T_RIP) ||
MemTable[memModeIdx].flags & MEMF_DSP || MemTable[memModeIdx].flags & MEMF_DSP32 || (opExpr[instr->memOpnd].sym && opExpr[instr->memOpnd].sym->state != SYM_STACK))
{
if (instr->memOpnd > NO_MEM)
{
switch (ModuleInfo.Ofssize)
{
case USE16:
*dispSize = 2;
break;
case USE32:
*dispSize = 4;
break;
case USE64:
*dispSize = 8;
break;
}
}
else
{
if (CompDisp(&opExpr[(instr->memOpnd & 7)], instr, CodeInfo) &&
(((!opExpr[instr->memOpnd].sym) || (opExpr[instr->memOpnd].sym && opExpr[instr->memOpnd].sym->state == SYM_STACK)) &&
(((MemTable[memModeIdx].flags & MEMF_DSP32) == 0) && (opExpr[instr->memOpnd].value >= -128 && opExpr[instr->memOpnd].value <= 127))))
{
*dispSize = 1;
*pmodRM |= MODRM_DISP8;
}
else
{
if (ModuleInfo.Ofssize == USE16)
*dispSize = 2;
else
*dispSize = 4;
if ((int)(MemTable[memModeIdx].flags & MEMF_DSP32) == 0)
*pmodRM |= MODRM_DISP;
}
}
*pDisp = opExpr[(instr->memOpnd & 7)].value64;
}
if (baseRegNo > 7 && baseRegNo < 16)
{
if (instr->vexflags == NO_VEX)
* pREX |= 0x41;
*needB = TRUE;
}
if (idxRegNo > 7 && idxRegNo < 16)
{
if (instr->vexflags == NO_VEX)
* pREX |= 0x42;
*needX = TRUE;
}
if (!skipSIB && instr->memOpnd < NO_MEM && (opExpr[instr->memOpnd].scale > 1 || opExpr[instr->memOpnd].idx_reg != 0 || (MemTable[memModeIdx].flags & MEMF_SIB)))
{
switch (opExpr[instr->memOpnd].scale)
{
case 1:
sibScale = 0;
break;
case 2:
sibScale = 1;
break;
case 4:
sibScale = 2;
break;
case 8:
sibScale = 3;
break;
}
*pSIB |= (sibScale << 6);
*needSIB |= TRUE;
}
return returnASO;
}
void PromoteBroadcast(struct Instr_Def* instr, struct code_info* CodeInfo)
{
if (strcasecmp(instr->mnemonic, "VCVTDQ2PD") == 0)
{
if (broadflags == 0x40 && instr->operand_types[0] == R_ZMM)
broadflags = 0x30;
else if (broadflags == 0x30 && instr->operand_types[0] == R_YMM)
broadflags = 0x20;
else if (broadflags == 0x20 && instr->operand_types[0] == R_XMM)
broadflags = 0x10;
}
}
bool CheckMTSize(struct Instr_Def* instr, int mtype) {
int i;
bool result = FALSE;
if (instr->op_elements == 1)
i = instr->op_size;
else if (instr->op_size < instr->op_elements)
i = instr->op_elements;
else
i = instr->op_size / instr->op_elements;
switch (mtype) {
case MT_BYTE:
if (i == 1)
break;
goto sizeerror;
case MT_WORD:
if (i == 2)
break;
goto sizeerror;
case MT_DWORD:
if (i == 4)
break;
goto sizeerror;
case MT_FWORD:
if (i == 6)
break;
goto sizeerror;
case MT_QWORD:
if (i == 8)
break;
goto sizeerror;
case MT_TBYTE:
if (i == 10)
break;
goto sizeerror;
case MT_OWORD:
if (i == 16)
break;
goto sizeerror;
case MT_YMMWORD:
if (i == 32)
break;
goto sizeerror;
case MT_ZMMWORD:
if (i == 64)
break;
sizeerror:
result = TRUE;
}
return result;
}
ret_code CodeGenV2(const char* instr, struct code_info* CodeInfo, uint_32 oldofs, uint_32 opCount, struct expr opExpr[4])
{
struct Instr_Def instrToMatch;
ret_code retcode = NOT_ERROR;
struct Instr_Def* matchedInstr = NULL;
uint_32 i = 0;
uint_8 fpfix = FALSE;
bool needModRM = FALSE;
bool needSIB = FALSE;
bool needFixup = FALSE;
bool hasMemReg = FALSE;
bool needVEX = FALSE;
bool needEVEX = FALSE;
bool needB = FALSE;
bool needX = FALSE;
bool needRR = FALSE;
int aso = 0;
unsigned char opcodeByte = 0;
unsigned char rexByte = 0;
unsigned char vexSize = 0;
unsigned char vexBytes[3] = { 0, 0, 0 };
unsigned char evexBytes[4] = { 0, 0, 0, 0 };
unsigned char modRM = 0;
unsigned char sib = 0;
unsigned int dispSize = 0;
unsigned int immSize = 0;
unsigned char encodeMode = 0;
unsigned int srcRegNo = 0;
unsigned int dstRegNo = 0;
union
{
uint_64 displacement64;
unsigned char byte[8];
} displacement;
union
{
uint_64 full;
unsigned char byte[8];
} immValue;
if ((CodeInfo->opnd[OPND2].type == OP_I16 || CodeInfo->opnd[OPND2].type == OP_I8) && opExpr[1].mem_type != MT_WORD)
{
if ((CodeInfo->opnd[OPND2].data32l <= UCHAR_MAX) && (CodeInfo->opnd[OPND2].data32l >= -255))
{
if (CodeInfo->opnd[OPND1].type == OP_M || CodeInfo->opnd[OPND1].type == OP_M08)
{
CodeInfo->opnd[OPND1].type = OP_M08;
CodeInfo->opnd[OPND2].type = OP_I8;
}
else if (CodeInfo->opnd[OPND1].type == OP_R8 || CodeInfo->opnd[OPND1].type == OP_AL || CodeInfo->opnd[OPND1].type == OP_CL)
CodeInfo->opnd[OPND2].type = OP_I8;
else
{
switch (CodeInfo->token)
{
case T_BT:
case T_BTC:
case T_BTR:
case T_BTS:
CodeInfo->opnd[OPND2].type = OP_I8;
}
}
}
}
if (CodeInfo->Ofssize == USE64)
MemTable = &MemTable64;
else
MemTable = &MemTable32;
if ((opExpr[1].override && opExpr[1].override->tokval == T_FLAT) ||
(opExpr[0].override && opExpr[0].override->tokval == T_FLAT))
return EMPTY;
memset(&instrToMatch, 0, sizeof(struct Instr_Def));
instrToMatch.mnemonic = instr;
instrToMatch.operand_count = opCount;
for (i = 0; i < opCount; i++)
{
instrToMatch.operand_types[i] = MatchOperand(CodeInfo, CodeInfo->opnd[i], opExpr[i]);
if (opExpr[i].kind == EXPR_ADDR && (opExpr[i].base_reg || opExpr[i].idx_reg))
hasMemReg = TRUE;
if (opExpr[i].kind == EXPR_REG && opExpr[i].indirect)
hasMemReg = TRUE;
if (CodeInfo->Ofssize == USE64 && opExpr[i].sym)
hasMemReg = TRUE;
}
switch (CodeInfo->Ofssize)
{
case USE16:
encodeMode = X16;
break;
case USE32:
encodeMode = X32;
break;
case USE64:
encodeMode = X64;
break;
}
if (opExpr[0].base_reg)
dstRegNo = GetRegisterNo(opExpr[0].base_reg);
if (opExpr[1].base_reg)
srcRegNo = GetRegisterNo(opExpr[1].base_reg);
matchedInstr = LookupInstruction(&instrToMatch, hasMemReg, encodeMode, srcRegNo, dstRegNo, CodeInfo);
if (matchedInstr == NULL)
{
for (i = 0; i < opCount; i++)
instrToMatch.operand_types[i] = DemoteOperand(instrToMatch.operand_types[i]);
matchedInstr = LookupInstruction(&instrToMatch, hasMemReg, encodeMode, srcRegNo, dstRegNo, CodeInfo);
}
if (!evexflag) {
if (dstRegNo <= 7 && srcRegNo > 7) {
switch (CodeInfo->token) {
case T_VMOVQ:
case T_VMOVDQA:
case T_VMOVDQU:
case T_VMOVUPD:
case T_VMOVUPS:
if (instrToMatch.operand_types[1] == R_XMM && instrToMatch.operand_types[0] == R_XMM)
instrToMatch.operand_types[1] = R_XMME;
else if (instrToMatch.operand_types[1] == R_YMM && instrToMatch.operand_types[0] == R_YMM)
instrToMatch.operand_types[1] = R_YMME;
}
}
}
matchedInstr = LookupInstruction(&instrToMatch, hasMemReg, encodeMode, srcRegNo, dstRegNo, CodeInfo);
if (matchedInstr && matchedInstr->memOpnd != NO_MEM && CodeInfo->Ofssize == USE64 && CodeInfo->token != T_MOVABS && (int)matchedInstr->group < SSE0 && !hasMemReg)
{
if ((int)CodeInfo->opnd[(matchedInstr->memOpnd & 7)].data64 > INT_MIN&& CodeInfo->opnd[(matchedInstr->memOpnd & 7)].data64 < UINT_MAX)
{
matchedInstr = NULL;
}
}
if (matchedInstr == NULL) {
if (CodeInfo->token == T_ENTER) {
if (CodeInfo->opnd[OPND1].type == OP_I16 && CodeInfo->opnd[OPND2].type == OP_I8) {
OutputCodeByte(0xc8);
OutputBytes((unsigned char*)&CodeInfo->opnd[OPND1].data32l, 2, NULL);
OutputCodeByte(CodeInfo->opnd[OPND2].data32l);
}
return NOT_ERROR;
}
else
retcode = EMPTY;
}
else
{
PromoteBroadcast(matchedInstr, CodeInfo);
if (Options.line_numbers)
AddLinnumDataRef(get_curr_srcfile(), GetLineNumber());
if (!IsValidInCPUMode(matchedInstr))
{
EmitError(INSTRUCTION_OR_REGISTER_NOT_ACCEPTED_IN_CURRENT_CPU_MODE);
return ERROR;
}
if (matchedInstr->memOpnd != NO_MEM)
{
if (opExpr[(matchedInstr->memOpnd & 7)].sym && opExpr[(matchedInstr->memOpnd & 7)].sym->state != SYM_STACK)
needFixup = TRUE;
}
if (matchedInstr->immOpnd != NO_IMM)
{
if (CodeInfo->opnd[matchedInstr->immOpnd].InsFixup)
needFixup = TRUE;
}
if (matchedInstr->memOpnd != NO_MEM)
aso = BuildMemoryEncoding(&modRM, &sib, &rexByte, &needModRM, &needSIB,
&dispSize, &displacement, matchedInstr, opExpr, &needB, &needX, &needRR, CodeInfo);
modRM |= BuildModRM(matchedInstr->modRM, matchedInstr, opExpr, &needModRM, &needSIB,
((matchedInstr->vexflags & VEX) || (matchedInstr->vexflags & EVEX)));
if ((matchedInstr->vexflags & VEX) != 0 && (matchedInstr->evexflags & EVEX_ONLY) == 0 && CodeInfo->evex_flag == 0)
BuildVEX(&needVEX, &vexSize, &vexBytes, matchedInstr, opExpr, needB, needX, opCount);
else if ((matchedInstr->evexflags & EVEX_ONLY) != 0 ||
((CodeInfo->evex_flag) && (matchedInstr->vexflags & EVEX) != 0))
BuildEVEX(&needEVEX, &evexBytes, matchedInstr, opExpr, needB, needX, needRR, opCount, CodeInfo);
if (CodeInfo->evex_flag && matchedInstr->evexflags == NO_EVEX)
EmitError(NO_EVEX_FORM);
else if (CodeInfo->Ofssize == USE64)
rexByte |= BuildREX(rexByte, matchedInstr, opExpr);
if (Require_ADDR_Size_Override(matchedInstr, CodeInfo) || aso)
OutputCodeByte(ADDR_SIZE_OVERRIDE);
if (CodeInfo->prefix.ins == T_BND && (matchedInstr->flags & ALLOW_BND) == 0)
EmitError(INSTRUCTION_PREFIX_NOT_ALLOWED);
else if (CodeInfo->prefix.ins == T_BND)
OutputCodeByte(BND);
if (CodeInfo->prefix.ins == T_LOCK && (matchedInstr->flags & ALLOW_LOCK) == 0)
EmitError(INSTRUCTION_PREFIX_NOT_ALLOWED);
else if (CodeInfo->prefix.ins == T_LOCK)
OutputCodeByte(LOCK);
if (Require_OPND_Size_Override(matchedInstr, CodeInfo))
OutputCodeByte(OP_SIZE_OVERRIDE);
if (CodeInfo->prefix.ins == T_REP && (matchedInstr->flags & ALLOW_REP) == 0)
EmitError(INSTRUCTION_PREFIX_NOT_ALLOWED);
else if (CodeInfo->prefix.ins == T_REP)
OutputCodeByte(REP);
if (CodeInfo->prefix.ins == T_REPE && (matchedInstr->flags & ALLOW_REP) == 0)
EmitError(INSTRUCTION_PREFIX_NOT_ALLOWED);
else if (CodeInfo->prefix.ins == T_REPE)
OutputCodeByte(REPE);
if (CodeInfo->prefix.ins == T_REPZ && (matchedInstr->flags & ALLOW_REP) == 0)
EmitError(INSTRUCTION_PREFIX_NOT_ALLOWED);
else if (CodeInfo->prefix.ins == T_REPZ)
OutputCodeByte(REPZ);
if (CodeInfo->prefix.ins == T_REPNE && (matchedInstr->flags & ALLOW_REP) == 0)
EmitError(INSTRUCTION_PREFIX_NOT_ALLOWED);
else if (CodeInfo->prefix.ins == T_REPNE)
OutputCodeByte(REPNE);
if (CodeInfo->prefix.ins == T_REPNZ && (matchedInstr->flags & ALLOW_REP) == 0)
EmitError(INSTRUCTION_PREFIX_NOT_ALLOWED);
else if (CodeInfo->prefix.ins == T_REPNZ)
OutputCodeByte(REPNZ);
if (CodeInfo->prefix.RegOverride != ASSUME_NOTHING)
{
if (matchedInstr->flags & ALLOW_SEG)
{
if (ModuleInfo.Ofssize == USE64 && (CodeInfo->prefix.RegOverride == ASSUME_FS || CodeInfo->prefix.RegOverride == ASSUME_GS || CodeInfo->prefix.RegOverride == ASSUME_SS))
{
switch (CodeInfo->prefix.RegOverride)
{
case ASSUME_FS:
OutputCodeByte(PREFIX_FS);
break;
case ASSUME_GS:
OutputCodeByte(PREFIX_GS);
break;
case ASSUME_SS:
OutputCodeByte(PREFIX_SS);
break;
}
}
else if (ModuleInfo.Ofssize == USE64 && ((matchedInstr->flags & ALLOW_SEGX) == 0))
{
EmitError(ILLEGAL_USE_OF_SEGMENT_REGISTER);
return ERROR;
}
else
{
switch (CodeInfo->prefix.RegOverride)
{
case ASSUME_CS:
OutputCodeByte(PREFIX_CS);
break;
case ASSUME_DS:
OutputCodeByte(PREFIX_DS);
break;
case ASSUME_ES:
OutputCodeByte(PREFIX_ES);
break;
case ASSUME_SS:
OutputCodeByte(PREFIX_SS);
break;
case ASSUME_FS:
OutputCodeByte(PREFIX_FS);
break;
case ASSUME_GS:
OutputCodeByte(PREFIX_GS);
break;
}
}
}
else
{
EmitError(ILLEGAL_USE_OF_SEGMENT_REGISTER);
return ERROR;
}
}
if (CodeInfo->pinstr->cpu & P_FPU_MASK) {
if ((ModuleInfo.emulator == TRUE) &&
(CodeInfo->Ofssize == USE16) &&
(CodeInfo->pinstr->cpu & P_FPU_MASK) &&
((CodeInfo->pinstr->allowed_prefix & NO_FWAIT) == 0)) {
fpfix = TRUE;
AddFloatingPointEmulationFixup(CodeInfo);
}
if (CodeInfo->token == T_FWAIT) {
if ((ModuleInfo.curr_cpu & P_CPU_MASK) < P_386) {
if ((ModuleInfo.emulator == TRUE) && (CodeInfo->Ofssize == USE16)) {
if (fpfix) {
OutputCodeByte(0x90);
}
}
else if (fpfix || (matchedInstr->flags & ALLOW_FWAIT)) {
OutputCodeByte(FWAIT);
}
else if ((CodeInfo->pinstr->allowed_prefix & NO_FWAIT) == 0) {
if ((ModuleInfo.curr_cpu & P_CPU_MASK) < P_286)
OutputCodeByte(FWAIT);
}
}
}
}
if (needVEX)
OutputBytes((unsigned char*)& vexBytes, vexSize, NULL);
if (needEVEX)
OutputBytes((unsigned char*)& evexBytes, 4, NULL);
switch (matchedInstr->mandatory_prefix)
{
case PFX_0x66F3A:
case PFX_0x66F38:
case PFX_0x66F:
OutputCodeByte(0x66);
break;
case PFX_0xF3F38:
case PFX_0xF30F:
case PFX_0xF3:
OutputCodeByte(0xf3);
break;
case PFX_0xF2F38:
case PFX_0xF20F:
OutputCodeByte(0xf2);
break;
}
if (rexByte != 0)
OutputCodeByte(rexByte);
switch (matchedInstr->mandatory_prefix)
{
case PFX_0xF:
OutputCodeByte(0x0f);
break;
case PFX_0x66F:
OutputCodeByte(0x0f);
break;
case PFX_0x66F38:
OutputCodeByte(0x0f);
OutputCodeByte(0x38);
break;
case PFX_0x66F3A:
OutputCodeByte(0x0f);
OutputCodeByte(0x3a);
break;
case PFX_0xF30F:
case PFX_0xF20F:
OutputCodeByte(0x0f);
break;
case PFX_0x0F38:
case PFX_0xF3F38:
case PFX_0xF2F38:
OutputCodeByte(0x0f);
OutputCodeByte(0x38);
break;
}
if (matchedInstr->flags & F_OPCODE_REG)
{
opcodeByte = matchedInstr->opcode[0];
if (matchedInstr->operand_types[0] == R_SEG || matchedInstr->operand_types[0] == R_SEGE)
opcodeByte += (((GetRegisterNo(opExpr[0].base_reg) & 0x07)) * 8);
else
opcodeByte += (GetRegisterNo(opExpr[0].base_reg) & 0x07);
OutputCodeByte(opcodeByte);
}
else if (matchedInstr->flags & F_OPCODE2_REG)
{
OutputCodeByte(matchedInstr->opcode[0]);
opcodeByte = matchedInstr->opcode[1];
opcodeByte += (GetRegisterNo(opExpr[0].base_reg) & 0x07);
OutputCodeByte(opcodeByte);
}
else if (matchedInstr->flags & F_OPCODE_REG2)
{
opcodeByte = matchedInstr->opcode[0];
opcodeByte += (GetRegisterNo(opExpr[1].base_reg) & 0x07);
OutputCodeByte(opcodeByte);
}
else if ((matchedInstr->flags & F_OPCODE2_REG2)&& (opExpr[1].value == 0))
{
OutputCodeByte(matchedInstr->opcode[0]);
opcodeByte = matchedInstr->opcode[1];
opcodeByte += (GetRegisterNo(opExpr[1].base_reg) & 0x07);
OutputCodeByte(opcodeByte);
needModRM = 0;
}
else if (matchedInstr->flags & F_OPCODE2_STI)
{
OutputCodeByte(matchedInstr->opcode[0]);
opcodeByte = matchedInstr->opcode[1];
opcodeByte += CodeInfo->rm_byte;
OutputCodeByte(opcodeByte);
}
else
{
if ((vexBytes == 0xc5) && (matchedInstr->opcode[0] == 0x6f))
OutputCodeByte(0x7f);
else {
for (i = 0; i < matchedInstr->opcode_bytes; i++)
OutputCodeByte(matchedInstr->opcode[i]);
}
}
if (needModRM)
OutputCodeByte(modRM);
if (needSIB)
OutputCodeByte(sib);
if (dispSize)
{
if (CodeInfo->opnd[(matchedInstr->memOpnd & 7)].InsFixup && needFixup)
{
if (Parse_Pass > PASS_1)
if ((1 << CodeInfo->opnd[(matchedInstr->memOpnd & 7)].InsFixup->type) & ModuleInfo.fmtopt->invalid_fixup_type)
EmitErr(UNSUPPORTED_FIXUP_TYPE, ModuleInfo.fmtopt->formatname, CodeInfo->opnd[(matchedInstr->memOpnd & 7)].InsFixup->sym ? CodeInfo->opnd[(matchedInstr->memOpnd & 7)].InsFixup->sym->name : szNullStr);
if (write_to_file)
{
CodeInfo->opnd[(matchedInstr->memOpnd & 7)].InsFixup->locofs = GetCurrOffset();
if (CodeInfo->isptr)
OutputBytes((unsigned char*)& displacement.byte, dispSize, NULL);
else
OutputBytes((unsigned char*)& displacement.byte, dispSize, CodeInfo->opnd[(matchedInstr->memOpnd & 7)].InsFixup);
}
else
OutputBytes((unsigned char*)& displacement.byte, dispSize, NULL);
}
else
OutputBytes((unsigned char*)& displacement.byte, dispSize, NULL);
}
if (matchedInstr->immOpnd != NO_IMM)
{
immValue.full = CodeInfo->opnd[matchedInstr->immOpnd].data64;
if ((matchedInstr->vexflags & VEX_4OPND) != 0)
{
immValue.full <<= 4;
}
immSize = matchedInstr->op_size;
if ((matchedInstr->flags & IMM8_ONLY) != 0)
immSize = 1;
if (CodeInfo->opnd[matchedInstr->immOpnd].InsFixup && needFixup)
{
if (Parse_Pass > PASS_1)
if ((1 << CodeInfo->opnd[matchedInstr->immOpnd].InsFixup->type) & ModuleInfo.fmtopt->invalid_fixup_type)
EmitErr(UNSUPPORTED_FIXUP_TYPE, ModuleInfo.fmtopt->formatname, CodeInfo->opnd[matchedInstr->immOpnd].InsFixup->sym ? CodeInfo->opnd[matchedInstr->immOpnd].InsFixup->sym->name : szNullStr);
if (write_to_file)
{
CodeInfo->opnd[matchedInstr->immOpnd].InsFixup->locofs = GetCurrOffset();
if (CodeInfo->isptr)
OutputBytes((unsigned char*)& immValue.byte, immSize, NULL);
else
OutputBytes((unsigned char*)& immValue.byte, immSize, CodeInfo->opnd[matchedInstr->immOpnd].InsFixup);
}
else
OutputBytes((unsigned char*)& immValue.byte, immSize, NULL);
}
else
OutputBytes((unsigned char*)& immValue.byte, immSize, NULL);
}
if (CodeInfo->Ofssize == USE64)
{
if (CodeInfo->opnd[OPND1].InsFixup && CodeInfo->opnd[OPND1].InsFixup->type == FIX_RELOFF32)
CodeInfo->opnd[OPND1].InsFixup->addbytes = GetCurrOffset() - CodeInfo->opnd[OPND1].InsFixup->locofs;
if (CodeInfo->opnd[OPND2].InsFixup && CodeInfo->opnd[OPND2].InsFixup->type == FIX_RELOFF32)
CodeInfo->opnd[OPND2].InsFixup->addbytes = GetCurrOffset() - CodeInfo->opnd[OPND2].InsFixup->locofs;
}
}
skip:
if (retcode == NOT_ERROR)
{
if (CurrFile[LST])
LstWrite(LSTTYPE_CODE, oldofs, NULL);
}
return retcode;
}