// Copyright (C) 2004, Matt Conover (mconover@gmail.com)
#undef NDEBUG
#include <assert.h>
#include "disasm.h"
#include "cpu.h"
// Since addresses are internally represented as 64-bit, we need to specially handle
// cases where IP + Displacement wraps around for 16-bit/32-bit operand size
// Otherwise, ignorethe possibility of wraparounds
#define SUPPORT_WRAPAROUND
#ifdef NO_SANITY_CHECKS
#undef NDEBUG
#undef DEBUG_DISASM
#undef assert
#define assert(x)
#endif
#ifdef DEBUG_DISASM
#define DISASM_OUTPUT(x) printf x
#else
#define DISASM_OUTPUT(x)
#endif
#include "disasm_x86_tables.h"
#ifdef _WIN64
#pragma warning(disable:4311 4312)
#endif
////////////////////////////////////////////////////////////////////////
// Internal macros
////////////////////////////////////////////////////////////////////////
#define VIRTUAL_ADDRESS ((U64)Instruction->Address + Instruction->VirtualAddressDelta)
#define AMD64_DIFF (AMD64_8BIT_OFFSET-X86_8BIT_OFFSET)
#define IS_AMD64() (INS_ARCH_TYPE(Instruction) == ARCH_X64)
#define IS_X86_32() (INS_ARCH_TYPE(Instruction) == ARCH_X86)
#define IS_X86_16() (INS_ARCH_TYPE(Instruction) == ARCH_X86_16)
#define X86_BOUND 0x62
#define X86_PUSH_REG 0x50
#define X86_PUSH_CS 0x0e
#define X86_PUSH_DS 0x1e
#define X86_PUSH_SS 0x16
#define X86_PUSH_ES 0x06
#define X86_PUSH_FS 0xa0
#define X86_PUSH_GS 0xa8
#define X86_PUSH_U8 0x6a
#define X86_PUSH_U32 0x68
#define X86_POP_DS 0x1f
#define X86_POP_ES 0x07
#define X86_POP_SS 0x17
#define X86_POP_FS 0xa1
#define X86_POP_GS 0xa9
#define X86_POP_REG 0x58
#define OPCSTR Instruction->String+Instruction->StringIndex
#define APPEND Instruction->StringIndex += (U8)_snprintf
#define APPENDPAD(x) \
{ \
if (Instruction->StringAligned) \
{ \
if (Instruction->StringIndex > x) assert(0); \
while (x != Instruction->StringIndex) APPENDB(' '); \
} \
else if (Instruction->StringIndex) \
{ \
APPENDB(' '); \
} \
}
#define APPENDB(a) Instruction->String[Instruction->StringIndex++] = a
#define APPENDS(a) APPEND(OPCSTR, SIZE_LEFT, a);
#define SIZE_LEFT (MAX_OPCODE_DESCRIPTION-1 > Instruction->StringIndex ? MAX_OPCODE_DESCRIPTION-Instruction->StringIndex : 0)
// If an address size prefix is used for an instruction that doesn't make sense, restore it
// to the default
#define SANITY_CHECK_OPERAND_SIZE() \
{ \
if (!Instruction->AnomalyOccurred && X86Instruction->HasOperandSizePrefix) \
{ \
if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Unexpected operand size prefix\n", VIRTUAL_ADDRESS); \
Instruction->AnomalyOccurred = TRUE; \
X86Instruction->HasOperandSizePrefix = FALSE; \
switch (X86Instruction->OperandSize) \
{ \
case 4: X86Instruction->OperandSize = 2; break; \
case 2: X86Instruction->OperandSize = 4; break; \
default: assert(0); \
} \
} \
}
#define SANITY_CHECK_ADDRESS_SIZE() \
{ \
if (!Instruction->AnomalyOccurred && X86Instruction->HasAddressSizePrefix) \
{ \
if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Unexpected address size prefix\n", VIRTUAL_ADDRESS); \
Instruction->AnomalyOccurred = TRUE; \
} \
X86Instruction->HasAddressSizePrefix = FALSE; \
switch (INS_ARCH_TYPE(Instruction)) \
{ \
case ARCH_X64: X86Instruction->AddressSize = 8; break; \
case ARCH_X86: X86Instruction->AddressSize = 4; break; \
case ARCH_X86_16: X86Instruction->AddressSize = 2; break; \
} \
}
#define SANITY_CHECK_SEGMENT_OVERRIDE() \
if (!Instruction->AnomalyOccurred && X86Instruction->HasSegmentOverridePrefix) \
{ \
if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: Unexpected segment override\n", VIRTUAL_ADDRESS); \
Instruction->AnomalyOccurred = TRUE; \
}
#define INSTR_INC(size) \
{ \
Instruction->Length += size; \
Address += size; \
}
#define X86_SET_TARGET() \
{ \
if (X86Instruction->HasSelector) \
{ \
if (!Instruction->AnomalyOccurred) \
{ \
if (!SuppressErrors) printf("[0x%08I64X] ANOMALY: unexpected segment 0x%02X\n", VIRTUAL_ADDRESS, X86Instruction->Selector); \
Instruction->AnomalyOccurred = TRUE; \
} \
} \
else \
{ \
switch (X86Instruction->Segment) \
{ \
case SEG_CS: \
case SEG_DS: \
case SEG_SS: \
case SEG_ES: \
assert(!X86Instruction->HasSelector); \
Operand->TargetAddress = (U64)X86Instruction->Displacement; \
/* assert(!GetAbsoluteAddressFromSegment((BYTE)X86Instruction->Segment, (DWORD)X86Instruction->Displacement) || GetAbsoluteAddressFromSegment(X86Instruction->Segment, (DWORD)X86Instruction->Displacement) == Operand->TargetAddress); */ \
break; \
case SEG_FS: \
case SEG_GS: \
assert(!X86Instruction->HasSelector); \
Operand->TargetAddress = (U64)GetAbsoluteAddressFromSegment((BYTE)X86Instruction->Segment, (DWORD)X86Instruction->Displacement); \
break; \
default: \
assert(0); /* shouldn't be possible */ \
break; \
} \
} \
}
#define X86_SET_SEG(reg) \
{ \
if (!X86Instruction->HasSegmentOverridePrefix && (reg == REG_EBP || reg == REG_ESP)) \
{ \
assert(!X86Instruction->HasSelector); \
X86Instruction->Segment = SEG_SS; \
} \
}
#define X86_SET_ADDR() \
{ \
if (Operand->Flags & OP_DST) \
{ \
assert(!X86Instruction->HasDstAddressing); \
X86Instruction->HasDstAddressing = TRUE; \
X86Instruction->DstOpIndex[X86Instruction->DstOpCount] = (U8)OperandIndex; \
X86Instruction->DstOpCount++; \
X86Instruction->DstAddressIndex = (U8)OperandIndex; \
} \
if (Operand->Flags & OP_SRC) \
{ \
if (Instruction->Type != ITYPE_STRCMP) assert(!X86Instruction->HasSrcAddressing); \
X86Instruction->HasSrcAddressing = TRUE; \
X86Instruction->SrcOpIndex[X86Instruction->SrcOpCount] = (U8)OperandIndex; \
X86Instruction->SrcOpCount++; \
X86Instruction->SrcAddressIndex = (U8)OperandIndex; \
} \
}
#define X86_SET_REG(reg) \
{ \
if (Operand->Flags & OP_DST) \
{ \
X86Instruction->DstOpIndex[X86Instruction->DstOpCount] = (U8)OperandIndex; \
X86Instruction->DstOpCount++; \
assert(OperandIndex < 2); \
if (Operand->Length > 1 && reg == REG_ESP) Instruction->Groups |= ITYPE_STACK; \
} \
if (Operand->Flags & OP_SRC) \
{ \
X86Instruction->SrcOpIndex[X86Instruction->SrcOpCount] = (U8)OperandIndex; \
X86Instruction->SrcOpCount++; \
} \
}
#define CHECK_AMD64_REG() { if (IS_AMD64()) Operand->Register += AMD64_DIFF; }
////////////////////////////////////////////////////////////////////////
// Internal structures/variables
////////////////////////////////////////////////////////////////////////
ARCHITECTURE_FORMAT_FUNCTIONS X86 =
{
X86_InitInstruction,
NULL,
X86_GetInstruction,
X86_FindFunctionByPrologue
};
char *X86_Registers[0xE0] =
{
// Segments
"es", // 0x00
"cs", // 0x01
"ss", // 0x02
"ds", // 0x03
"fs", // 0x04
"gs", // 0x05
"flags", // 0x06
"eflags", // 0x07
"rflags", // 0x08
"ip+ilen", // 0x09
"eip+ilen", // 0x0A
"rip+ilen", // 0x0B
NULL, // 0x0C
NULL, // 0x0D
NULL, // 0x0E
NULL, // 0x0F
// Test
"tr0", // 0x10
"tr1", // 0x11
"tr2", // 0x12
"tr3", // 0x13
"tr4", // 0x14
"tr5", // 0x15
"tr6", // 0x16
"tr7", // 0x17
"tr8", // 0