Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 9 additions & 64 deletions src/Zydis.Generator.Core/Definitions/Builder/EncodingRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private static PhysicalInstructionEncoding GetPhysicalInstructionEncoding(Instru
(definition.GetDecisionNodeIndex(ModrmRmNode.NodeDefinition.Instance) is not null);

var hasIS4 = false;
PhysicalInstructionEncodingDisp? displacement = null;
SizeTable? displacement = null;
List<PhysicalInstructionEncodingImm>? immediates = null;

foreach (var operand in definition.Operands ?? [])
Expand Down Expand Up @@ -83,31 +83,31 @@ private static PhysicalInstructionEncoding GetPhysicalInstructionEncoding(Instru
break;

case OperandEncoding.Disp8:
displacement = new() { Width16 = 8, Width32 = 8, Width64 = 8 };
displacement = new SizeTable(8, 8, 8);
break;

case OperandEncoding.Disp16:
displacement = new() { Width16 = 16, Width32 = 16, Width64 = 16 };
displacement = new SizeTable(16, 16, 16);
break;

case OperandEncoding.Disp32:
displacement = new() { Width16 = 32, Width32 = 32, Width64 = 32 };
displacement = new SizeTable(32, 32, 32);
break;

case OperandEncoding.Disp64:
displacement = new() { Width16 = 64, Width32 = 64, Width64 = 64 };
displacement = new SizeTable(64, 64, 64);
break;

case OperandEncoding.Disp16_32_64:
displacement = new() { Width16 = 16, Width32 = 32, Width64 = 64 };
displacement = new SizeTable(16, 32, 64);
break;

case OperandEncoding.Disp32_32_64:
displacement = new() { Width16 = 32, Width32 = 32, Width64 = 648 };
displacement = new SizeTable(32, 32, 64);
break;

case OperandEncoding.Disp16_32_32:
displacement = new() { Width16 = 16, Width32 = 32, Width64 = 32 };
displacement = new SizeTable(16, 32, 32);
break;

case OperandEncoding.Uimm8:
Expand Down Expand Up @@ -226,7 +226,7 @@ public sealed class PhysicalInstructionEncoding :
#pragma warning restore CA1036
{
public bool HasModrm { get; init; }
public PhysicalInstructionEncodingDisp? Displacement { get; init; }
public SizeTable? Displacement { get; init; }
public PhysicalInstructionEncodingImm? Immediate0 { get; init; }
public PhysicalInstructionEncodingImm? Immediate1 { get; init; }
public bool ForceRegForm { get; init; }
Expand Down Expand Up @@ -279,61 +279,6 @@ public override int GetHashCode()

#pragma warning disable CA1036

public sealed class PhysicalInstructionEncodingDisp :
IComparable<PhysicalInstructionEncodingDisp>,
IComparable,
IEquatable<PhysicalInstructionEncodingDisp>

#pragma warning restore CA1036
{
public int Width16 { get; init; }
public int Width32 { get; init; }
public int Width64 { get; init; }

public int CompareTo(PhysicalInstructionEncodingDisp? other)
{
return FluentComparer.Compare(this, other,
x => x.Compare(x => x.Width16),
x => x.Compare(x => x.Width32),
x => x.Compare(x => x.Width64)
);
}

public int CompareTo(object? obj)
{
return CompareTo(obj as PhysicalInstructionEncodingDisp);
}

public bool Equals(PhysicalInstructionEncodingDisp? other)
{
if (other is null)
{
return false;
}

if (ReferenceEquals(this, other))
{
return true;
}

return (Width16 == other.Width16) &&
(Width32 == other.Width32) &&
(Width64 == other.Width64);
}

public override bool Equals(object? obj)
{
return ReferenceEquals(this, obj) || (obj is PhysicalInstructionEncodingDisp other) && Equals(other);
}

public override int GetHashCode()
{
return HashCode.Combine(Width16, Width32, Width64);
}
}

#pragma warning disable CA1036

[Emittable(0, "size")]
public sealed class PhysicalInstructionEncodingImm :
IComparable<PhysicalInstructionEncodingImm>,
Expand Down
78 changes: 75 additions & 3 deletions src/Zydis.Generator.Core/Definitions/Builder/OperandsRegistry.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;

using Zydis.Generator.Core.Helpers;
using Zydis.Generator.Enums;

namespace Zydis.Generator.Core.Definitions.Builder;

internal sealed class OperandsRegistry
{
private readonly List<InstructionOperand> _operands = new();
private readonly ConditionalWeakTable<InstructionDefinition, PhysicalInstructionEncoding> _lut = new();

private readonly SortedSet<SizeTable> _sizes = new();

private readonly SortedSet<OperandDetails> _details = new();

public IReadOnlyList<InstructionOperand> Operands => _operands;

public IReadOnlySet<SizeTable> Sizes => _sizes;

public IReadOnlySet<OperandDetails> OperandsDetails => _details;

public void Initialize(IEnumerable<InstructionDefinition> definitions)
{
foreach (var definition in definitions.OrderByDescending(x => x.NumberOfOperands))
Expand Down Expand Up @@ -47,6 +57,11 @@ private void InsertOperands(IReadOnlyList<InstructionOperand> operands)
}

_operands.AddRange(operands);
foreach (var operand in operands)
{
_sizes.Add(GetSizeTable(operand));
_details.Add(GetDetails(operand));
}
}

private int FindOperandsIndex(IReadOnlyList<InstructionOperand> operands)
Expand All @@ -62,11 +77,68 @@ private int FindOperandsIndex(IReadOnlyList<InstructionOperand> operands)

if (operands.SequenceEqual(_operands.Skip(index).Take(operands.Count)))
{
var test = _operands[index];
return index;
}
}

return -1;
}

public static SizeTable GetSizeTable(InstructionOperand operand)
{
return new SizeTable(operand.Width16, operand.Width32, operand.Width64);
}

public static OperandDetails GetDetails(InstructionOperand operand)
{
var type = "OTHER";
if (operand.Type is OperandType.ImplicitReg)
{
type = operand.Register.GetRegisterClass() switch
{
RegisterClass.GPROSZ => "GPR_OSZ",
RegisterClass.GPRASZ => "GPR_ASZ",
RegisterClass.GPRSSZ => "GPR_SSZ",
_ => "STATIC"
};
type = operand.Register switch
{
Register.ASZIP => "IP_ASZ",
Register.SSZIP => "IP_SSZ",
Register.SSZFLAGS => "FLAGS_SSZ",
_ => type
};
}
else if (operand.Type is OperandType.ImplicitMem)
{
type = "MEMORY";
}

return new OperandDetails(type, operand.Encoding, operand.Register, operand.MemorySegment, operand.MemoryBase);
}
}

#pragma warning disable CA1036

public sealed record OperandDetails(string Type, OperandEncoding Encoding, Register Register, SegmentRegister? MemorySegment = null, BaseRegister? MemoryBase = null) :
IComparable<OperandDetails>,
IComparable

#pragma warning restore CA1036
{
public int CompareTo(OperandDetails? other)
{
return FluentComparer.Compare(this, other,
x => x.Compare(x => x.Type),
x => x.Compare(x => x.Encoding),
x => x.Compare(x => x.Register),
x => x.Compare(x => x.MemorySegment),
x => x.Compare(x => x.MemoryBase)
);
}

public int CompareTo(object? obj)
{
return CompareTo(obj as OperandDetails);
}
}
124 changes: 74 additions & 50 deletions src/Zydis.Generator.Core/Definitions/Emitters/OperandsEmitter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -27,75 +28,98 @@ public static async Task EmitAsync(StreamWriter writer, OperandsRegistry operand
.WriteInitializerList()
.BeginList();
var operandDeclaration = new ObjectDeclaration<InstructionOperand>();
var opDeclaration = new SimpleObjectDeclaration(InitializerType.Designated, "encoding", "reg", "mem");
var sizes = operandsRegistry.Sizes.ToList();
var details = operandsRegistry.OperandsDetails.ToList();
Debug.Assert(sizes.Count < byte.MaxValue);
Debug.Assert(details.Count < byte.MaxValue);

foreach (var operand in operandsRegistry.Operands)
{
var operandEntry = operandsWriter.CreateObjectWriter(operandDeclaration)
.WriteExpression("type", "ZYDIS_SEMANTIC_OPTYPE_{0}", operand.Type.ToZydisString())
.WriteExpression("visibility", "ZYDIS_OPERAND_VISIBILITY_{0}", operand.Visibility.ToZydisString())
.WriteExpression("actions", "ZYDIS_OPERAND_ACTION_{0}", operand.Access.ToZydisString())
.WriteExpression("element_type", operand.ElementType.ToZydisString())
.WriteBool("is_multisource4", operand.IsMultiSource4)
.WriteBool("ignore_seg_override", operand.IgnoreSegmentOverride)
.WriteInteger("size_reference", sizes.BinarySearch(OperandsRegistry.GetSizeTable(operand)), 2, true)
.WriteInteger("details_reference", details.BinarySearch(OperandsRegistry.GetDetails(operand)), 2, true);

operandsWriter.WriteObject(operandEntry);
}

operandsWriter.EndList();
declarationWriter.EndDeclaration();
declarationWriter.WriteNewline();
declarationWriter.WriteNewline();

var sizesWriter = declarationWriter
.BeginDeclaration("static const", "ZyanU16", "OPERAND_SIZES[][3]")
.WriteInitializerList()
.BeginList();
var sizeArrayDeclaration = new ArrayObjectDeclaration(3);

foreach (var sizeTable in sizes)
{
var sizeTableEntry = new ObjectWriter(sizeArrayDeclaration, null)
.WriteInteger(0, sizeTable.Width16)
.WriteInteger(1, sizeTable.Width32)
.WriteInteger(2, sizeTable.Width64);
sizesWriter.WriteObject(sizeTableEntry);
}

sizesWriter.EndList();
declarationWriter.EndDeclaration();
declarationWriter.WriteNewline();
declarationWriter.WriteNewline();

var detailsWriter = declarationWriter
.BeginDeclaration("static const", "ZydisOperandDetails", "OPERAND_DETAILS[]")
.WriteInitializerList()
.BeginList();
var detailsDeclaration = new SimpleObjectDeclaration(InitializerType.Designated, "encoding", "reg", "mem");
var regOuterDeclaration = new SimpleObjectDeclaration("type", "reg");
var regInnerDeclaration = new SimpleObjectDeclaration(InitializerType.Designated, "reg", "id");
var memDeclaration = new SimpleObjectDeclaration("seg", "base");

foreach (var operand in operandsRegistry.Operands)
foreach (var opDetails in details)
{
var operandEntry = operandsWriter.CreateObjectWriter(operandDeclaration);
var opEntry = operandEntry.CreateObjectWriter(opDeclaration);
if (operand.Type is OperandType.ImplicitReg)
var detailsEntry = detailsWriter.CreateObjectWriter(detailsDeclaration);
if (opDetails.Type == "MEMORY")
{
var memEntry = detailsEntry.CreateObjectWriter(memDeclaration);
memEntry
.WriteInteger("seg", (int)(opDetails.MemorySegment ?? SegmentRegister.None))
.WriteExpression("base", opDetails.MemoryBase!.Value.ToZydisString());
detailsEntry.WriteObject("mem", memEntry);
}
else if (opDetails.Type == "OTHER")
{
detailsEntry.WriteExpression("encoding", "ZYDIS_OPERAND_ENCODING_{0}", opDetails.Encoding.ToZydisString());
}
else
{
var regOuterEntry = opEntry.CreateObjectWriter(regOuterDeclaration);
var regOuterEntry = detailsEntry.CreateObjectWriter(regOuterDeclaration);
var regInnerEntry = regOuterEntry.CreateObjectWriter(regInnerDeclaration);
var type = operand.Register.GetRegisterClass() switch
{
RegisterClass.GPROSZ => "GPR_OSZ",
RegisterClass.GPRASZ => "GPR_ASZ",
RegisterClass.GPRSSZ => "GPR_SSZ",
_ => "STATIC"
};
type = operand.Register switch
{
Register.ASZIP => "IP_ASZ",
Register.SSZIP => "IP_SSZ",
Register.SSZFLAGS => "FLAGS_SSZ",
_ => type
};

if (type == "STATIC")
if (opDetails.Type == "STATIC")
{
regInnerEntry.WriteExpression("reg", "ZYDIS_REGISTER_{0}", operand.Register.ToZydisString());
regInnerEntry.WriteExpression("reg", "ZYDIS_REGISTER_{0}", opDetails.Register.ToZydisString());
regOuterEntry.WriteExpression("type", "ZYDIS_IMPLREG_TYPE_STATIC");

}
else
{
regInnerEntry.WriteInteger("id", operand.Register.GetRegisterId() & 0x3F, 4, true);
regOuterEntry.WriteExpression("type", "ZYDIS_IMPLREG_TYPE_{0}", type);
regInnerEntry.WriteInteger("id", opDetails.Register.GetRegisterId() & 0x3F, 4, true);
regOuterEntry.WriteExpression("type", "ZYDIS_IMPLREG_TYPE_{0}", opDetails.Type);
}

regOuterEntry.WriteObject("reg", regInnerEntry);
opEntry.WriteObject("reg", regOuterEntry);
}
else if (operand.Type is OperandType.ImplicitMem)
{
var memEntry = opEntry.CreateObjectWriter(memDeclaration);
memEntry
.WriteInteger("seg", (int)(operand.MemorySegment ?? SegmentRegister.None))
.WriteExpression("base", operand.MemoryBase!.Value.ToZydisString());
opEntry.WriteObject("mem", memEntry);
}
else
{
opEntry.WriteExpression("encoding", "ZYDIS_OPERAND_ENCODING_{0}", operand.Encoding.ToZydisString());
detailsEntry.WriteObject("reg", regOuterEntry);
}
operandEntry
.WriteExpression("type", "ZYDIS_SEMANTIC_OPTYPE_{0}", operand.Type.ToZydisString())
.WriteExpression("visibility", "ZYDIS_OPERAND_VISIBILITY_{0}", operand.Visibility.ToZydisString())
.WriteExpression("actions", "ZYDIS_OPERAND_ACTION_{0}", operand.Access.ToZydisString())
.WriteIntegerArray("size", operand.Width16, operand.Width32, operand.Width64)
.WriteExpression("element_type", operand.ElementType.ToZydisString())
.WriteObject("op", opEntry)
.WriteBool("is_multisource4", operand.IsMultiSource4)
.WriteBool("ignore_seg_override", operand.IgnoreSegmentOverride);

operandsWriter.WriteObject(operandEntry);
detailsWriter.WriteObject(detailsEntry);
}

operandsWriter.EndList();
detailsWriter.EndList();
declarationWriter.EndDeclaration();

await writer.WriteLineAsync().ConfigureAwait(false);
Expand Down
Loading
Loading