Internal changes and optimizations of the generated tables and the InstructionEditor

This commit is contained in:
flobernd 2016-11-22 18:12:05 +01:00
parent be56ef937d
commit 7f7cbd8dcd
16 changed files with 114453 additions and 113266 deletions

View File

@ -158,7 +158,7 @@ const
FILENAME_MNEMONICSTRINGS = 'MnemonicStrings.inc';
FILENAME_INSTRUCTIONDEFINITIONS = 'InstructionDefinitions.inc';
FILENAME_OPERANDDEFINITIONS = 'OperandDefinitions.inc';
FILENAME_INTERNALSTRUCTS = 'InternalStructs.inc';
FILENAME_GENERATEDTYPES = 'GeneratedTypes.inc';
{ TCodeGenerator }
@ -562,8 +562,15 @@ begin
if (ifHasEvexSAE in Definition.Flags) then U := 'ZYDIS_EVEXB_FUNCTIONALITY_SAE';
Buffer.Append(Format(' /*%.4x*/ ', [Index]));
Buffer.Append(Format('ZYDIS_MAKE_INSTRUCTIONDEFINITION(ZYDIS_MNEMONIC_%s, 0x%.4x, %s, %s, %s)', [
AnsiUpperCase(Definition.Mnemonic), O, U, S, T]));
Buffer.Append(Format('{ ZYDIS_MNEMONIC_%s, 0x%.4x, %s, %s, %s, %d, %d, %d, %d, %d, %d, %d }', [
AnsiUpperCase(Definition.Mnemonic), O, U, S, T,
Byte(pfAcceptsLock in Definition.PrefixFlags),
Byte(pfAcceptsREP in Definition.PrefixFlags),
Byte(pfAcceptsREPEREPNE in Definition.PrefixFlags),
Byte(pfAcceptsXACQUIRE in Definition.PrefixFlags),
Byte(pfAcceptsXRELEASE in Definition.PrefixFlags),
Byte(pfAcceptsHLEWithoutLock in Definition.PrefixFlags),
Byte(pfAcceptsBranchHints in Definition.PrefixFlags)]));
end;
var
@ -573,7 +580,7 @@ var
begin
Buffer := TStringBuffer.Create;
try
Buffer.AppendLn('const ZydisInternalInstructionDefinition instructionDefinitions[] =');
Buffer.AppendLn('const ZydisInstructionDefinition instructionDefinitions[] =');
Buffer.AppendLn('{');
WorkStart('Generating instruction definitions', 0, Length(DefinitionList));
for I := Low(DefinitionList) to High(DefinitionList) do
@ -637,7 +644,7 @@ begin
end;
// Open the filter-array
Buffer.AppendLn(Format('const ZydisInternalInstructionTableNode filter%s[][%d] = ', [
Buffer.AppendLn(Format('const ZydisInstructionTableNode filter%s[][%d] = ', [
InstructionFilterClasses[I].GetDescription,
Integer(InstructionFilterClasses[I].GetCapacity) - IndexShift]));
Buffer.AppendLn('{');
@ -943,7 +950,7 @@ begin
opaWrite : OperandAccessMode := 'WRITE';
opaReadWrite : OperandAccessMode := 'READWRITE';
end;
Buffer.Append(Format('ZYDIS_MAKE_OPERANDDEFINITION(ZYDIS_SEM_OPERAND_TYPE_%s, ' +
Buffer.Append(Format('ZYDIS_OPERAND_DEFINITION(ZYDIS_SEM_OPERAND_TYPE_%s, ' +
'ZYDIS_OPERAND_ENCODING_%s, ZYDIS_OPERAND_ACCESS_%s)', [
OperandType, OperandEncoding, OperandAccessMode]));
end;
@ -966,7 +973,7 @@ begin
// Generate operand-definition tables
for I := Low(OperandMapping) to High(OperandMapping) do
begin
Buffer.AppendLn(Format('const ZydisInternalOperandDefinition operandDefinitions%d[][%d] =',
Buffer.AppendLn(Format('const ZydisOperandDefinition operandDefinitions%d[][%d] =',
[I, I]));
Buffer.AppendLn('{');
for J := Low(OperandMapping[I]) to High(OperandMapping[I]) do
@ -996,7 +1003,7 @@ begin
Buffer.Append(Format(' /*%.4x*/ { ', [0]));
for K := 1 to I do
begin
Buffer.Append('ZYDIS_MAKE_OPERANDDEFINITION(ZYDIS_SEM_OPERAND_TYPE_UNUSED, ' +
Buffer.Append('ZYDIS_OPERAND_DEFINITION(ZYDIS_SEM_OPERAND_TYPE_UNUSED, ' +
'ZYDIS_OPERAND_ENCODING_NONE, ZYDIS_OPERAND_ACCESS_READ)');
if (K <> I) then
begin

View File

@ -355,6 +355,38 @@ type
property FlagID: TX86FlagValue read FID write SetID default fvUnused;
end;
{TEVEXEncodingContext = (
ecNone,
ecBroadcast,
ecRoundingControl,
ecSuppressAllExceptions
);
TEVEXInformation = class(TPersistent)
strict private
FDefinition: TInstructionDefinition;
strict private
procedure Changed; inline;
strict private
function GetConflictState: Boolean;
private
procedure LoadFromJSON(JSON: PJSONVariantData; const FieldName: String);
procedure SaveToJSON(JSON: PJSONVariantData; const FieldName: String);
protected
procedure AssignTo(Dest: TPersistent); override;
protected
constructor Create(Definition: TInstructionDefinition);
public
function Equals(const Value: TX86Flags): Boolean; reintroduce;
public
property HasConflicts: Boolean read GetConflictState;
published
property EncodingContext: TEVEXEncodingContext;
property HasEvexAAA: Boolean;
property HasEvexZ: Boolean;
property CD8Scale: Cardinal;
end;}
TInstructionOperands = class;
TOperandType = (
@ -542,6 +574,8 @@ type
idcForcedConflict,
// The instruction-operands configuration is invalid
idcOperands,
// The prefix-flags are invalid
idcPrefixFlags,
// The FLAGS/EFLAGS/RFLAGS registers in the ImplicitRead or ImplicitWrite property do not
// match the given X86Flags configuration
idcX86Flags
@ -568,13 +602,19 @@ type
TOpcodeByte = type Byte;
TPrefixFlag = (
pfAcceptsLock,
pfAcceptsREP,
pfAcceptsREPEREPNE,
pfAcceptsXACQUIRE,
pfAcceptsXRELEASE,
pfAcceptsHLEWithoutLock,
pfAcceptsBranchHints
);
TPrefixFlags = set of TPrefixFlag;
TInstructionDefinitionFlag = (
ifForceConflict,
ifAcceptsLock,
ifAcceptsREP,
ifAcceptsXACQUIRE,
ifAcceptsXRELEASE,
ifAcceptsBranchHints,
ifAcceptsEVEXAAA,
ifAcceptsEVEXZ,
ifIsPrivileged,
@ -601,6 +641,7 @@ type
FExtensions: TOpcodeExtensions;
FCPUID: TCPUIDFeatureFlags;
FOperands: TInstructionOperands;
FPrefixFlags: TPrefixFlags;
FFlags: TInstructionDefinitionFlags;
FImplicitRead: TX86Registers;
FImplicitWrite: TX86Registers;
@ -613,6 +654,7 @@ type
procedure SetEncoding(const Value: TInstructionEncoding); inline;
procedure SetOpcodeMap(const Value: TOpcodeMap); inline;
procedure SetOpcode(const Value: TOpcodeByte); inline;
procedure SetPrefixFlags(const Value: TPrefixFlags); inline;
procedure SetFlags(const Value: TInstructionDefinitionFlags); inline;
procedure SetComment(const Value: String); inline;
strict private
@ -650,7 +692,8 @@ type
property OpcodeExtensions: TOpcodeExtensions read FExtensions;
property CPUID: TCPUIDFeatureFlags read FCPUID;
property Operands: TInstructionOperands read FOperands;
property Flags: TInstructionDefinitionFlags read FFlags write SetFlags;
property PrefixFlags: TPrefixFlags read FPrefixFlags write SetPrefixFlags default [];
property Flags: TInstructionDefinitionFlags read FFlags write SetFlags default [];
property ImplicitRead: TX86Registers read FImplicitRead;
property ImplicitWrite: TX86Registers read FImplicitWrite;
property X86Flags: TX86Flags read FX86Flags;
@ -1204,13 +1247,18 @@ const
'xopa'
);
SInstructionDefinitionFlag: array[TInstructionDefinitionFlag] of String = (
'conflict',
SPrefixFlag: array[TPrefixFlag] of String = (
'accepts_lock',
'accepts_rep',
'accepts_reperepne',
'accepts_xacquire',
'accepts_xrelease',
'accepts_branch_hints',
'accepts_hle_without_lock',
'accepts_branch_hints'
);
SInstructionDefinitionFlag: array[TInstructionDefinitionFlag] of String = (
'conflict',
'accepts_evex_aaa',
'accepts_evex_z',
'privileged',
@ -1223,7 +1271,7 @@ const
{$REGION 'Class: TJSONEnumHelper'}
type
TJSONEnumHelper = record
private
strict private
class function ReadString(JSON: PJSONVariantData; const Name, Default: String;
const LowerCase: Boolean = true): String; static; inline;
public
@ -1259,6 +1307,116 @@ begin
end;
{$ENDREGION}
{$REGION 'Class: TJSONSetHelper'}
type
TJSONSetHelper<TSet> = record
strict private
class procedure GetEnumBounds(var MinValue, MaxValue: Integer); static; inline;
public
class function ReadValue(JSON: PJSONVariantData; const Name: String;
const ElementStrings: array of String): TSet; static;
class procedure WriteValue(JSON: PJSONVariantData; const Name: String;
const ElementStrings: array of String; Value: TSet); static;
end;
class procedure TJSONSetHelper<TSet>.GetEnumBounds(var MinValue, MaxValue: Integer);
var
TypInfo: PTypeInfo;
TypData: PTypeData;
begin
TypInfo := TypeInfo(TSet);
{$IFDEF DEBUG}
if (TypInfo^.Kind <> tkSet) then
begin
raise Exception.Create('Invalid generic type.');
end;
{$ENDIF}
TypData := GetTypeData(GetTypeData(TypInfo)^.CompType^);
{$IFDEF DEBUG}
if (TypData^.MinValue <> 0) then
begin
raise Exception.Create('The enum-type needs to be zero-based.');
end;
if (TypData^.MaxValue > 255) then
begin
raise Exception.Create('The enum-type''s maximum value needs the be lower than 256.');
end;
{$ENDIF}
MinValue := TypData^.MinValue;
MaxValue := TypData^.MaxValue;
end;
class function TJSONSetHelper<TSet>.ReadValue(JSON: PJSONVariantData; const Name: String;
const ElementStrings: array of String): TSet;
type
TSetType = set of 0..255;
var
A: PJSONVariantData;
MinValue,
MaxValue: Integer;
I, J: Integer;
begin
GetEnumBounds(MinValue, MaxValue);
{$IFDEF DEBUG}
if (MaxValue <> High(ElementStrings)) then
begin
raise Exception.Create('The size of the string-array does not match the size of the enum-type');
end;
{$ENDIF}
FillChar(Pointer(@Result)^, SizeOf(TSet), #0);
A := JSON^.Data(Name);
if (Assigned(A)) then
begin
if (A^.Kind <> jvArray) then
begin
raise Exception.CreateFmt('The "%s" field is not a valid JSON array.', [Name]);
end;
for I := 0 to A^.Count - 1 do
begin
for J := MinValue to MaxValue do
begin
if (LowerCase(A^.Item[I]) = ElementStrings[J]) then
begin
Include(TSetType(Pointer(@Result)^), J);
Break;
end;
end;
end;
end;
end;
class procedure TJSONSetHelper<TSet>.WriteValue(JSON: PJSONVariantData; const Name: String;
const ElementStrings: array of String; Value: TSet);
type
TSetType = set of 0..255;
var
A: TJSONVariantData;
MinValue,
MaxValue: Integer;
I: Integer;
begin
GetEnumBounds(MinValue, MaxValue);
{$IFDEF DEBUG}
if (MaxValue <> High(ElementStrings)) then
begin
raise Exception.Create('The size of the string-array does not match the size of the enum-type');
end;
{$ENDIF}
A.Init;
for I := MinValue to MaxValue do
begin
if (I in TSetType(Pointer(@Value)^)) then
begin
A.AddValue(ElementStrings[I]);
end;
end;
if (A.Count > 0) then
begin
JSON^.AddNameValue(Name, Variant(A));
end;
end;
{$ENDREGION}
{$REGION 'Class: TOpcodeExtensions'}
procedure TOpcodeExtensions.AssignTo(Dest: TPersistent);
var
@ -1301,10 +1459,8 @@ end;
procedure TOpcodeExtensions.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String);
var
V, A: PJSONVariantData;
V: PJSONVariantData;
I: Integer;
F: TExtBitFilter;
BitFilters: TExtBitFilters;
begin
V := JSON.Data(FieldName);
if (Assigned(V)) then
@ -1327,34 +1483,13 @@ begin
SetOperandSize(TExtOperandSize(I));
I := TJSONEnumHelper.ReadEnumValueFromString(V, 'adsize', SExtAddressSize);
SetAddressSize(TExtAddressSize(I));
A := V^.Data('bitfilters');
if (Assigned(A)) then
begin
if (A^.Kind <> jvArray) then
begin
raise Exception.Create('The "prefix_flags" field is not a valid JSON array.');
end;
BitFilters := [];
for I := 0 to A^.Count - 1 do
begin
for F := Low(SExtBitFilter) to High(SExtBitFilter) do
begin
if (LowerCase(A^.Item[I]) = SExtBitFilter[F]) then
begin
BitFilters := BitFilters + [F];
Break;
end;
end;
end;
SetBitFilters(BitFilters);
end;
SetBitFilters(TJSONSetHelper<TExtBitFilters>.ReadValue(V, 'bitfilters', SExtBitFilter));
end;
end;
procedure TOpcodeExtensions.SaveToJSON(JSON: PJSONVariantData; const FieldName: String);
var
V, A: TJSONVariantData;
F: TExtBitFilter;
V: TJSONVariantData;
begin
V.Init;
if (FMode <> imNeutral) then
@ -1371,15 +1506,7 @@ begin
V.AddNameValue('opsize', SExtOperandSize[FOperandSize]);
if (FAddressSize <> asNeutral) then
V.AddNameValue('adsize', SExtAddressSize[FAddressSize]);
A.Init;
for F in FBitFilters do
begin
A.AddValue(SExtBitFilter[F]);
end;
if (A.Count > 0) then
begin
V.AddNameValue('bitfilters', Variant(A));
end;
TJSONSetHelper<TExtBitFilters>.WriteValue(@V, 'bitfilters', SExtBitFilter, FBitFilters);
if (V.Count > 0) then
begin
JSON^.AddNameValue(FieldName, Variant(V));
@ -1493,49 +1620,15 @@ begin
end;
procedure TCPUIDFeatureFlags.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String);
var
A: PJSONVariantData;
I: Integer;
C: TCPUIDFeatureFlag;
Value: TCPUIDFeatureFlagSet;
begin
A := JSON.Data(FieldName);
if (Assigned(A)) then
begin
if (A^.Kind <> jvArray) then
begin
raise Exception.CreateFmt('The "%s" field is not a valid JSON array.', [FieldName]);
end;
Value := [];
for I := 0 to A^.Count - 1 do
begin
for C := Low(SCPUIDFeatureFlag) to High(SCPUIDFeatureFlag) do
begin
if (LowerCase(A^.Item[I]) = SCPUIDFeatureFlag[C]) then
begin
Value := Value + [C];
Break;
end;
end;
end;
SetFeatureFlags(Value);
end;
SetFeatureFlags(
TJSONSetHelper<TCPUIDFeatureFlagSet>.ReadValue(JSON, FieldName, SCPUIDFeatureFlag));
end;
procedure TCPUIDFeatureFlags.SaveToJSON(JSON: PJSONVariantData; const FieldName: String);
var
A: TJSONVariantData;
C: TCPUIDFeatureFlag;
begin
A.Init;
for C in FFeatureFlags do
begin
A.AddValue(SCPUIDFeatureFlag[C]);
end;
if (A.Count > 0) then
begin
JSON.AddNameValue(FieldName, Variant(A));
end;
TJSONSetHelper<TCPUIDFeatureFlagSet>.WriteValue(
JSON, FieldName, SCPUIDFeatureFlag, FFeatureFlags);
end;
procedure TCPUIDFeatureFlags.SetFeatureFlags(const Value: TCPUIDFeatureFlagSet);
@ -1577,49 +1670,13 @@ begin
end;
procedure TX86Registers.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String);
var
A: PJSONVariantData;
I: Integer;
R: TX86Register;
Value: TX86RegisterSet;
begin
A := JSON^.Data(FieldName);
if (Assigned(A)) then
begin
if (A^.Kind <> jvArray) then
begin
raise Exception.CreateFmt('The "%s" field is not a valid JSON array.', [FieldName]);
end;
Value := [];
for I := 0 to A^.Count - 1 do
begin
for R := Low(SX86Register) to High(SX86Register) do
begin
if (LowerCase(A^.Item[I]) = SX86Register[R]) then
begin
Value := Value + [R];
Break;
end;
end;
end;
SetRegisters(Value);
end;
SetRegisters(TJSONSetHelper<TX86RegisterSet>.ReadValue(JSON, FieldName, SX86Register));
end;
procedure TX86Registers.SaveToJSON(JSON: PJSONVariantData; const FieldName: String);
var
A: TJSONVariantData;
R: TX86Register;
begin
A.Init;
for R in FRegisters do
begin
A.AddValue(SX86Register[R]);
end;
if (A.Count > 0) then
begin
JSON.AddNameValue(FieldName, Variant(A));
end;
TJSONSetHelper<TX86RegisterSet>.WriteValue(JSON, FieldName, SX86Register, FRegisters);
end;
procedure TX86Registers.SetRegisters(const Value: TX86RegisterSet);
@ -2480,7 +2537,7 @@ var
begin
for I := Low(FOperands) to High(FOperands) do
begin
if (Assigned(FOperands[I])) then FOperands[I].Free;
FOperands[I].Free;
end;
inherited;
end;
@ -2683,12 +2740,12 @@ begin
end;
// Remove definition from the definition list
FEditor.UnregisterDefinition(Self);
if (Assigned(FExtensions)) then FExtensions.Free;
if (Assigned(FCPUID)) then FCPUID.Free;
if (Assigned(FOperands)) then FOperands.Free;
if (Assigned(FImplicitRead)) then FImplicitRead.Free;
if (Assigned(FImplicitWrite)) then FImplicitWrite.Free;
if (Assigned(FX86Flags)) then FX86Flags.Free;
FExtensions.Free;
FCPUID.Free;
FOperands.Free;
FImplicitRead.Free;
FImplicitWrite.Free;
FX86Flags.Free;
inherited;
end;
@ -2735,9 +2792,6 @@ end;
procedure TInstructionDefinition.LoadFromJSON(JSON: PJSONVariantData);
var
I: Integer;
A: PJSONVariantData;
F: TInstructionDefinitionFlag;
Flags: TInstructionDefinitionFlags;
begin
BeginUpdate;
try
@ -2764,27 +2818,9 @@ begin
FOperands.LoadFromJSON(JSON, 'operands');
FImplicitRead.LoadFromJSON(JSON, 'implicit_read');
FImplicitWrite.LoadFromJSON(JSON, 'implicit_write');
A := JSON.Data('flags');
if (Assigned(A)) then
begin
if (A^.Kind <> jvArray) then
begin
raise Exception.Create('The "flags" field is not a valid JSON array.');
end;
Flags := [];
for I := 0 to A^.Count - 1 do
begin
for F := Low(SInstructionDefinitionFlag) to High(SInstructionDefinitionFlag) do
begin
if (LowerCase(A^.Item[I]) = SInstructionDefinitionFlag[F]) then
begin
Flags := Flags + [F];
Break;
end;
end;
end;
SetFlags(Flags);
end;
SetFlags(TJSONSetHelper<TInstructionDefinitionFlags>.ReadValue(
JSON, 'flags', SInstructionDefinitionFlag));
SetPrefixFlags(TJSONSetHelper<TPrefixFlags>.ReadValue(JSON, 'prefix_flags', SPrefixFlag));
FX86Flags.LoadFromJSON(JSON, 'x86flags');
FComment := JSON^.Value['comment'];
finally
@ -2793,9 +2829,6 @@ begin
end;
procedure TInstructionDefinition.SaveToJSON(JSON: PJSONVariantData);
var
A: TJSONVariantData;
F: TInstructionDefinitionFlag;
begin
JSON^.AddNameValue('mnemonic', FMnemonic);
JSON^.AddNameValue('opcode', LowerCase(IntToHex(FOpcode, 2)));
@ -2806,15 +2839,9 @@ begin
FOperands.SaveToJSON(JSON, 'operands');
FImplicitRead.SaveToJSON(JSON, 'implicit_read');
FImplicitWrite.SaveToJSON(JSON, 'implicit_write');
A.Init;
for F in FFlags do
begin
A.AddValue(SInstructionDefinitionFlag[F]);
end;
if (A.Count > 0) then
begin
JSON^.AddNameValue('flags', Variant(A));
end;
TJSONSetHelper<TInstructionDefinitionFlags>.WriteValue(JSON, 'flags',
SInstructionDefinitionFlag, FFlags);
TJSONSetHelper<TPrefixFlags>.WriteValue(JSON, 'prefix_flags', SPrefixFlag, FPrefixFlags);
FX86Flags.SaveToJSON(JSON, 'x86flags');
if (FComment <> '') then
begin
@ -2946,6 +2973,15 @@ begin
end;
end;
procedure TInstructionDefinition.SetPrefixFlags(const Value: TPrefixFlags);
begin
if (FPrefixFlags <> Value) then
begin
FPrefixFlags := Value;
UpdateValues;
end;
end;
procedure TInstructionDefinition.Update;
begin
UpdatePosition;
@ -2965,6 +3001,33 @@ begin
begin
Include(Conflicts, idcOperands);
end;
if ((pfAcceptsXACQUIRE in FPrefixFlags) or (pfAcceptsXRELEASE in FPrefixFlags)) and
(not ((pfAcceptsLock in FPrefixFlags) or (pfAcceptsHLEWithoutLock in FPrefixFlags))) then
begin
Include(Conflicts, idcPrefixFlags);
end;
if ((pfAcceptsXACQUIRE in FPrefixFlags) or (pfAcceptsXRELEASE in FPrefixFlags)) and
((pfAcceptsREP in FPrefixFlags) or (pfAcceptsREPEREPNE in FPrefixFlags)) then
begin
Include(Conflicts, idcPrefixFlags);
end;
if ((pfAcceptsLock in FPrefixFlags) or (pfAcceptsXACQUIRE in FPrefixFlags) or
(pfAcceptsXRELEASE in FPrefixFlags)) and (not (FOperands.Operands[0].OperandType in [
optMem8, optMem16, optMem32, optMem64, optMem128])) then
begin
Include(Conflicts, idcPrefixFlags);
end;
if ((pfAcceptsREP in FPrefixFlags) and (pfAcceptsREPEREPNE in FPrefixFlags)) then
begin
Include(Conflicts, idcPrefixFlags);
end;
if (pfAcceptsBranchHints in FPrefixFlags) and (not (FOperands.Operands[0].OperandType in [
optRel8, optRel16, optRel32, optRel64])) then
begin
Include(Conflicts, idcPrefixFlags);
end;
if (FX86Flags.HasConflicts) then
begin
Include(Conflicts, idcX86Flags);
@ -3071,7 +3134,7 @@ end;
destructor TInstructionFilter.Destroy;
begin
Assert((FItemCount = 0) and (FParent = nil));
if Assigned(FDefinitions) then
if (Assigned(FDefinitions)) then
begin
Assert(FDefinitions.Count = 0);
FDefinitions.Free;
@ -3865,11 +3928,23 @@ var
I: Integer;
JSONDefinitionList, JSONDefinition: TJSONVariantData;
begin
// Sort definitions by mnemonic
// Sort definitions
Comparison :=
function(const Left, Right: TInstructionDefinition): Integer
begin
Result := CompareStr(Left.Mnemonic, Right.Mnemonic);
if (Result = 0) then
begin
Result := Ord(Left.Encoding) - Ord(Right.Encoding);
end;
if (Result = 0) then
begin
Result := Ord(Left.OpcodeMap) - Ord(Right.OpcodeMap);
end;
if (Result = 0) then
begin
Result := Left.Opcode - Right.Opcode;
end;
end;
FDefinitions.Sort(TComparer<TInstructionDefinition>.Construct(Comparison));
// Save to JSON

File diff suppressed because it is too large Load Diff

View File

@ -247,36 +247,36 @@ typedef uint32_t ZydisPrefixFlags;
/**
* @brief The instruction accepts the string prefixes (rep/repe/repz/repne/repnz).
*/
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPE 0x00400000
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPE 0x00800000
/**
* @brief The instruction accepts the string prefixes (rep/repe/repz/repne/repnz).
*/
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPZ 0x00400000
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPZ 0x00800000
/**
* @brief The instruction accepts the string prefixes (rep/repe/repz/repne/repnz).
*/
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPNE 0x00400000
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPNE 0x01000000
/**
* @brief The instruction accepts the string prefixes (rep/repe/repz/repne/repnz).
*/
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPNZ 0x00400000
#define ZYDIS_PREFIXFLAG_ACCEPTS_REPNZ 0x01000000
/**
* @brief The instruction has multiple prefixes of the first prefix-group (0x0F, 0xF3, 0xF2).
*/
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP1 0x00800000
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP1 0x02000000
/**
* @brief The instruction has multiple prefixes of the second prefix-group (0x2E, 0x36,
* 0x3E, 0x26, 0x64, 0x65).
*/
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP2 0x01000000
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP2 0x04000000
/**
* @brief The instruction has multiple prefixes of the third prefix-group (0x66).
*/
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP3 0x02000000
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP3 0x08000000
/**
* @brief The instruction has multiple prefixes of the fourth prefix-group (0x67).
*/
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP4 0x04000000
#define ZYDIS_PREFIXFLAG_MULTIPLE_GRP4 0x10000000
/* ---------------------------------------------------------------------------------------------- */
/* Instruction encoding */

View File

@ -0,0 +1,15 @@
typedef struct ZydisInstructionDefinition_
{
uint32_t mnemonic : 11;
uint32_t operandsId : 9;
uint32_t evexBFunctionality : 2;
uint32_t hasEvexAAA : 1;
uint32_t hasEvexZ : 1;
uint32_t acceptsLock : 1;
uint32_t acceptsREP : 1;
uint32_t acceptsREPEREPNE : 1;
uint32_t acceptsXACQUIRE : 1;
uint32_t acceptsXRELEASE : 1;
uint32_t acceptsHLEWithoutLock : 1;
uint32_t acceptsBranchHints : 1;
} ZydisInstructionDefinition;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -41,21 +41,69 @@ extern "C" {
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Instruction table */
/* Generated types */
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisInstructionTableNode datatype.
*/
typedef void* ZydisInstructionTableNode;
// MSVC does not like types other than (un-)signed int for bitfields
#ifdef ZYDIS_MSVC
# pragma warning(push)
# pragma warning(disable:4214)
#endif
/* ---------------------------------------------------------------------------------------------- */
#pragma pack(push, 1)
/**
* @brief Defines the @c ZydisInstructionTableNodeType datatype.
*/
typedef uint8_t ZydisInstructionTableNodeType;
/**
* @brief Defines the @c ZydisInstructionTableNodeValue datatype.
*/
typedef uint16_t ZydisInstructionTableNodeValue;
/**
* @brief Defines the @c ZydisInstructionTableNode struct.
*
* This struct is static for now, because its size is sufficient to encode up to 65535
* instruction filters (what is about 10 times more than we currently need).
*/
typedef struct ZydisInstructionTableNode_
{
ZydisInstructionTableNodeType type;
ZydisInstructionTableNodeValue value;
} ZydisInstructionTableNode;
/**
* @brief Defines the @c ZydisSemanticOperandType datatype.
*/
typedef uint8_t ZydisSemanticOperandType;
/**
* @brief Defines the @c ZydisOperandDefinition struct.
*
* This struct is static for now, because adding more operand-types oder encodings requires
* code changes anyways.
*/
typedef struct ZydisOperandDefinition_
{
ZydisSemanticOperandType type : 7;
ZydisOperandEncoding encoding : 5;
ZydisOperandAccess access : 2;
} ZydisOperandDefinition;
#include <Zydis/Internal/GeneratedTypes.inc>
#pragma pack(pop)
#ifdef ZYDIS_MSVC
# pragma warning(pop)
#endif
/* ---------------------------------------------------------------------------------------------- */
/* Instruction Table */
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Values that represent zydis instruction table node types.
*/
@ -144,20 +192,10 @@ enum ZydisInstructionTableNodeTypes
ZYDIS_NODETYPE_FILTER_EVEXB = 0x14
};
/**
* @brief Defines the @c ZydisInstructionTableNodeValue datatype.
*/
typedef uint16_t ZydisInstructionTableNodeValue;
/* ---------------------------------------------------------------------------------------------- */
/* Operand definition */
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisSemanticOperandType datatype.
*/
typedef uint8_t ZydisSemanticOperandType;
/**
* @brief Values that represent semantic operand types.
*/
@ -246,34 +284,10 @@ enum ZydisSemanticOperandTypes
ZYDIS_SEM_OPERAND_TYPE_ST0
};
/**
* @brief Defines the @c ZydisOperandDefinition struct.
*/
typedef struct ZydisOperandDefinition_
{
/**
* @brief The semantic operand type.
*/
ZydisSemanticOperandType type;
/**
* @brief The operand encoding.
*/
ZydisOperandEncoding encoding;
/**
* @brief The operand access-mode.
*/
ZydisOperandAccess access;
} ZydisOperandDefinition;
/* ---------------------------------------------------------------------------------------------- */
/* Instruction definition */
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisEvexBFunctionality datatype .
*/
typedef uint8_t ZydisEvexBFunctionality;
/**
* @brief Values that represent zydis evex.b-functionalities.
*/
@ -285,66 +299,18 @@ enum ZydisEvexBFunctionalities
ZYDIS_EVEXB_FUNCTIONALITY_SAE
};
/**
* @brief Defines the @c ZydisInstructionDefinition struct.
*/
typedef struct ZydisInstructionDefinition_
{
/**
* @brief The instruction mnemonic.
*/
ZydisInstructionMnemonic mnemonic;
/**
* @brief The number of used operands.
*/
uint8_t operandCount;
/**
* @brief The operand-definitions.
*/
ZydisOperandDefinition operands[5];
/**
* @brief The evex.b functionality.
*/
ZydisEvexBFunctionality evexBFunctionality;
bool hasEvexAAA;
bool hasEvexZ;
} ZydisInstructionDefinition;
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Functions */
/* ============================================================================================== */
/**
* @brief Returns the type of the specified instruction table node.
*
* @param node The node.
*
* @return The type of the specified instruction table node.
*/
ZYDIS_NO_EXPORT ZydisInstructionTableNodeType ZydisInstructionTableGetNodeType(
const ZydisInstructionTableNode node);
/**
* @brief Returns the value of the specified instruction table node.
*
* @param node The node.
*
* @return The value of the specified instruction table node.
*/
ZYDIS_NO_EXPORT ZydisInstructionTableNodeValue ZydisInstructionTableGetNodeValue(
const ZydisInstructionTableNode* node);
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Returns the root node of the instruction table.
*
* @return The root node of the instruction table.
*/
ZYDIS_NO_EXPORT ZydisInstructionTableNode ZydisInstructionTableGetRootNode();
ZYDIS_NO_EXPORT const ZydisInstructionTableNode* ZydisInstructionTableGetRootNode();
/**
* @brief Returns the child node of @c parent specified by @c index.
@ -354,18 +320,25 @@ ZYDIS_NO_EXPORT ZydisInstructionTableNode ZydisInstructionTableGetRootNode();
*
* @return The specified child node.
*/
ZYDIS_NO_EXPORT ZydisInstructionTableNode ZydisInstructionTableGetChildNode(
const ZydisInstructionTableNode parent, uint16_t index);
ZYDIS_NO_EXPORT const ZydisInstructionTableNode* ZydisInstructionTableGetChildNode(
const ZydisInstructionTableNode* parent, uint16_t index);
/**
* @brief Returns the instruction definition that is linked to the given @c node.
* @brief Returns the instruction- and operand-definition that is linked to the given @c node.
*
* @param node The instruction definition node.
* @param definition A pointer to a variable that receives a pointer to the
* instruction-definition.
* @param operands A pointer to a variable that receives a pointer to the first
* operand-definition of the instruction.
* @param operandCount A pointer to a variable that receives the number of operand-definitions
* for the instruction.
*
* @return Pointer to the instruction definition.
* @return @c TRUE, if @c node contained a valid instruction-definition, @c FALSE if not.
*/
ZYDIS_NO_EXPORT ZydisInstructionDefinition ZydisInstructionDefinitionByNode(
const ZydisInstructionTableNode node);
ZYDIS_NO_EXPORT bool ZydisInstructionTableGetDefinition(const ZydisInstructionTableNode* node,
const ZydisInstructionDefinition** definition, const ZydisOperandDefinition** operands,
uint8_t* operandCount);
/* ============================================================================================== */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1529,31 +1529,32 @@ static ZydisDecoderStatus ZydisDecodeOperand(ZydisInstructionDecoder* decoder,
*
* @param decoder A pointer to the @c ZydisInstructionDecoder decoder instance.
* @param info A pointer to the @c ZydisInstructionInfo struct.
* @param definition A pointer to the @c ZydisInstructionDefinition struct.
* @param operands A pointer to the first operand-definition of the instruction.
* @param operandCount The number of operands.
*
* @return A zydis decoder status code.
*/
static ZydisDecoderStatus ZydisDecodeOperands(ZydisInstructionDecoder* decoder,
ZydisInstructionInfo* info, const ZydisInstructionDefinition* definition)
ZydisInstructionInfo* info, const ZydisOperandDefinition* operands, uint8_t operandCount)
{
ZYDIS_ASSERT(decoder);
ZYDIS_ASSERT(info);
ZYDIS_ASSERT(definition);
ZYDIS_ASSERT(definition->operandCount <= 6);
ZYDIS_ASSERT(operands);
ZYDIS_ASSERT(operandCount < 6);
info->operandCount = definition->operandCount;
for (int i = 0; i < definition->operandCount; ++i)
info->operandCount = operandCount;
for (int i = 0; i < operandCount; ++i)
{
ZydisSemanticOperandType type = definition->operands[i].type;
ZydisSemanticOperandType type = operands[i].type;
if (type == ZYDIS_SEM_OPERAND_TYPE_UNUSED)
{
break;
}
ZydisInstructionEncoding encoding = definition->operands[i].encoding;
ZydisInstructionEncoding encoding = operands[i].encoding;
ZydisDecoderStatus status =
ZydisDecodeOperand(decoder, info, &info->operand[i], type, encoding);
info->operand[i].encoding = encoding;
info->operand[i].access = definition->operands[i].access;
info->operand[i].access = operands[i].access;
if (status != ZYDIS_STATUS_DECODER_SUCCESS)
{
info->instrFlags |= ZYDIS_INSTRFLAG_ERROR_OPERANDS;
@ -1607,129 +1608,86 @@ static ZydisDecoderStatus ZydisDecodeOperands(ZydisInstructionDecoder* decoder,
/* ---------------------------------------------------------------------------------------------- */
static void ZydisFinalizeInstructionInfo(ZydisInstructionInfo* info)
/**
* @brief Finalizes the @c ZydisInstructionInfo struct by adding additional information.
*
* @param info A pointer to the @c ZydisInstructionInfo struct.
* @param definition A pointer to the @c ZydisInstructionDefinition struct.
*/
static void ZydisFinalizeInstructionInfo(ZydisInstructionInfo* info,
const ZydisInstructionDefinition* definition)
{
ZYDIS_ASSERT(info);
ZYDIS_ASSERT(definition);
// TODO: Encode all these things in the instruction definition
// Adjust prefix flags
switch (info->mnemonic)
{
case ZYDIS_MNEMONIC_ADD:
case ZYDIS_MNEMONIC_ADC:
case ZYDIS_MNEMONIC_AND:
case ZYDIS_MNEMONIC_BTC:
case ZYDIS_MNEMONIC_BTR:
case ZYDIS_MNEMONIC_BTS:
case ZYDIS_MNEMONIC_CMPXCHG:
case ZYDIS_MNEMONIC_CMPXCHG8B:
case ZYDIS_MNEMONIC_CMPXCHG16B:
case ZYDIS_MNEMONIC_DEC:
case ZYDIS_MNEMONIC_INC:
case ZYDIS_MNEMONIC_NEG:
case ZYDIS_MNEMONIC_NOT:
case ZYDIS_MNEMONIC_OR:
case ZYDIS_MNEMONIC_SBB:
case ZYDIS_MNEMONIC_SUB:
case ZYDIS_MNEMONIC_XOR:
case ZYDIS_MNEMONIC_XADD:
case ZYDIS_MNEMONIC_XCHG:
if (info->operand[0].type == ZYDIS_OPERAND_TYPE_MEMORY)
// Set prefix-flags
if (definition->acceptsLock)
{
info->prefixFlags |= ZYDIS_PREFIXFLAG_ACCEPTS_LOCK;
}
break;
case ZYDIS_MNEMONIC_MOVSB:
case ZYDIS_MNEMONIC_MOVSW:
case ZYDIS_MNEMONIC_MOVSD:
case ZYDIS_MNEMONIC_MOVSQ:
case ZYDIS_MNEMONIC_CMPS: // TODO: Only the string-instruction! We will use flags later.
case ZYDIS_MNEMONIC_SCASB:
case ZYDIS_MNEMONIC_SCASW:
case ZYDIS_MNEMONIC_SCASD:
case ZYDIS_MNEMONIC_SCASQ:
case ZYDIS_MNEMONIC_LODSB:
case ZYDIS_MNEMONIC_LODSW:
case ZYDIS_MNEMONIC_LODSD:
case ZYDIS_MNEMONIC_LODSQ:
case ZYDIS_MNEMONIC_STOSB:
case ZYDIS_MNEMONIC_STOSW:
case ZYDIS_MNEMONIC_STOSD:
case ZYDIS_MNEMONIC_STOSQ:
case ZYDIS_MNEMONIC_INSB:
case ZYDIS_MNEMONIC_INSW:
case ZYDIS_MNEMONIC_INSD:
case ZYDIS_MNEMONIC_OUTSB:
case ZYDIS_MNEMONIC_OUTSW:
case ZYDIS_MNEMONIC_OUTSD:
info->prefixFlags |= ZYDIS_PREFIXFLAG_ACCEPTS_REP | ZYDIS_PREFIXFLAG_ACCEPTS_REPNE;
break;
case ZYDIS_MNEMONIC_JO:
case ZYDIS_MNEMONIC_JNO:
case ZYDIS_MNEMONIC_JS:
case ZYDIS_MNEMONIC_JNS:
case ZYDIS_MNEMONIC_JE:
case ZYDIS_MNEMONIC_JNE:
case ZYDIS_MNEMONIC_JB:
case ZYDIS_MNEMONIC_JAE:
case ZYDIS_MNEMONIC_JBE:
case ZYDIS_MNEMONIC_JA:
case ZYDIS_MNEMONIC_JL:
case ZYDIS_MNEMONIC_JGE:
case ZYDIS_MNEMONIC_JLE:
case ZYDIS_MNEMONIC_JG:
case ZYDIS_MNEMONIC_JP:
case ZYDIS_MNEMONIC_JNP:
case ZYDIS_MNEMONIC_JCXZ:
case ZYDIS_MNEMONIC_JECXZ:
case ZYDIS_MNEMONIC_JRCXZ:
if (definition->acceptsREP)
{
info->prefixFlags |= ZYDIS_PREFIXFLAG_ACCEPTS_REP;
} else if (definition->acceptsREPEREPNE)
{
info->prefixFlags |= ZYDIS_PREFIXFLAG_ACCEPTS_REPE | ZYDIS_PREFIXFLAG_ACCEPTS_REPNE;
}
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_LOCK) || (definition->acceptsHLEWithoutLock))
{
if (definition->acceptsXACQUIRE && (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REPE))
{
info->prefixFlags |= ZYDIS_PREFIXFLAG_HAS_XACQUIRE;
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_REPE;
}
if (definition->acceptsXRELEASE && (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REPNE))
{
info->prefixFlags |= ZYDIS_PREFIXFLAG_HAS_XRELEASE;
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_REPNE;
}
}
if (definition->acceptsBranchHints)
{
if (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_SEGMENT_CS)
{
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_SEGMENT_CS;
info->prefixFlags |= ZYDIS_PREFIXFLAG_HAS_BRANCH_NOT_TAKEN;
} else
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_SEGMENT_CS;
}
if (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_SEGMENT_DS)
{
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_SEGMENT_DS;
info->prefixFlags |= ZYDIS_PREFIXFLAG_HAS_BRANCH_TAKEN;
}
break;
default:
break;
}
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_ACCEPTS_LOCK) &&
((info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REP) ||
(info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REPNE)))
{
if (info->mnemonic != ZYDIS_MNEMONIC_CMPXCHG16B)
{
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_LOCK) ||
(info->mnemonic == ZYDIS_MNEMONIC_XCHG))
{
if (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REPNE)
{
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_REPNE;
info->prefixFlags |= ZYDIS_PREFIXFLAG_HAS_XACQUIRE;
}
{
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_REP;
info->prefixFlags |= ZYDIS_PREFIXFLAG_HAS_XRELEASE;
}
} else
if ((info->mnemonic == ZYDIS_MNEMONIC_MOV) && ((info->opcode == 0x88) ||
(info->opcode == 0x89) || (info->opcode == 0xC6) || (info->opcode == 0xC7)))
{
if (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REP)
{
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_REP;
info->prefixFlags |= ZYDIS_PREFIXFLAG_HAS_XRELEASE;
}
}
info->prefixFlags &= ~ZYDIS_PREFIXFLAG_HAS_SEGMENT_DS;
}
}
// Adjust instruction mnemonics
// Set AVX-512 info
if (info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX)
{
if (definition->hasEvexAAA && info->details.evex.aaa)
{
info->avx.maskRegister = ZYDIS_REGISTER_K0 + info->details.evex.aaa;
}
if (definition->hasEvexZ && info->details.evex.z)
{
info->avx.maskMode = ZYDIS_AVX_MASKMODE_ZERO;
} else
{
info->avx.maskMode = ZYDIS_AVX_MASKMODE_MERGE;
}
switch (definition->evexBFunctionality)
{
case ZYDIS_EVEXB_FUNCTIONALITY_BC:
break;
case ZYDIS_EVEXB_FUNCTIONALITY_RC:
info->avx.roundingMode =
(((info->details.evex.l2 & 0x01) << 1) | info->details.evex.l) + 1;
case ZYDIS_EVEXB_FUNCTIONALITY_SAE:
info->avx.sae = true;
default:
info->avx.broadcast = ZYDIS_AVX_BCSTMODE_INVALID;
}
}
// Replace XCHG rAX, rAX with NOP alias
if (info->mnemonic == ZYDIS_MNEMONIC_XCHG)
{
if (((info->operand[0].reg == ZYDIS_REGISTER_RAX) &&
@ -2199,11 +2157,11 @@ static ZydisDecoderStatus ZydisDecodeOpcode(ZydisInstructionDecoder* decoder,
ZYDIS_ASSERT(info);
// Iterate through the instruction table
ZydisInstructionTableNode node = ZydisInstructionTableGetRootNode();
const ZydisInstructionTableNode* node = ZydisInstructionTableGetRootNode();
ZydisInstructionTableNodeType nodeType;
do
{
nodeType = ZydisInstructionTableGetNodeType(node);
nodeType = node->type;
uint16_t index = 0;
ZydisDecoderStatus status = 0;
switch (nodeType)
@ -2220,16 +2178,22 @@ static ZydisDecoderStatus ZydisDecodeOpcode(ZydisInstructionDecoder* decoder,
case ZYDIS_NODETYPE_DEFINITION_4OP:
case ZYDIS_NODETYPE_DEFINITION_5OP:
{
const ZydisInstructionDefinition definition = ZydisInstructionDefinitionByNode(node);
//ZYDIS_ASSERT(definition); // TODO: Pointer?
info->mnemonic = definition.mnemonic;
const ZydisInstructionDefinition* definition = NULL;
const ZydisOperandDefinition* operands = NULL;
uint8_t operandCount;
ZydisInstructionTableGetDefinition(node, &definition, &operands, &operandCount);
ZYDIS_ASSERT(definition);
ZYDIS_ASSERT(operands);
info->mnemonic = (ZydisInstructionMnemonic)definition->mnemonic;
if (info->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
{
// Save input-buffer state and decode dummy operands
uint8_t bufferPosRead = decoder->buffer.posRead;
uint8_t length = info->length;
ZYDIS_CHECK(ZydisDecodeOperands(decoder, info, &definition)); // TODO: Reference?
ZYDIS_CHECK(ZydisDecodeOperands(decoder, info, operands, operandCount));
// Read actual 3dnow opcode
ZYDIS_CHECK(ZydisInputNext(decoder, info, &info->opcode));
// Restore input-buffer state
@ -2247,7 +2211,7 @@ static ZydisDecoderStatus ZydisDecodeOpcode(ZydisInstructionDecoder* decoder,
node = ZydisInstructionTableGetChildNode(node, 0x0F);
node = ZydisInstructionTableGetChildNode(node, 0x0F);
node = ZydisInstructionTableGetChildNode(node, info->opcode);
if (ZydisInstructionTableGetNodeType(node) == ZYDIS_NODETYPE_INVALID)
if (node->type == ZYDIS_NODETYPE_INVALID)
{
info->instrFlags |= ZYDIS_INSTRFLAG_ERROR_UNDEFINED;
return ZYDIS_STATUS_DECODER_UNDEFINED_INSTRUCTION;
@ -2255,43 +2219,18 @@ static ZydisDecoderStatus ZydisDecodeOpcode(ZydisInstructionDecoder* decoder,
node = ZydisInstructionTableGetChildNode(node,
(info->details.modrm.mod == 0x3) ? 1 : 0);
// Decode actual operands and fix the instruction-info
ZydisInstructionDefinition definition2 = ZydisInstructionDefinitionByNode(node);
//ZYDIS_ASSERT(definition); // TODO: Pointer
ZYDIS_CHECK(ZydisDecodeOperands(decoder, info, &definition2)); // TODO: Reference
info->mnemonic = definition2.mnemonic;
ZydisFinalizeInstructionInfo(info);
ZydisInstructionTableGetDefinition(node, &definition, &operands, &operandCount);
ZYDIS_ASSERT(definition);
ZYDIS_ASSERT(operands);
ZYDIS_CHECK(ZydisDecodeOperands(decoder, info, operands, operandCount));
info->mnemonic = (ZydisInstructionMnemonic)definition->mnemonic;
ZydisFinalizeInstructionInfo(info, definition);
return ZydisInputNext(decoder, info, &info->opcode);
}
ZYDIS_CHECK(ZydisDecodeOperands(decoder, info, &definition)); // TODO: Reference
ZydisFinalizeInstructionInfo(info);
ZYDIS_CHECK(ZydisDecodeOperands(decoder, info, operands, operandCount));
ZydisFinalizeInstructionInfo(info, definition);
if (info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX)
{
if (definition.hasEvexAAA && info->details.evex.aaa)
{
info->avx.maskRegister = ZYDIS_REGISTER_K0 + info->details.evex.aaa;
}
if (definition.hasEvexZ && info->details.evex.z)
{
info->avx.maskMode = ZYDIS_AVX_MASKMODE_ZERO;
} else
{
info->avx.maskMode = ZYDIS_AVX_MASKMODE_MERGE;
}
switch (definition.evexBFunctionality)
{
case ZYDIS_EVEXB_FUNCTIONALITY_BC:
break;
case ZYDIS_EVEXB_FUNCTIONALITY_RC:
info->avx.roundingMode =
(((info->details.evex.l2 & 0x01) << 1) | info->details.evex.l) + 1;
case ZYDIS_EVEXB_FUNCTIONALITY_SAE:
info->avx.sae = true;
default:
info->avx.broadcast = ZYDIS_AVX_BCSTMODE_INVALID;
}
}
return ZYDIS_STATUS_DECODER_SUCCESS;
}
case ZYDIS_NODETYPE_FILTER_OPCODE:

View File

@ -440,18 +440,26 @@ static ZydisStatus ZydisFormatterFormatInstructionIntel(ZydisInstructionFormatte
{
size_t offset = 0;
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_ACCEPTS_REP) &&
(info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REP))
{
ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset,
(formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "rep "));
}
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_ACCEPTS_REPE) &&
(info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REPE))
{
ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset,
(formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "repe "));
}
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_ACCEPTS_REPNE) &&
(info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REPNE))
{
ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset,
(formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "repne "));
}
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_ACCEPTS_REP) && (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_REP))
{
ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset,
(formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "rep "));
}
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_ACCEPTS_LOCK) && (info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_LOCK))
if ((info->prefixFlags & ZYDIS_PREFIXFLAG_ACCEPTS_LOCK) &&
(info->prefixFlags & ZYDIS_PREFIXFLAG_HAS_LOCK))
{
ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset,
(formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "lock "));

View File

@ -25,81 +25,12 @@
***************************************************************************************************/
#include <assert.h>
#include <string.h>
#include <Zydis/Internal/InstructionTable.h>
/* ============================================================================================== */
/* Data tables */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Generated types & Macros */
/* ---------------------------------------------------------------------------------------------- */
// TODO: Auto generate these structs and macros
typedef struct ZydisInternalInstructionTableNode_
{
ZydisInstructionTableNodeType type;
ZydisInstructionTableNodeValue value;
} ZydisInternalInstructionTableNode;
#define ZYDIS_MAKE_INSTRUCTIONTABLENODE(type, value) \
{ type, value }
#define ZYDIS_GET_INSTRUCTIONTABLENODE_TYPE(node) \
node.type
#define ZYDIS_GET_INSTRUCTIONTABLENODE_VALUE(node) \
node.value
//typedef struct ZydisInternalOperandDefinition_
//{
// unsigned int type : 8;
// unsigned int encoding : 8;
// unsigned int access : 2;
//} ZydisInternalOperandDefinition;
//
//#define ZYDIS_MAKE_OPERANDDEFINITION(type, encoding, access) \
// { type, encoding, access }
//#define ZYDIS_GET_OPERANDDEFINITION_TYPE(def) \
// (ZydisSemanticOperandType)def.type
//#define ZYDIS_GET_OPERANDDEFINITION_ENCODING(def) \
// (ZydisOperandEncoding)def.encoding
//#define ZYDIS_GET_OPERANDDEFINITION_ACCESS(def) \
// (ZydisOperandAccess)def.access
typedef uint8_t ZydisInternalOperandDefinition[2];
#define ZYDIS_MAKE_OPERANDDEFINITION(type, encoding, access) \
{ type, ((encoding & 0x3F) << 2) | (access & 0x03) }
#define ZYDIS_GET_OPERANDDEFINITION_TYPE(def) \
def[0]
#define ZYDIS_GET_OPERANDDEFINITION_ENCODING(def) \
((def[1] >> 2) & 0x3F)
#define ZYDIS_GET_OPERANDDEFINITION_ACCESS(def) \
(def[1] & 0x03)
typedef struct ZydisInternalInstructionDefinition_
{
unsigned int mnemonic : 11;
unsigned int operandRef : 9;
unsigned int evexBFunctionality : 2;
unsigned int hasEvexAAA : 1;
unsigned int hasEvexZ : 1;
} ZydisInternalInstructionDefinition;
#define ZYDIS_MAKE_INSTRUCTIONDEFINITION(mnemonic, operandRef, evexBFunctionality, hasEvexAAA, hasEvexZ) \
{ mnemonic, operandRef, evexBFunctionality, hasEvexAAA, hasEvexZ }
#define ZYDIS_GET_INSTRUCTIONDEFINITION_MNEMONIC(def) \
(ZydisInstructionMnemonic)def.mnemonic
#define ZYDIS_GET_INSTRUCTIONDEFINITION_OPERANDREF(def) \
def.operandRef
#define ZYDIS_GET_INSTRUCTIONDEFINITION_EVEXBFUNCTIONALITY(def) \
(ZydisEvexBFunctionality)def.evexBFunctionality
#define ZYDIS_GET_INSTRUCTIONDEFINITION_HASEVEXAAA(def) \
def.hasEvexAAA
#define ZYDIS_GET_INSTRUCTIONDEFINITION_HASEVEXZ(def) \
def.hasEvexZ
/* ---------------------------------------------------------------------------------------------- */
/* Forward declarations */
/* ---------------------------------------------------------------------------------------------- */
@ -109,7 +40,7 @@ typedef struct ZydisInternalInstructionDefinition_
*
* Indexed by the numeric value of the opcode.
*/
extern const ZydisInternalInstructionTableNode filterOpcode[][256];
extern const ZydisInstructionTableNode filterOpcode[][256];
/**
* @brief Contains all vex-map filters.
@ -132,7 +63,7 @@ extern const ZydisInternalInstructionTableNode filterOpcode[][256];
* E = F2_0F38
* F = F2_0F3A
*/
extern const ZydisInternalInstructionTableNode filterVEX[][16];
extern const ZydisInstructionTableNode filterVEX[][16];
/**
* @brief Contains all xop-map filters.
@ -143,7 +74,7 @@ extern const ZydisInternalInstructionTableNode filterVEX[][16];
* 2 = xop9
* 3 = xopA
*/
extern const ZydisInternalInstructionTableNode filterXOP[][4];
extern const ZydisInstructionTableNode filterXOP[][4];
/**
* @brief Contains all instruction-mode filters.
@ -152,7 +83,7 @@ extern const ZydisInternalInstructionTableNode filterXOP[][4];
* 0 = 64 bit mode required
* 1 = 64 bit mode excluded
*/
extern const ZydisInternalInstructionTableNode filterMode[][2];
extern const ZydisInstructionTableNode filterMode[][2];
/**
* @brief Contains all mandatory-prefix switch tables.
@ -163,7 +94,7 @@ extern const ZydisInternalInstructionTableNode filterMode[][2];
* 2 = F3
* 3 = F2
*/
extern const ZydisInternalInstructionTableNode filterMandatoryPrefix[][4];
extern const ZydisInstructionTableNode filterMandatoryPrefix[][4];
/**
* @brief Contains all modrm.mod filters.
@ -172,21 +103,21 @@ extern const ZydisInternalInstructionTableNode filterMandatoryPrefix[][4];
* 0 = [modrm_mod == !11] = memory
* 1 = [modrm_mod == 11] = register
*/
extern const ZydisInternalInstructionTableNode filterModrmMod[][2];
extern const ZydisInstructionTableNode filterModrmMod[][2];
/**
* @brief Contains all modrm.reg filters.
*
* Indexed by the numeric value of the modrm_reg field.
*/
extern const ZydisInternalInstructionTableNode filterModrmReg[][8];
extern const ZydisInstructionTableNode filterModrmReg[][8];
/**
* @brief Contains all modrm.rm filters.
*
* Indexed by the numeric value of the modrm_rm field.
*/
extern const ZydisInternalInstructionTableNode filterModrmRm[][8];
extern const ZydisInstructionTableNode filterModrmRm[][8];
/**
* @brief Contains all operand-size filters.
@ -195,7 +126,7 @@ extern const ZydisInternalInstructionTableNode filterModrmRm[][8];
* 0 = 16bit = 0x66 prefix in 32 bit mode
* 1 = 32bit = 0x66 prefix in 16 bit mode
*/
extern const ZydisInternalInstructionTableNode filterOperandSize[][2];
extern const ZydisInstructionTableNode filterOperandSize[][2];
/**
* @brief Contains all address-size filters.
@ -205,207 +136,169 @@ extern const ZydisInternalInstructionTableNode filterOperandSize[][2];
* 1 = 32
* 2 = 64
*/
extern const ZydisInternalInstructionTableNode filterAddressSize[][3];
extern const ZydisInstructionTableNode filterAddressSize[][3];
/**
* @brief Contains all rex/vex/evex.w filters.
*
* Indexed by the numeric value of the rex/vex/evex.w field.
*/
extern const ZydisInternalInstructionTableNode filterREXW[][2];
extern const ZydisInstructionTableNode filterREXW[][2];
/**
* @brief Contains all vex.l filters.
*
* Indexed by the numeric value of the vex/evex.l field.
*/
extern const ZydisInternalInstructionTableNode filterVEXL[][2];
extern const ZydisInstructionTableNode filterVEXL[][2];
/**
* @brief Contains all evex.l' filters.
*
* Indexed by the numeric value of the evex.l' field.
*/
extern const ZydisInternalInstructionTableNode filterEVEXL2[][2];
extern const ZydisInstructionTableNode filterEVEXL2[][2];
/**
* @brief Contains all evex.b filters.
*
* Indexed by the numeric value of the evex.b field.
*/
extern const ZydisInternalInstructionTableNode filterEVEXB[][2];
extern const ZydisInstructionTableNode filterEVEXB[][2];
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Contains all operand-definitions with 1 operand.
*/
extern const ZydisInternalOperandDefinition operandDefinitions1[][1];
extern const ZydisOperandDefinition operandDefinitions1[][1];
/**
* @brief Contains all operand-definitions with 2 operands.
*/
extern const ZydisInternalOperandDefinition operandDefinitions2[][2];
extern const ZydisOperandDefinition operandDefinitions2[][2];
/**
* @brief Contains all operand-definitions with 3 operands.
*/
extern const ZydisInternalOperandDefinition operandDefinitions3[][3];
extern const ZydisOperandDefinition operandDefinitions3[][3];
/**
* @brief Contains all operand-definitions with 4 operands.
*/
extern const ZydisInternalOperandDefinition operandDefinitions4[][4];
extern const ZydisOperandDefinition operandDefinitions4[][4];
/**
* @brief Contains all operand-definitions with 5 operands.
*/
extern const ZydisInternalOperandDefinition operandDefinitions5[][5];
extern const ZydisOperandDefinition operandDefinitions5[][5];
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Contains all instruction-definitions.
*/
extern const ZydisInternalInstructionDefinition instructionDefinitions[];
extern const ZydisInstructionDefinition instructionDefinitions[];
/* ---------------------------------------------------------------------------------------------- */
/* Functions */
/* ---------------------------------------------------------------------------------------------- */
ZydisInstructionTableNodeType ZydisInstructionTableGetNodeType(
const ZydisInstructionTableNode node)
const ZydisInstructionTableNode* ZydisInstructionTableGetRootNode()
{
return (ZydisInstructionTableNodeType)
ZYDIS_GET_INSTRUCTIONTABLENODE_TYPE((*(ZydisInternalInstructionTableNode*)node));
static const ZydisInstructionTableNode root = { ZYDIS_NODETYPE_FILTER_OPCODE, 0x00000000 };
return &root;
}
ZydisInstructionTableNodeValue ZydisInstructionTableGetNodeValue(
const ZydisInstructionTableNode* node)
const ZydisInstructionTableNode* ZydisInstructionTableGetChildNode(
const ZydisInstructionTableNode* parent, uint16_t index)
{
return (ZydisInstructionTableNodeValue)
ZYDIS_GET_INSTRUCTIONTABLENODE_VALUE((*(ZydisInternalInstructionTableNode*)node));
}
/* ---------------------------------------------------------------------------------------------- */
ZydisInstructionTableNode ZydisInstructionTableGetRootNode()
{
static const ZydisInternalInstructionTableNode root =
ZYDIS_MAKE_INSTRUCTIONTABLENODE(ZYDIS_NODETYPE_FILTER_OPCODE, 0x00000000);
return (ZydisInstructionTableNode)&root;
}
ZydisInstructionTableNode ZydisInstructionTableGetChildNode(
const ZydisInstructionTableNode parent, uint16_t index)
{
ZydisInstructionTableNodeType nodeType = ZydisInstructionTableGetNodeType(parent);
uint16_t tableIndex = ZydisInstructionTableGetNodeValue(parent);
switch (nodeType)
switch (parent->type)
{
case ZYDIS_NODETYPE_FILTER_OPCODE:
ZYDIS_ASSERT(index < 256);
return (ZydisInstructionTableNode*)&filterOpcode[tableIndex][index];
return &filterOpcode[parent->value][index];
case ZYDIS_NODETYPE_FILTER_VEX:
ZYDIS_ASSERT(index < 16);
return (ZydisInstructionTableNode*)&filterVEX[tableIndex][index];
return &filterVEX[parent->value][index];
case ZYDIS_NODETYPE_FILTER_XOP:
ZYDIS_ASSERT(index < 4);
return (ZydisInstructionTableNode*)&filterXOP[tableIndex][index];
return &filterXOP[parent->value][index];
case ZYDIS_NODETYPE_FILTER_MODE:
ZYDIS_ASSERT(index < 3);
return (ZydisInstructionTableNode*)&filterMode[tableIndex][index];
return &filterMode[parent->value][index];
case ZYDIS_NODETYPE_FILTER_MANDATORYPREFIX:
ZYDIS_ASSERT(index < 4);
return (ZydisInstructionTableNode*)&filterMandatoryPrefix[tableIndex][index];
return &filterMandatoryPrefix[parent->value][index];
case ZYDIS_NODETYPE_FILTER_MODRMMOD:
ZYDIS_ASSERT(index < 2);
return (ZydisInstructionTableNode*)&filterModrmMod[tableIndex][index];
return &filterModrmMod[parent->value][index];
case ZYDIS_NODETYPE_FILTER_MODRMREG:
ZYDIS_ASSERT(index < 8);
return (ZydisInstructionTableNode*)&filterModrmReg[tableIndex][index];
return &filterModrmReg[parent->value][index];
case ZYDIS_NODETYPE_FILTER_MODRMRM:
ZYDIS_ASSERT(index < 8);
return (ZydisInstructionTableNode*)&filterModrmRm[tableIndex][index];
return &filterModrmRm[parent->value][index];
case ZYDIS_NODETYPE_FILTER_OPERANDSIZE:
ZYDIS_ASSERT(index < 2);
return (ZydisInstructionTableNode*)&filterOperandSize[tableIndex][index];
return &filterOperandSize[parent->value][index];
case ZYDIS_NODETYPE_FILTER_ADDRESSSIZE:
ZYDIS_ASSERT(index < 3);
return (ZydisInstructionTableNode*)&filterAddressSize[tableIndex][index];
return &filterAddressSize[parent->value][index];
case ZYDIS_NODETYPE_FILTER_REXW:
ZYDIS_ASSERT(index < 2);
return (ZydisInstructionTableNode*)&filterREXW[tableIndex][index];
return &filterREXW[parent->value][index];
case ZYDIS_NODETYPE_FILTER_VEXL:
ZYDIS_ASSERT(index < 2);
return (ZydisInstructionTableNode*)&filterVEXL[tableIndex][index];
return &filterVEXL[parent->value][index];
case ZYDIS_NODETYPE_FILTER_EVEXL2:
ZYDIS_ASSERT(index < 2);
return (ZydisInstructionTableNode*)&filterEVEXL2[tableIndex][index];
return &filterEVEXL2[parent->value][index];
case ZYDIS_NODETYPE_FILTER_EVEXB:
ZYDIS_ASSERT(index < 2);
return (ZydisInstructionTableNode*)&filterEVEXB[tableIndex][index];
return &filterEVEXB[parent->value][index];
default:
ZYDIS_UNREACHABLE;
}
static const ZydisInternalInstructionTableNode invalid =
ZYDIS_MAKE_INSTRUCTIONTABLENODE(ZYDIS_NODETYPE_INVALID, 0x00000000);
return (ZydisInstructionTableNode)&invalid;
static const ZydisInstructionTableNode invalid = { ZYDIS_NODETYPE_INVALID, 0x00000000 };
return &invalid;
}
ZydisInstructionDefinition ZydisInstructionDefinitionByNode(
const ZydisInstructionTableNode node)
bool ZydisInstructionTableGetDefinition(const ZydisInstructionTableNode* node,
const ZydisInstructionDefinition** definition, const ZydisOperandDefinition** operands,
uint8_t* operandCount)
{
ZydisInstructionDefinition result;
memset(&result, 0, sizeof(result));
const ZydisInternalInstructionDefinition* definition =
&instructionDefinitions[ZydisInstructionTableGetNodeValue(node)];
result.mnemonic = ZYDIS_GET_INSTRUCTIONDEFINITION_MNEMONIC((*definition));
result.evexBFunctionality = ZYDIS_GET_INSTRUCTIONDEFINITION_EVEXBFUNCTIONALITY((*definition));
result.hasEvexAAA = ZYDIS_GET_INSTRUCTIONDEFINITION_HASEVEXAAA((*definition));
result.hasEvexZ = ZYDIS_GET_INSTRUCTIONDEFINITION_HASEVEXZ((*definition));
const ZydisInternalOperandDefinition* operand = NULL;
switch (ZydisInstructionTableGetNodeType(node))
*definition = &instructionDefinitions[node->value];
switch (node->type)
{
case ZYDIS_NODETYPE_DEFINITION_0OP:
result.operandCount = 0;
*operandCount = 0;
break;
case ZYDIS_NODETYPE_DEFINITION_1OP:
result.operandCount = 1;
operand = operandDefinitions1[ZYDIS_GET_INSTRUCTIONDEFINITION_OPERANDREF((*definition))];
*operandCount = 1;
*operands = operandDefinitions1[(*definition)->operandsId];
break;
case ZYDIS_NODETYPE_DEFINITION_2OP:
result.operandCount = 2;
operand = operandDefinitions2[ZYDIS_GET_INSTRUCTIONDEFINITION_OPERANDREF((*definition))];
*operandCount = 2;
*operands = operandDefinitions2[(*definition)->operandsId];
break;
case ZYDIS_NODETYPE_DEFINITION_3OP:
result.operandCount = 3;
operand = operandDefinitions3[ZYDIS_GET_INSTRUCTIONDEFINITION_OPERANDREF((*definition))];
*operandCount = 3;
*operands = operandDefinitions3[(*definition)->operandsId];
break;
case ZYDIS_NODETYPE_DEFINITION_4OP:
result.operandCount = 4;
operand = operandDefinitions4[ZYDIS_GET_INSTRUCTIONDEFINITION_OPERANDREF((*definition))];
*operandCount = 4;
*operands = operandDefinitions4[(*definition)->operandsId];
break;
case ZYDIS_NODETYPE_DEFINITION_5OP:
result.operandCount = 5;
operand = operandDefinitions5[ZYDIS_GET_INSTRUCTIONDEFINITION_OPERANDREF((*definition))];
*operandCount = 5;
*operands = operandDefinitions5[(*definition)->operandsId];
break;
default:
ZYDIS_UNREACHABLE;
return false;
}
if (result.operandCount > 0)
{
for (int i = 0; i < result.operandCount; ++i)
{
result.operands[i].type = ZYDIS_GET_OPERANDDEFINITION_TYPE((*operand));
result.operands[i].encoding = ZYDIS_GET_OPERANDDEFINITION_ENCODING((*operand));
result.operands[i].access = ZYDIS_GET_OPERANDDEFINITION_ACCESS((*operand));
++operand;
}
}
return result;
return true;
}
/* ---------------------------------------------------------------------------------------------- */
@ -413,7 +306,7 @@ ZydisInstructionDefinition ZydisInstructionDefinitionByNode(
/* ---------------------------------------------------------------------------------------------- */
#define ZYDIS_INVALID \
ZYDIS_MAKE_INSTRUCTIONTABLENODE(ZYDIS_NODETYPE_INVALID, 0x00000000)
{ ZYDIS_NODETYPE_INVALID, 0x00000000 }
#define ZYDIS_FILTER(type, id) \
{ type, id }
#define ZYDIS_DEFINITION_0OP(id) \
@ -440,15 +333,16 @@ ZydisInstructionDefinition ZydisInstructionDefinitionByNode(
#undef ZYDIS_DEFINITION_4OP
#undef ZYDIS_DEFINITION_5OP
#undef ZYDIS_MAKE_INSTRUCTIONTABLENODE
/* ---------------------------------------------------------------------------------------------- */
/* Operand definitions */
/* ---------------------------------------------------------------------------------------------- */
#define ZYDIS_OPERAND_DEFINITION(type, encoding, access) \
{ type, encoding, access }
#include <Zydis/Internal/OperandDefinitions.inc>
#undef ZYDIS_MAKE_OPERANDDEFINITION
#undef ZYDIS_OPERAND_DEFINITION
/* ---------------------------------------------------------------------------------------------- */
/* Instruction definitions */
@ -456,7 +350,4 @@ ZydisInstructionDefinition ZydisInstructionDefinitionByNode(
#include <Zydis/Internal/InstructionDefinitions.inc>
#undef ZYDIS_MAKE_AVX512INFO
#undef ZYDIS_MAKE_INSTRUCTIONDEFINITION
/* ============================================================================================== */