using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using Disarm.InternalDisassembly; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: InternalsVisibleTo("Disarm.Tests")] [assembly: AssemblyCompany("N/A")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Samboy063 2022")] [assembly: AssemblyDescription("Pure-C# Disassembler for the ARM64 Instruction Set")] [assembly: AssemblyFileVersion("2022.1.0.0")] [assembly: AssemblyInformationalVersion("2022.1.0-master.26+cb8877f.cb8877f0dc1eecd6cbfba219991f8b00be2d41bc")] [assembly: AssemblyProduct("Disarm")] [assembly: AssemblyTitle("Disarm")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/SamboyCoding/Disarm.git")] [assembly: AssemblyVersion("2022.1.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace Disarm { public enum Arm64ArrangementSpecifier { None, TwoD, FourH, FourS, TwoS, EightH, EightB, SixteenB } public enum Arm64ConditionCode : byte { EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV, NONE } public readonly struct Arm64DisassemblyResult { public readonly List Instructions; public readonly ulong VirtualAddress; public ulong EndVirtualAddress => VirtualAddress + (ulong)(Instructions.Count * 4); public Arm64DisassemblyResult(List instructions, ulong virtualAddress) { Instructions = instructions; VirtualAddress = virtualAddress; } public Arm64DisassemblyResult() { Instructions = new List(); VirtualAddress = 0uL; } } public static class Arm64EnumExtensions { public static bool IsSp(this Arm64Register register) { if (register != Arm64Register.X31) { return register == Arm64Register.W31; } return true; } public static bool IsZr(this Arm64Register register) { return register.IsSp(); } public static Arm64ConditionCode Invert(this Arm64ConditionCode conditionCode) { return conditionCode switch { Arm64ConditionCode.EQ => Arm64ConditionCode.NE, Arm64ConditionCode.NE => Arm64ConditionCode.EQ, Arm64ConditionCode.CS => Arm64ConditionCode.CC, Arm64ConditionCode.CC => Arm64ConditionCode.CS, Arm64ConditionCode.MI => Arm64ConditionCode.PL, Arm64ConditionCode.PL => Arm64ConditionCode.MI, Arm64ConditionCode.VS => Arm64ConditionCode.VC, Arm64ConditionCode.VC => Arm64ConditionCode.VS, Arm64ConditionCode.HI => Arm64ConditionCode.LS, Arm64ConditionCode.LS => Arm64ConditionCode.HI, Arm64ConditionCode.GE => Arm64ConditionCode.LT, Arm64ConditionCode.LT => Arm64ConditionCode.GE, Arm64ConditionCode.GT => Arm64ConditionCode.LE, Arm64ConditionCode.LE => Arm64ConditionCode.GT, _ => conditionCode, }; } public static string ToDisassemblyString(this Arm64ArrangementSpecifier specifier) { return specifier switch { Arm64ArrangementSpecifier.TwoD => "2D", Arm64ArrangementSpecifier.FourH => "4H", Arm64ArrangementSpecifier.FourS => "4S", Arm64ArrangementSpecifier.TwoS => "2S", Arm64ArrangementSpecifier.EightH => "8H", Arm64ArrangementSpecifier.EightB => "8B", Arm64ArrangementSpecifier.SixteenB => "16B", _ => throw new ArgumentOutOfRangeException("specifier", specifier, null), }; } } public enum Arm64ExtendType : byte { UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX, NONE } public struct Arm64Instruction { public ulong Address { get; internal set; } public Arm64Mnemonic Mnemonic { get; internal set; } public Arm64MnemonicCategory MnemonicCategory { get; internal set; } public Arm64ConditionCode MnemonicConditionCode { get; internal set; } public Arm64OperandKind Op0Kind { get; internal set; } public Arm64OperandKind Op1Kind { get; internal set; } public Arm64OperandKind Op2Kind { get; internal set; } public Arm64OperandKind Op3Kind { get; internal set; } public Arm64Register Op0Reg { get; internal set; } public Arm64Register Op1Reg { get; internal set; } public Arm64Register Op2Reg { get; internal set; } public Arm64Register Op3Reg { get; internal set; } public Arm64VectorElement Op0VectorElement { get; internal set; } public Arm64VectorElement Op1VectorElement { get; internal set; } public Arm64VectorElement Op2VectorElement { get; internal set; } public Arm64VectorElement Op3VectorElement { get; internal set; } public long Op0Imm { get; internal set; } public long Op1Imm { get; internal set; } public long Op2Imm { get; internal set; } public long Op3Imm { get; internal set; } public double Op0FpImm { get; internal set; } public double Op1FpImm { get; internal set; } public double Op2FpImm { get; internal set; } public double Op3FpImm { get; internal set; } public Arm64ArrangementSpecifier Op0Arrangement { get; internal set; } public Arm64ArrangementSpecifier Op1Arrangement { get; internal set; } public Arm64ArrangementSpecifier Op2Arrangement { get; internal set; } public Arm64ArrangementSpecifier Op3Arrangement { get; internal set; } public Arm64ShiftType Op0ShiftType { get; internal set; } public Arm64ShiftType Op1ShiftType { get; internal set; } public Arm64ShiftType Op2ShiftType { get; internal set; } public Arm64ShiftType Op3ShiftType { get; internal set; } public Arm64Register MemBase { get; internal set; } public Arm64Register MemAddendReg { get; internal set; } public bool MemIsPreIndexed { get; internal set; } public long MemOffset { get; internal set; } public Arm64ExtendType MemExtendType { get; internal set; } public Arm64ShiftType MemShiftType { get; internal set; } public int MemExtendOrShiftAmount { get; internal set; } public Arm64ExtendType FinalOpExtendType { get; internal set; } public Arm64ShiftType FinalOpShiftType { get; internal set; } public Arm64ConditionCode FinalOpConditionCode { get; internal set; } public ulong BranchTarget { get { Arm64Mnemonic mnemonic = Mnemonic; if (mnemonic != Arm64Mnemonic.B && mnemonic != Arm64Mnemonic.BL) { throw new Exception("Branch target not available for this instruction, must be a B or BL"); } return Address + (ulong)Op0Imm; } } public Arm64Instruction() { Address = 0uL; Mnemonic = Arm64Mnemonic.INVALID; MnemonicCategory = Arm64MnemonicCategory.Unspecified; Op0Kind = Arm64OperandKind.None; Op1Kind = Arm64OperandKind.None; Op2Kind = Arm64OperandKind.None; Op3Kind = Arm64OperandKind.None; Op0Reg = Arm64Register.INVALID; Op1Reg = Arm64Register.INVALID; Op2Reg = Arm64Register.INVALID; Op3Reg = Arm64Register.INVALID; Op0Imm = 0L; Op1Imm = 0L; Op2Imm = 0L; Op3Imm = 0L; Op0FpImm = double.NaN; Op1FpImm = double.NaN; Op2FpImm = double.NaN; Op3FpImm = double.NaN; Op0Arrangement = Arm64ArrangementSpecifier.None; Op1Arrangement = Arm64ArrangementSpecifier.None; Op2Arrangement = Arm64ArrangementSpecifier.None; Op3Arrangement = Arm64ArrangementSpecifier.None; MemBase = Arm64Register.INVALID; MemAddendReg = Arm64Register.INVALID; MemIsPreIndexed = false; MemOffset = 0L; MemExtendOrShiftAmount = 0; Op0VectorElement = default(Arm64VectorElement); Op1VectorElement = default(Arm64VectorElement); Op2VectorElement = default(Arm64VectorElement); Op3VectorElement = default(Arm64VectorElement); MnemonicConditionCode = Arm64ConditionCode.NONE; FinalOpConditionCode = Arm64ConditionCode.NONE; FinalOpExtendType = Arm64ExtendType.NONE; FinalOpShiftType = Arm64ShiftType.NONE; MemExtendType = Arm64ExtendType.NONE; MemShiftType = Arm64ShiftType.NONE; Op0ShiftType = Arm64ShiftType.NONE; Op1ShiftType = Arm64ShiftType.NONE; Op2ShiftType = Arm64ShiftType.NONE; Op3ShiftType = Arm64ShiftType.NONE; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("0x"); stringBuilder.Append(Address.ToString("X8")); stringBuilder.Append(' '); stringBuilder.Append(Mnemonic); if (MnemonicConditionCode != Arm64ConditionCode.NONE) { stringBuilder.Append('.').Append(MnemonicConditionCode); } stringBuilder.Append(' '); if (AppendOperand(stringBuilder, Op0Kind, Op0Reg, Op0VectorElement, Op0Arrangement, Op1ShiftType, Op0Imm, Op0FpImm) && AppendOperand(stringBuilder, Op1Kind, Op1Reg, Op1VectorElement, Op1Arrangement, Op1ShiftType, Op1Imm, Op1FpImm, comma: true) && AppendOperand(stringBuilder, Op2Kind, Op2Reg, Op2VectorElement, Op2Arrangement, Op1ShiftType, Op2Imm, Op2FpImm, comma: true)) { AppendOperand(stringBuilder, Op3Kind, Op3Reg, Op3VectorElement, Op3Arrangement, Op1ShiftType, Op3Imm, Op3FpImm, comma: true); } if (FinalOpExtendType != Arm64ExtendType.NONE) { stringBuilder.Append(", ").Append(FinalOpExtendType); } else if (FinalOpShiftType != Arm64ShiftType.NONE) { stringBuilder.Append(", ").Append(FinalOpShiftType); } else if (FinalOpConditionCode != Arm64ConditionCode.NONE) { stringBuilder.Append(", ").Append(FinalOpConditionCode); } return stringBuilder.ToString(); } private bool AppendOperand(StringBuilder sb, Arm64OperandKind kind, Arm64Register reg, Arm64VectorElement vectorElement, Arm64ArrangementSpecifier regArrangement, Arm64ShiftType shiftType, long imm, double fpImm, bool comma = false) { if (kind == Arm64OperandKind.None) { return false; } if (comma) { sb.Append(", "); } switch (kind) { case Arm64OperandKind.Register: sb.Append(reg); if (regArrangement != 0) { sb.Append('.').Append(regArrangement.ToDisassemblyString()); } break; case Arm64OperandKind.VectorRegisterElement: sb.Append(reg).Append('.').Append(vectorElement); break; case Arm64OperandKind.Immediate: if (shiftType != Arm64ShiftType.NONE) { sb.Append(shiftType).Append(' '); } sb.Append("0x").Append(imm.ToString("X")); break; case Arm64OperandKind.FloatingPointImmediate: sb.Append(fpImm.ToString(CultureInfo.InvariantCulture)); break; case Arm64OperandKind.ImmediatePcRelative: sb.Append("0x").Append(((long)Address + imm).ToString("X")); break; case Arm64OperandKind.Memory: AppendMemory(sb); break; } return true; } private void AppendMemory(StringBuilder sb) { sb.Append('[').Append(MemBase.ToString()); if (MemAddendReg != 0) { sb.Append(", ").Append(MemAddendReg.ToString()); } if (MemOffset != 0L) { sb.Append(' ').Append((MemOffset < 0) ? '-' : '+').Append(" 0x") .Append(Math.Abs(MemOffset).ToString("X")); } if (MemExtendType != Arm64ExtendType.NONE) { sb.Append(", ").Append(MemExtendType.ToString()); } else if (MemShiftType != Arm64ShiftType.NONE) { sb.Append(", ").Append(MemShiftType.ToString()); } if (MemExtendOrShiftAmount != 0) { sb.Append(" #").Append(MemExtendOrShiftAmount); } sb.Append(']'); if (MemIsPreIndexed) { sb.Append('!'); } } } public enum Arm64Mnemonic { INVALID, UNIMPLEMENTED, ADD, ADDHN, ADDHN2, ADDP, ADDS, ADR, ADRP, AND, ANDS, ASRV, B, BC, BFM, BIC, BICS, BL, BLR, BR, BRK, CBNZ, CBZ, CCMN, CCMP, CINC, CMGE, CMGT, CMP, CMTST, CRC32B, CRC32CB, CRC32CH, CRC32CW, CRC32CX, CRC32H, CRC32W, CRC32X, CSEL, CSET, CSINC, CSINV, CSNEG, DCPS1, DCPS2, DCPS3, DRPS, DUP, EOR, EON, EXTR, FABS, FADD, FCMEQ, FCMP, FCMPE, FCSEL, FCVT, FCVTMS, FCVTNS, FCVTPS, FCVTZS, FCVTMU, FCVTNU, FCVTPU, FCVTZU, FDIV, FMAX, FMAXNM, FMIN, FMINNM, FMLA, FMLS, FMLAL, FMLSL, FMOV, FMUL, FMULX, FNEG, FNMUL, FRECPS, FRINTA, FRINTI, FRINTM, FRINTN, FRINTP, FRINTX, FRINTZ, FRINT32X, FRINT32Z, FRINT64X, FRINT64Z, FRSQRTS, FSQRT, FSUB, GMI, HLT, HVC, INS, IRG, LDP, LDPSW, LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, LDUR, LDURB, LDURH, LDURSB, LDURSH, LDURSW, LSLV, LSRV, MADD, MLA, MOV, MOVI, MOVK, MOVN, MOVZ, MSUB, MUL, MVNI, NOP, ORN, ORR, PACGA, PMULL, PMULL2, PRFM, PRFUM, RADDHN, RADDHN2, RORV, RSUBHN, RSUBHN2, RET, SABAL, SABAL2, SABA, SABD, SABDL, SABDL2, SADDL, SADDL2, SADDW, SADDW2, SBFM, SCVTF, SDIV, SMADDL, SHADD, SHSUB, SMAX, SMAXP, SMC, SMIN, SMINP, SMLAL, SMLAL2, SMLSL, SMLSL2, SMOV, SMSUBL, SMULH, SMULL, SMULL2, SQADD, SQDMULH, SQDMLAL, SQDMLAL2, SQDMLSL, SQDMLSL2, SQDMULL, SQDMULL2, SQRSHL, SQSHL, SQSUB, SRHADD, SRSHL, SSHL, SSUBL, SSUBL2, SSUBW, SSUBW2, STGP, STP, STR, STRB, STRH, STUR, STURB, STURH, SUB, SUBHN, SUBHN2, SUBP, SUBPS, SUBS, SVC, SXTB, SXTH, SXTW, TBNZ, TBZ, TCANCEL, UABAL, UABAL2, UABDL, UABDL2, UADDL, UADDL2, UADDW, UADDW2, UBFM, UCVTF, UDIV, UMLAL, UMLAL2, UMOV, UMULL, UMULL2, UMADDL, UMLSL, UMLSL2, UMSUBL, UMULH, USUBL, USUBL2, USUBW, USUBW2 } public enum Arm64MnemonicCategory { Unspecified, Barrier, Branch, Comparison, ConditionalBranch, FlagMath, FloatingPointComparison, FloatingPointConversion, FloatingPointDataProcessing, FloatingPointMath, Exception, GeneralDataProcessing, Hint, LoadAddress, Math, MemoryTagging, MemoryToOrFromRegister, Move, PointerAuthentication, Pstate, Return, ScalableVectorExtension, SimdComparison, SimdConstantToRegister, SimdCryptographic, SimdRegisterToRegister, SimdScalarConversion, SimdScalarMath, SimdScalarRegisterToRegister, SimdStructureLoadOrStore, SimdVectorMath, System } public enum Arm64OperandKind { None, Register, VectorRegisterElement, Immediate, ImmediatePcRelative, FloatingPointImmediate, Memory } public enum Arm64ShiftType { LSL, LSR, ASR, ROR, NONE } public class Arm64UndefinedInstructionException : Exception { public Arm64UndefinedInstructionException(string message) : base(message) { } } public readonly struct Arm64VectorElement { public readonly Arm64VectorElementWidth Width; public readonly int Index; public Arm64VectorElement(Arm64VectorElementWidth width, int index) { Width = width; Index = index; } public override string ToString() { return $"{Width}[{Index}]"; } } public enum Arm64VectorElementWidth { B, H, S, D } public static class Disassembler { public static Arm64DisassemblyResult Disassemble(ReadOnlySpan assembly, ulong virtualAddress, bool remapAliases = true, bool continueOnError = false, bool throwOnUnimplemented = true) { List list = new List(assembly.Length / 4); if (assembly.Length % 4 != 0) { throw new Exception("Arm64 instructions are 4 bytes, therefore the assembly to disassemble must be a multiple of 4 bytes"); } for (int i = 0; i < assembly.Length; i += 4) { uint num = (uint)(assembly[i] | (assembly[i + 1] << 8) | (assembly[i + 2] << 16) | (assembly[i + 3] << 24)); Arm64Instruction arm64Instruction; try { arm64Instruction = DisassembleSingleInstruction(num, i, remapAliases); } catch (Arm64UndefinedInstructionException ex) { if (!continueOnError) { throw new Exception($"Encountered undefined instruction 0x{num:X8} at offset {i}. Undefined reason: {ex.Message}"); } Arm64Instruction arm64Instruction2 = new Arm64Instruction(); arm64Instruction2.Mnemonic = Arm64Mnemonic.INVALID; arm64Instruction = arm64Instruction2; } catch (Exception innerException) { if (!continueOnError) { throw new Exception($"Unhandled and unexpected exception disassembling instruction 0x{num:X8} at offset {i} (0x{i:X}) (va 0x{(long)virtualAddress + (long)i:X8})", innerException); } Arm64Instruction arm64Instruction2 = new Arm64Instruction(); arm64Instruction2.Mnemonic = Arm64Mnemonic.INVALID; arm64Instruction = arm64Instruction2; } arm64Instruction.Address = virtualAddress + (ulong)i; if (throwOnUnimplemented) { CheckUnimplemented(virtualAddress, arm64Instruction, num, i); } list.Add(arm64Instruction); } return new Arm64DisassemblyResult(list, virtualAddress); } internal static Arm64Instruction DisassembleSingleInstruction(uint instruction, int offset = 0, bool remapAliases = true) { bool num = instruction >> 31 == 0; uint num2 = (instruction >> 25) & 0xFu; if (num && num2 == 0) { throw new Arm64UndefinedInstructionException("Encountered reserved group of instructions"); } Arm64Instruction arm64Instruction; switch (num2) { case 1u: case 3u: throw new Arm64UndefinedInstructionException("Unallocated instruction type (bits 25-28 are 0b0001 or 0b0011)"); case 0u: throw new Exception($"SME instruction encountered at offset {offset}: 0x{instruction:X} - they are not implemented because Arm V9 is not supported"); case 2u: arm64Instruction = Arm64Sve.Disassemble(instruction); break; case 8u: case 9u: arm64Instruction = Arm64DataProcessingImmediate.Disassemble(instruction); break; case 10u: case 11u: arm64Instruction = DisassembleBranchExceptionSystemInstruction(instruction); break; case 4u: case 6u: case 12u: case 14u: arm64Instruction = Arm64LoadsStores.Disassemble(instruction); break; case 5u: case 13u: arm64Instruction = Arm64DataProcessingRegister.Disassemble(instruction); break; default: arm64Instruction = Arm64Simd.Disassemble(instruction); break; } Arm64Instruction instruction2 = arm64Instruction; if (remapAliases) { Arm64Aliases.CheckForAlias(ref instruction2); } return instruction2; } public static IEnumerable DisassembleOnDemand(byte[] input, ulong virtualAddress, bool remapAliases = true, bool continueOnError = false, bool throwOnUnimplemented = true) { for (int i = 0; i < input.Length; i += 4) { Span span = input.AsSpan(i, 4); uint num = (uint)(span[0] | (span[1] << 8) | (span[2] << 16) | (span[3] << 24)); Arm64Instruction arm64Instruction; try { arm64Instruction = DisassembleSingleInstruction(num, i, remapAliases); arm64Instruction.Address = virtualAddress + (ulong)i; } catch (Arm64UndefinedInstructionException ex) { if (!continueOnError) { throw new Exception($"Encountered undefined instruction 0x{num:X8} at offset {i}. Undefined reason: {ex.Message}", ex); } Arm64Instruction arm64Instruction2 = new Arm64Instruction(); arm64Instruction2.Mnemonic = Arm64Mnemonic.INVALID; arm64Instruction = arm64Instruction2; } catch (Exception innerException) { if (!continueOnError) { throw new Exception($"Unhandled and unexpected exception disassembling instruction 0x{num:X8} at offset {i}", innerException); } Arm64Instruction arm64Instruction2 = new Arm64Instruction(); arm64Instruction2.Mnemonic = Arm64Mnemonic.INVALID; arm64Instruction = arm64Instruction2; } if (throwOnUnimplemented) { CheckUnimplemented(virtualAddress, arm64Instruction, num, i); } yield return arm64Instruction; } } private static Arm64Instruction DisassembleBranchExceptionSystemInstruction(uint instruction) { uint num = (instruction >> 29) & 7; uint num2 = (instruction >> 12) & 0x3FFFu; switch (num) { case 2u: return Arm64Branches.ConditionalBranchImmediate(instruction); case 0u: case 4u: return Arm64Branches.UnconditionalBranchImmediate(instruction); case 1u: case 5u: if (num2 >> 13 == 1) { return Arm64Branches.TestAndBranch(instruction); } return Arm64Branches.CompareAndBranch(instruction); case 6u: if (num2 >> 13 == 1) { return Arm64Branches.UnconditionalBranchRegister(instruction); } break; } return DisassembleSystemHintExceptionBarrierOrPstate(instruction); } private static Arm64Instruction DisassembleSystemHintExceptionBarrierOrPstate(uint instruction) { uint num = (instruction >> 12) & 0x3FFFu; uint num2 = instruction & 0x1Fu; if (num >> 12 == 0) { return Arm64ExceptionGeneration.Disassemble(instruction); } uint num3 = (num >> 7) & 0x7Fu; if (num3 == 32 && (num & 0xF) == 4) { return Arm64Pstate.Disassemble(instruction); } switch (num3) { case 36u: return Arm64System.WithResult(instruction); case 33u: case 37u: return Arm64System.General(instruction); default: num3 >>= 1; if (num3 == 17 || num3 == 19) { return Arm64System.RegisterMove(instruction); } switch (num) { case 4145u: return Arm64System.WithRegisterArgument(instruction); case 4146u: if (num2 != 31) { throw new Arm64UndefinedInstructionException($"Hint instructions require op2 to be all 1s. Got {num2:X}"); } return Arm64Hints.Disassemble(instruction); case 4147u: return Arm64Barriers.Disassemble(instruction); default: throw new Arm64UndefinedInstructionException($"Undefined op1 in system instruction processor: {num:X}"); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void CheckUnimplemented(ulong virtualAddress, Arm64Instruction instruction, uint rawInstruction, int i) { if (instruction.Mnemonic == Arm64Mnemonic.UNIMPLEMENTED) { throw new NotImplementedException($"Encountered an unimplemented instruction belonging to category {instruction.MnemonicCategory}: 0x{rawInstruction:X8} at offset {i} (0x{i:X}) (va 0x{(long)virtualAddress + (long)i:X8})"); } } } } namespace Disarm.InternalDisassembly { internal static class Arm64Aliases { public static void CheckForAlias(ref Arm64Instruction instruction) { if (instruction.Mnemonic == Arm64Mnemonic.ORR && instruction.Op2Imm == 0L) { Arm64Register op1Reg = instruction.Op1Reg; if (op1Reg == Arm64Register.X31 || op1Reg == Arm64Register.W31) { instruction.Mnemonic = Arm64Mnemonic.MOV; instruction.Op3Imm = 0L; instruction.Op3Kind = Arm64OperandKind.None; instruction.Op1Reg = instruction.Op2Reg; instruction.Op2Reg = Arm64Register.INVALID; instruction.Op2Kind = Arm64OperandKind.None; instruction.MnemonicCategory = Arm64MnemonicCategory.Move; return; } } if (instruction.Mnemonic == Arm64Mnemonic.ORR && instruction.Op1Kind == Arm64OperandKind.Register && instruction.Op2Kind == Arm64OperandKind.Register && instruction.Op1Reg == instruction.Op2Reg) { instruction.Mnemonic = Arm64Mnemonic.MOV; instruction.Op2Kind = Arm64OperandKind.None; instruction.Op2Reg = Arm64Register.INVALID; instruction.MnemonicCategory = Arm64MnemonicCategory.Move; return; } if (instruction.Mnemonic == Arm64Mnemonic.SUBS && instruction.Op0Kind == Arm64OperandKind.Register) { Arm64Register op1Reg = instruction.Op0Reg; if ((op1Reg == Arm64Register.W31 || op1Reg == Arm64Register.X31) && instruction.Op1Kind == Arm64OperandKind.Register) { Arm64OperandKind op2Kind = instruction.Op2Kind; if (op2Kind == Arm64OperandKind.Immediate || op2Kind == Arm64OperandKind.Register) { instruction.Mnemonic = Arm64Mnemonic.CMP; instruction.Op0Reg = instruction.Op1Reg; instruction.Op1Kind = instruction.Op2Kind; instruction.Op2Kind = Arm64OperandKind.None; instruction.Op1Imm = instruction.Op2Imm; instruction.Op1Reg = instruction.Op2Reg; instruction.Op2Imm = 0L; instruction.MnemonicCategory = Arm64MnemonicCategory.Comparison; return; } } } if (instruction.Mnemonic == Arm64Mnemonic.MADD) { Arm64Register op1Reg = instruction.Op3Reg; if (op1Reg == Arm64Register.X31 || op1Reg == Arm64Register.W31) { instruction.Mnemonic = Arm64Mnemonic.MUL; instruction.Op3Kind = Arm64OperandKind.None; instruction.Op3Reg = Arm64Register.INVALID; return; } } if (instruction.Mnemonic == Arm64Mnemonic.CSINC) { Arm64ConditionCode finalOpConditionCode = instruction.FinalOpConditionCode; if (finalOpConditionCode != Arm64ConditionCode.AL && finalOpConditionCode != Arm64ConditionCode.NV && instruction.Op2Kind == Arm64OperandKind.Register && instruction.Op1Kind == Arm64OperandKind.Register) { if (instruction.Op2Reg.IsSp() && instruction.Op1Reg.IsSp()) { instruction.FinalOpConditionCode = instruction.FinalOpConditionCode.Invert(); instruction.Op1Kind = Arm64OperandKind.None; instruction.Op1Reg = Arm64Register.INVALID; instruction.Op2Kind = Arm64OperandKind.None; instruction.Op2Reg = Arm64Register.INVALID; instruction.Mnemonic = Arm64Mnemonic.CSET; return; } if (!instruction.Op2Reg.IsSp() && !instruction.Op1Reg.IsSp() && instruction.Op1Reg == instruction.Op2Reg) { instruction.FinalOpConditionCode = instruction.FinalOpConditionCode.Invert(); instruction.Op2Kind = Arm64OperandKind.None; instruction.Op2Reg = Arm64Register.INVALID; instruction.Mnemonic = Arm64Mnemonic.CINC; return; } } } if (instruction.Mnemonic == Arm64Mnemonic.SBFM && instruction.Op2Kind == Arm64OperandKind.Immediate && instruction.Op3Kind == Arm64OperandKind.Immediate && instruction.Op2Imm == 0L) { Arm64Mnemonic arm64Mnemonic; switch (instruction.Op3Imm) { default: return; case 7L: arm64Mnemonic = Arm64Mnemonic.SXTB; break; case 15L: arm64Mnemonic = Arm64Mnemonic.SXTH; break; case 31L: arm64Mnemonic = Arm64Mnemonic.SXTW; break; case 8L: case 9L: case 10L: case 11L: case 12L: case 13L: case 14L: case 16L: case 17L: case 18L: case 19L: case 20L: case 21L: case 22L: case 23L: case 24L: case 25L: case 26L: case 27L: case 28L: case 29L: case 30L: throw new Exception("Impossible imm3"); } Arm64Mnemonic mnemonic = arm64Mnemonic; instruction.Mnemonic = mnemonic; instruction.Op2Kind = Arm64OperandKind.None; instruction.Op2Reg = Arm64Register.INVALID; instruction.Op3Kind = Arm64OperandKind.None; instruction.Op3Reg = Arm64Register.INVALID; Arm64Register op1Reg = instruction.Op0Reg; if (op1Reg >= Arm64Register.X0 && op1Reg <= Arm64Register.X31) { instruction.Op1Reg = 1 + (instruction.Op1Reg - 33); } } else if (instruction.Mnemonic == Arm64Mnemonic.INS && instruction.Op0Kind == Arm64OperandKind.VectorRegisterElement && instruction.Op1Kind == Arm64OperandKind.VectorRegisterElement) { instruction.Mnemonic = Arm64Mnemonic.MOV; } else if (instruction.Mnemonic == Arm64Mnemonic.DUP && instruction.Op0Kind == Arm64OperandKind.Register && instruction.Op1Kind == Arm64OperandKind.VectorRegisterElement) { instruction.Mnemonic = Arm64Mnemonic.MOV; } } } internal static class Arm64Barriers { public static Arm64Instruction Disassemble(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Barrier; return result; } } internal static class Arm64Branches { public static Arm64Instruction ConditionalBranchImmediate(uint instruction) { if (instruction.TestBit(24)) { throw new Arm64UndefinedInstructionException("Conditional branch (immediate): o1 bit set"); } uint num = (instruction >> 5) & 0x7FFFF; bool flag = instruction.TestBit(4); Arm64ConditionCode mnemonicConditionCode = (Arm64ConditionCode)(instruction & 0xFu); long op0Imm = Arm64CommonUtils.SignExtend(num << 2, 21, 64); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = (flag ? Arm64Mnemonic.BC : Arm64Mnemonic.B); result.MnemonicConditionCode = mnemonicConditionCode; result.Op0Kind = Arm64OperandKind.ImmediatePcRelative; result.Op0Imm = op0Imm; result.MnemonicCategory = Arm64MnemonicCategory.ConditionalBranch; return result; } public static Arm64Instruction UnconditionalBranchImmediate(uint instruction) { bool flag = instruction.TestBit(31); long op0Imm = Arm64CommonUtils.SignExtend((instruction & 0x3FFFFFF) << 2, 28, 64); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = (flag ? Arm64Mnemonic.BL : Arm64Mnemonic.B); result.Op0Kind = Arm64OperandKind.ImmediatePcRelative; result.Op0Imm = op0Imm; result.MnemonicCategory = Arm64MnemonicCategory.Branch; return result; } public static Arm64Instruction TestAndBranch(uint instruction) { bool flag = instruction.TestBit(24); uint original = (instruction >> 5) & 0x3FFF; int num = (int)(instruction & 0x1F); bool num2 = instruction.TestBit(31); uint num3 = (instruction >> 19) & 0x1F; Arm64Mnemonic mnemonic = (flag ? Arm64Mnemonic.TBNZ : Arm64Mnemonic.TBZ); uint num4 = num3; if (num2) { num4 &= 0x20u; } int num5 = Arm64CommonUtils.CorrectSignBit(original, 14) * 4; Arm64Register op0Reg = (Arm64Register)(33 + num); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Immediate; result.Op2Kind = Arm64OperandKind.ImmediatePcRelative; result.Op0Reg = op0Reg; result.Op1Imm = num4; result.Op2Imm = num5; result.MnemonicCategory = Arm64MnemonicCategory.ConditionalBranch; return result; } public static Arm64Instruction CompareAndBranch(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(24); uint original = (instruction >> 5) & 0x7FFFFu; int num3 = (int)(instruction & 0x1F); Arm64Mnemonic mnemonic = (num2 ? Arm64Mnemonic.CBNZ : Arm64Mnemonic.CBZ); int num4 = ((!num) ? 1 : 33); int num5 = Arm64CommonUtils.CorrectSignBit(original, 19) * 4; Arm64Register op0Reg = (Arm64Register)(num4 + num3); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.ImmediatePcRelative; result.Op0Reg = op0Reg; result.Op1Imm = num5; result.MnemonicCategory = Arm64MnemonicCategory.ConditionalBranch; return result; } public static Arm64Instruction UnconditionalBranchRegister(uint instruction) { uint num = (instruction >> 21) & 0xFu; uint num2 = (instruction >> 16) & 0x1Fu; if (num2 != 31) { throw new Arm64UndefinedInstructionException($"Unconditional Branch: op2 != 0b11111: {num2:X}"); } switch (num) { case 3u: case 6u: case 7u: case 12u: case 13u: case 14u: case 15u: throw new Arm64UndefinedInstructionException($"Unconditional Branch: Unallocated opc: {num}"); case 0u: case 8u: return HandleBrFamily(instruction); case 1u: case 9u: return HandleBlFamily(instruction); case 2u: return HandleRetFamily(instruction); case 4u: return HandleEretFamily(instruction); case 5u: return HandleDrpsFamily(instruction); default: throw new Exception($"Impossible opc: {num}"); } } private static Arm64Instruction HandleRetFamily(uint instruction) { uint num = (instruction >> 10) & 0x1F; int num2 = (int)((instruction >> 5) & 0x1F); uint num3 = instruction & 0x1Fu; Arm64Instruction result; if (num == 0 && num3 == 0) { if (num2 == 30) { result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.RET; return result; } result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.RET; result.Op0Kind = Arm64OperandKind.Register; result.Op0Reg = (Arm64Register)(33 + num2); result.MnemonicCategory = Arm64MnemonicCategory.Return; return result; } result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Return; return result; } private static Arm64Instruction HandleBrFamily(uint instruction) { uint num = (instruction >> 21) & 0xF; uint num2 = (instruction >> 10) & 0x1Fu; int num3 = (int)((instruction >> 5) & 0x1F); uint num4 = instruction & 0x1Fu; if (num != 0) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Branch; return result; } if (num2 == 0 && num4 == 0) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.BR; result.Op0Kind = Arm64OperandKind.Register; result.Op0Reg = (Arm64Register)(33 + num3); result.MnemonicCategory = Arm64MnemonicCategory.Branch; return result; } if (num2 == 2 && num4 == 31) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Branch; return result; } if (num2 == 3 && num4 == 31) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Branch; return result; } throw new Arm64UndefinedInstructionException($"BR Family: op3 {num2}, op4 {num4}"); } private static Arm64Instruction HandleBlFamily(uint instruction) { uint num = (instruction >> 10) & 0x1Fu; int num2 = (int)((instruction >> 5) & 0x1F); uint num3 = instruction & 0x1Fu; switch (num) { case 0u: { if (num3 != 0) { throw new Arm64UndefinedInstructionException("BLR with op4 != 0"); } Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.BLR; result.Op0Kind = Arm64OperandKind.Register; result.Op0Reg = (Arm64Register)(33 + num2); return result; } case 2u: { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Branch; return result; } case 3u: { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Branch; return result; } default: throw new Arm64UndefinedInstructionException($"BL Family: op3 {num}, op4 {num3}"); } } private static Arm64Instruction HandleEretFamily(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Return; return result; } private static Arm64Instruction HandleDrpsFamily(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.DRPS; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; return result; } } internal static class Arm64CommonUtils { private static BitArray SignExtend(BitArray value, int size) { BitArray bitArray = new BitArray(size); bool value2 = value[0]; int num = size - value.Length; for (int i = num; i < size - 1; i++) { bitArray[i] = value[i - num]; } for (int j = 0; j < num; j++) { bitArray[j] = value2; } return bitArray; } private static BitArray Replicate(BitArray original, int desiredLength) { if (desiredLength % original.Length != 0) { throw new Exception("Desired length is not a multiple of the original length"); } BitArray bitArray = new BitArray(desiredLength); for (int i = 0; i < desiredLength; i += original.Length) { for (int j = 0; j < original.Length; j++) { bitArray[i + j] = original[j]; } } return bitArray; } private static long BitsToLong(BitArray bits) { long num = 0L; for (int i = 0; i < bits.Count; i++) { if (bits[i]) { num |= 1L << bits.Count - 1 - i; } } return num; } private static ulong RotateRight(ulong original, int numBits, int shift) { int num = shift % numBits; ulong num2 = original >> num; ulong num3 = original << numBits - num; return num2 | num3; } private static BitArray LongToBits(long value, int numBits) { BitArray bitArray = new BitArray(numBits); long num = 1L << numBits - 1; for (int i = 0; i < numBits; i++) { bool value2 = (value & num) != 0; num >>= 1; bitArray[i] = value2; } return bitArray; } private static int HighestSetBit(BitArray bits) { for (int i = 0; i < bits.Length; i++) { if (bits.Get(i)) { return bits.Length - i - 1; } } return 0; } public static long SignExtend(long original, int originalSizeBits, int newSizeBits) { return BitsToLong(SignExtend(LongToBits(original, originalSizeBits), newSizeBits)); } public static int CorrectSignBit(uint original, int originalSizeBits) { int num = 1 << originalSizeBits - 1; if ((original & num) == 0) { return (int)original; } int num2 = (int)original & (num - 1); return -1 - (~num2 & (num - 1)); } public static ulong ApplyShift(ulong original, Arm64ShiftType type, int numBits, int amount) { return type switch { Arm64ShiftType.LSL => original << amount, Arm64ShiftType.LSR => original >> amount, Arm64ShiftType.ASR => (uint)((int)original >> amount), Arm64ShiftType.ROR => RotateRight(original, numBits, amount), _ => throw new ArgumentException("Unknown shift type"), }; } public static (long, long) DecodeBitMasks(bool nFlag, int desiredSize, byte imms, byte immr, bool immediate) { int num = HighestSetBit(LongToBits((short)((nFlag ? 64 : 0) | (~imms & 0x3F)), 12)); if (num < 1) { throw new Arm64UndefinedInstructionException("DecodeBitMasks: highestBit < 1"); } if (1 << num > desiredSize) { throw new Arm64UndefinedInstructionException("DecodeBitMasks: (1 << highestBit) > desiredSize"); } int num2 = (1 << num) - 1; if (immediate && (imms & num2) == num2) { throw new Arm64UndefinedInstructionException("DecodeBitMasks: imms & levels == levels not allowed in immediate mode"); } int num3 = imms & num2; int num4 = immr & num2; int num5 = num3 - num4; int numBits = 1 << num; int num6 = num5 & ((1 << num - 1) - 1); int num7 = (1 << num3 + 1) - 1; int num8 = (1 << num6 + 1) - 1; BitArray bits = Replicate(LongToBits((long)RotateRight((ulong)num7, numBits, num4), numBits), desiredSize); return new ValueTuple(item2: BitsToLong(Replicate(LongToBits(num8, numBits), desiredSize)), item1: BitsToLong(bits)); } public static ulong AdvancedSimdExpandImmediate(bool op, byte cmode, byte imm) { switch (cmode >> 1) { case 0: return imm & ((ulong)imm << 32); case 1: { uint num9 = (uint)(imm << 8); return num9 & ((ulong)num9 << 32); } case 2: { uint num14 = (uint)(imm << 16); return num14 & ((ulong)num14 << 32); } case 3: { uint num10 = (uint)(imm << 24); return num10 & ((ulong)num10 << 32); } case 4: { ushort num11 = imm; return num11 & ((ulong)num11 << 16) & ((ulong)num11 << 32) & ((ulong)num11 << 48); } case 5: { ushort num8 = (ushort)(imm << 8); return num8 & ((ulong)num8 << 16) & ((ulong)num8 << 32) & ((ulong)num8 << 48); } case 6: { if ((cmode & 1) == 0) { uint num12 = (uint)(imm << 8) | 0xFFu; return num12 & ((ulong)num12 << 32); } uint num13 = (uint)(imm << 16) | 0xFFFFu; return num13 & ((ulong)num13 << 32); } case 7: { bool flag = (cmode & 1) == 1; if (!flag && !op) { return imm & ((ulong)imm << 8) & ((ulong)imm << 16) & ((ulong)imm << 24) & ((ulong)imm << 32) & ((ulong)imm << 40) & ((ulong)imm << 48) & ((ulong)imm << 56); } if (!flag && op) { ulong num = 0uL; for (int i = 0; i < 8; i++) { bool flag2 = ((imm >> i) & 1) == 1; num |= (ulong)((long)(flag2 ? 255 : 0) << i * 8); } return num; } uint num2 = (uint)(imm & 0x40) >> 6; int num3 = (imm & 0x80) >>> 7; uint num4 = ((num2 == 0) ? 1u : 0u); uint num5 = imm & 0x3Fu; uint num6 = (num2 << 4) | (num2 << 3) | (num2 << 2) | (num2 << 1) | num2; uint num7 = (uint)(num3 << 12) | (num4 << 11) | (num6 << 6) | num5; if (flag && !op) { num7 <<= 19; return num7 & ((ulong)num7 << 32); } num7 = (num7 >> 6 << 3) | (num2 << 2) | (num2 << 1) | (num2 << 6) | num5; return (ulong)num7 << 48; } default: throw new ArgumentException("cmode"); } } public static double DecodeFPImm(uint pType, uint imm8) { int num = pType switch { 0u => 32, 1u => 64, 2u => 16, _ => throw new Exception("Invalid pType"), }; int num2 = pType switch { 0u => 8, 1u => 11, 2u => 5, _ => throw new Exception("Invalid pType"), }; int num3 = num - num2 - 1; bool flag = imm8.TestBit(7); ulong num4 = (ulong)(imm8.TestBit(6) ? 0 : 1); num4 <<= num2 - 1; uint num5 = (imm8 >> 6) & 1u; for (int i = 0; i < num2 - 3; i++) { num4 |= num5 << num2 - 2 - i; } num4 |= (imm8 & 0x30) >> 4; uint num6 = imm8 & 0xFu; num6 <<= num3 - 4; byte[] bytes = BitConverter.GetBytes((ulong)((long)(flag ? 1 : 0) << num - 1) | (num4 << num3) | num6); return num switch { 16 => ToFloat16(bytes), 32 => BitConverter.ToSingle(bytes, 0), 64 => BitConverter.ToDouble(bytes, 0), _ => throw new Exception("Impossible"), }; } private static double ToFloat16(byte[] bytes) { return (double)BitConverter.ToHalf(bytes); } } internal static class Arm64DataProcessingImmediate { public static Arm64Instruction Disassemble(uint instruction) { switch ((instruction >> 23) & 7) { case 0u: case 1u: return PcRelativeAddressing(instruction); case 2u: return AddSubtractImmediate(instruction); case 3u: return AddSubtractImmediateWithTags(instruction); case 4u: return LogicalImmediate(instruction); case 5u: return MoveWideImmediate(instruction); case 6u: return Bitfield(instruction); case 7u: return Extract(instruction); default: throw new ArgumentOutOfRangeException("op0", "Impossible op0 value"); } } public static Arm64Instruction PcRelativeAddressing(uint instruction) { bool flag = instruction.TestBit(31); uint num = (instruction >> 29) & 3u; uint num2 = (instruction >> 5) & 0x7FFFF; int num3 = (int)(instruction & 0x1F); uint num4 = (num2 << 2) | num; if (flag) { num4 <<= 12; } int num5 = Arm64CommonUtils.CorrectSignBit(num4, flag ? 33 : 21); Arm64Mnemonic mnemonic = (flag ? Arm64Mnemonic.ADRP : Arm64Mnemonic.ADR); Arm64Register op0Reg = (Arm64Register)(33 + num3); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Imm = num5; result.MnemonicCategory = Arm64MnemonicCategory.LoadAddress; return result; } public static Arm64Instruction AddSubtractImmediate(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(30); bool flag = instruction.TestBit(29); bool num3 = instruction.TestBit(22); ulong num4 = (ulong)(instruction >> 10) & 0xFFFuL; int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); if (num3) { num4 <<= 12; } Arm64Mnemonic arm64Mnemonic = (num2 ? ((!flag) ? Arm64Mnemonic.SUB : Arm64Mnemonic.SUBS) : ((!flag) ? Arm64Mnemonic.ADD : Arm64Mnemonic.ADDS)); Arm64Mnemonic mnemonic = arm64Mnemonic; int num7 = ((!num) ? 1 : 33); Arm64Register op1Reg = (Arm64Register)(num7 + num5); Arm64Register op0Reg = (Arm64Register)(num7 + num6); ulong num8 = ((!num) ? ((uint)num4) : num4); ulong op2Imm = num8; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Imm = (long)op2Imm; result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } public static Arm64Instruction AddSubtractImmediateWithTags(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } public static Arm64Instruction LogicalImmediate(uint instruction) { bool flag = instruction.TestBit(31); uint num = (instruction >> 29) & 3u; bool flag2 = instruction.TestBit(22); byte immr = (byte)((instruction >> 16) & 0x3Fu); byte imms = (byte)((instruction >> 10) & 0x3Fu); int num2 = (int)((instruction >> 5) & 0x1F); int num3 = (int)(instruction & 0x1F); if (!flag && flag2) { throw new Arm64UndefinedInstructionException("32-bit instruction with N flag set"); } Arm64Mnemonic mnemonic = num switch { 0u => Arm64Mnemonic.AND, 1u => Arm64Mnemonic.ORR, 2u => Arm64Mnemonic.EOR, 3u => Arm64Mnemonic.ANDS, _ => throw new Exception("Impossible opc value"), }; int num4 = ((!flag) ? 1 : 33); Arm64Register op1Reg = (Arm64Register)(num4 + num2); Arm64Register op0Reg = (Arm64Register)(num4 + num3); long item = Arm64CommonUtils.DecodeBitMasks(flag2, flag ? 64 : 32, imms, immr, immediate: true).Item1; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Imm = item; result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } public static Arm64Instruction MoveWideImmediate(uint instruction) { bool flag = instruction.TestBit(31); uint num = (instruction >> 29) & 3u; uint num2 = (instruction >> 21) & 3u; uint num3 = (instruction >> 5) & 0xFFFFu; int num4 = (int)(instruction & 0x1F); if (num == 1) { throw new Arm64UndefinedInstructionException("Move wide immediate with opc == 0b01"); } if (!flag && num2.TestBit(1)) { throw new Arm64UndefinedInstructionException("Move wide immediate with hw bit 1 and !is64Bit"); } Arm64Mnemonic mnemonic = num switch { 0u => Arm64Mnemonic.MOVN, 2u => Arm64Mnemonic.MOVZ, 3u => Arm64Mnemonic.MOVK, _ => throw new Exception("Impossible opc value"), }; Arm64Register op0Reg = (Arm64Register)(((!flag) ? 1 : 33) + num4); int num5 = (int)(num2 * 16); num3 <<= num5; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Imm = num3; result.MnemonicCategory = Arm64MnemonicCategory.Move; return result; } public static Arm64Instruction Bitfield(uint instruction) { bool flag = instruction.TestBit(31); uint num = (instruction >> 29) & 3u; bool flag2 = instruction.TestBit(22); byte b = (byte)((instruction >> 16) & 0x3Fu); byte b2 = (byte)((instruction >> 10) & 0x3Fu); int num2 = (int)((instruction >> 5) & 0x1F); int num3 = (int)(instruction & 0x1F); if (num == 3) { throw new Arm64UndefinedInstructionException("Bitfield with opc == 0b11"); } if (flag != flag2) { throw new Arm64UndefinedInstructionException("Bitfield with is64Bit != n"); } Arm64Mnemonic mnemonic = num switch { 0u => Arm64Mnemonic.SBFM, 1u => Arm64Mnemonic.BFM, 2u => Arm64Mnemonic.UBFM, _ => throw new Exception("Impossible opc"), }; int num4 = ((!flag) ? 1 : 33); Arm64Register op1Reg = (Arm64Register)(num4 + num2); Arm64Register op0Reg = (Arm64Register)(num4 + num3); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Immediate; result.Op3Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Imm = b; result.Op3Imm = b2; result.MnemonicCategory = Arm64MnemonicCategory.Move; return result; } public static Arm64Instruction Extract(uint instruction) { bool num = instruction.TestBit(31); uint num2 = (instruction >> 29) & 3; bool flag = instruction.TestBit(22); bool flag2 = instruction.TestBit(21); int num3 = (int)((instruction >> 16) & 0x1F); uint num4 = (instruction >> 10) & 0x3Fu; int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); if (num2 != 0) { throw new Arm64UndefinedInstructionException("Extract with op21 != 0"); } if (num != flag) { throw new Arm64UndefinedInstructionException("Extract with sf != N"); } if (flag2) { throw new Arm64UndefinedInstructionException("Extract with o0 == 1"); } if (!num && num4.TestBit(5)) { throw new Arm64UndefinedInstructionException("Extract: imms top bit can only be set if sf is also set"); } int num7 = ((!num) ? 1 : 33); Arm64Register op1Reg = (Arm64Register)(num7 + num5); Arm64Register op0Reg = (Arm64Register)(num7 + num6); Arm64Register op2Reg = (Arm64Register)(num7 + num3); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.EXTR; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op3Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.Op3Imm = num4; return result; } } internal static class Arm64DataProcessingRegister { public static Arm64Instruction Disassemble(uint instruction) { bool flag = instruction.TestBit(30); bool flag2 = instruction.TestBit(28); uint num = (instruction >> 21) & 0xFu; uint num2 = (instruction >> 10) & 0x3Fu; if (num == 6 && flag2) { if (!flag) { return DataProcessing2Source(instruction); } return DataProcessing1Source(instruction); } if (!flag2) { if (num >> 3 == 0) { return LogicalShiftedRegister(instruction); } if ((num & 9) == 8) { return AddSubtractShiftedRegister(instruction); } return AddSubtractExtendedRegister(instruction); } switch (num) { case 0u: switch (num2) { case 0u: return AddSubtractWithCarry(instruction); case 1u: case 33u: return RotateRightIntoFlags(instruction); } if ((num2 & 0xF) == 2) { return EvaluateIntoFlags(instruction); } break; case 2u: if (num2.TestBit(1)) { return ConditionalCompare(instruction, secondOpIsReg: false); } return ConditionalCompare(instruction, secondOpIsReg: true); case 4u: return ConditionalSelect(instruction); } return DataProcessing3Source(instruction); } private static Arm64Instruction DataProcessing1Source(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.GeneralDataProcessing; return result; } private static Arm64Instruction DataProcessing2Source(uint instruction) { bool flag = instruction.TestBit(31); bool flag2 = instruction.TestBit(29); int num = (int)((instruction >> 16) & 0x1F); int num2 = (int)((instruction >> 10) & 0x3F); int num3 = (int)((instruction >> 5) & 0x1F); int num4 = (int)(instruction & 0x1F); if (num2 == 1 || num2 >> 5 == 1 || num2 >> 3 == 3) { throw new Arm64UndefinedInstructionException($"Invalid opcode for DataProcessing2Source: {num2:X}"); } if (!flag && num2 == 0) { throw new Arm64UndefinedInstructionException($"Invalid opcode for DataProcessing2Source: {num2:X} when sf = 0"); } Arm64Instruction result; if (!flag && !flag2) { Arm64Mnemonic mnemonic = num2 switch { 2 => Arm64Mnemonic.UDIV, 3 => Arm64Mnemonic.SDIV, 8 => Arm64Mnemonic.LSLV, 9 => Arm64Mnemonic.LSRV, 10 => Arm64Mnemonic.ASRV, 11 => Arm64Mnemonic.RORV, 16 => Arm64Mnemonic.CRC32B, 17 => Arm64Mnemonic.CRC32H, 18 => Arm64Mnemonic.CRC32W, 20 => Arm64Mnemonic.CRC32CB, 21 => Arm64Mnemonic.CRC32CH, 22 => Arm64Mnemonic.CRC32CW, _ => throw new Arm64UndefinedInstructionException($"DataProcessing2Source: opcode {num2:X} with sf == S == 0"), }; result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op0Reg = (Arm64Register)(1 + num4); result.Op1Reg = (Arm64Register)(1 + num3); result.Op2Reg = (Arm64Register)(1 + num); result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } if (flag && flag2) { if (num2 != 0) { throw new Arm64UndefinedInstructionException("DataProcessing2Source: opcode != 0 when sf == S == 1"); } result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.SUBPS; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op0Reg = (Arm64Register)(33 + num4); result.Op1Reg = (Arm64Register)(33 + num3); result.Op2Reg = (Arm64Register)(33 + num); result.MnemonicCategory = Arm64MnemonicCategory.MemoryTagging; return result; } Arm64Mnemonic arm64Mnemonic = num2 switch { 0 => Arm64Mnemonic.SUBP, 2 => Arm64Mnemonic.UDIV, 3 => Arm64Mnemonic.SDIV, 4 => Arm64Mnemonic.IRG, 5 => Arm64Mnemonic.GMI, 8 => Arm64Mnemonic.LSLV, 9 => Arm64Mnemonic.LSRV, 10 => Arm64Mnemonic.ASRV, 11 => Arm64Mnemonic.RORV, 12 => Arm64Mnemonic.PACGA, 19 => Arm64Mnemonic.CRC32X, 23 => Arm64Mnemonic.CRC32CX, _ => throw new Arm64UndefinedInstructionException($"DataProcessing2Source: opcode {num2:X} with sf == 1 and S == 0"), }; Arm64MnemonicCategory arm64MnemonicCategory; switch (arm64Mnemonic) { case Arm64Mnemonic.GMI: case Arm64Mnemonic.IRG: case Arm64Mnemonic.SUBP: arm64MnemonicCategory = Arm64MnemonicCategory.MemoryTagging; break; case Arm64Mnemonic.PACGA: arm64MnemonicCategory = Arm64MnemonicCategory.PointerAuthentication; break; default: arm64MnemonicCategory = Arm64MnemonicCategory.Math; break; } Arm64MnemonicCategory mnemonicCategory = arm64MnemonicCategory; result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op0Reg = (Arm64Register)(33 + num4); result.Op1Reg = (Arm64Register)(33 + num3); result.Op2Reg = (Arm64Register)(33 + num); result.MnemonicCategory = mnemonicCategory; return result; } private static Arm64Instruction LogicalShiftedRegister(uint instruction) { bool flag = instruction.TestBit(31); uint num = (instruction >> 29) & 3u; bool flag2 = instruction.TestBit(21); int num2 = (int)((instruction >> 16) & 0x1F); uint num3 = (instruction >> 10) & 0x3Fu; int num4 = (int)((instruction >> 5) & 0x1F); int num5 = (int)(instruction & 0x1F); if (!flag && num3.TestBit(5)) { throw new Arm64UndefinedInstructionException("LogicalShiftedRegister: imm6 bit 5 set and sf = 0"); } Arm64Mnemonic mnemonic = num switch { 0u => (!flag2) ? Arm64Mnemonic.AND : Arm64Mnemonic.BIC, 1u => (!flag2) ? Arm64Mnemonic.ORR : Arm64Mnemonic.ORN, 2u => (!flag2) ? Arm64Mnemonic.EOR : Arm64Mnemonic.EON, 3u => (!flag2) ? Arm64Mnemonic.ANDS : Arm64Mnemonic.BICS, _ => throw new Exception("LogicalShiftedRegister: impossible opc"), }; int num6 = ((!flag) ? 1 : 33); Arm64Register op0Reg = (Arm64Register)(num6 + num5); Arm64Register op1Reg = (Arm64Register)(num6 + num4); Arm64Register op2Reg = (Arm64Register)(num6 + num2); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op3Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.Op3Imm = num3; result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } private static Arm64Instruction AddSubtractShiftedRegister(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(30); bool flag = instruction.TestBit(29); Arm64ShiftType arm64ShiftType = (Arm64ShiftType)((int)(instruction >> 22) & 3); int num3 = (int)((instruction >> 16) & 0x1F); uint num4 = (instruction >> 10) & 0x3Fu; int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); Arm64Mnemonic mnemonic = ((!num2) ? (flag ? Arm64Mnemonic.ADDS : Arm64Mnemonic.ADD) : (flag ? Arm64Mnemonic.SUBS : Arm64Mnemonic.SUB)); int num7 = ((!num) ? 1 : 33); Arm64Register op0Reg = (Arm64Register)(num7 + num6); Arm64Register op1Reg = (Arm64Register)(num7 + num5); Arm64Register op2Reg = (Arm64Register)(num7 + num3); if (arm64ShiftType == Arm64ShiftType.ROR) { throw new Arm64UndefinedInstructionException("Add/Subtract Shifted Register: Shift type ROR is reserved"); } Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op3Kind = ((num4 != 0) ? Arm64OperandKind.Immediate : Arm64OperandKind.None); result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.Op3Imm = num4; result.FinalOpShiftType = ((num4 == 0) ? Arm64ShiftType.NONE : arm64ShiftType); result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } private static Arm64Instruction AddSubtractExtendedRegister(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(30); bool flag = instruction.TestBit(29); uint num3 = (instruction >> 22) & 3; int num4 = (int)((instruction >> 16) & 0x1F); Arm64ExtendType arm64ExtendType = (Arm64ExtendType)((instruction >> 13) & 7u); uint num5 = (instruction >> 10) & 7u; int num6 = (int)((instruction >> 5) & 0x1F); int num7 = (int)(instruction & 0x1F); if (num3 != 0) { throw new Arm64UndefinedInstructionException("AddSubtractExtendedRegister: opt != 0"); } if (num5 > 4) { throw new Arm64UndefinedInstructionException("AddSubtractExtendedRegister: Shift > 4"); } Arm64Mnemonic mnemonic = ((!num2) ? (flag ? Arm64Mnemonic.ADDS : Arm64Mnemonic.ADD) : (flag ? Arm64Mnemonic.SUBS : Arm64Mnemonic.SUB)); Arm64Register arm64Register = ((!num) ? Arm64Register.W0 : Arm64Register.X0); int num8 = ((!num) ? 1 : ((arm64ExtendType != Arm64ExtendType.UXTX && arm64ExtendType != Arm64ExtendType.SXTX) ? 1 : 33)); Arm64Register op0Reg = arm64Register + num7; Arm64Register op1Reg = arm64Register + num6; Arm64Register op2Reg = (Arm64Register)(num8 + num4); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op3Kind = ((num5 != 0) ? Arm64OperandKind.Immediate : Arm64OperandKind.None); result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.Op3Imm = num5; result.FinalOpExtendType = arm64ExtendType; result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } private static Arm64Instruction AddSubtractWithCarry(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } private static Arm64Instruction RotateRightIntoFlags(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.FlagMath; return result; } private static Arm64Instruction EvaluateIntoFlags(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.FlagMath; return result; } private static Arm64Instruction ConditionalCompare(uint instruction, bool secondOpIsReg) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(30); bool flag = instruction.TestBit(29); uint num3 = (instruction >> 16) & 0x1Fu; Arm64ConditionCode finalOpConditionCode = (Arm64ConditionCode)((instruction >> 12) & 0xFu); bool num4 = instruction.TestBit(10); int num5 = (int)((instruction >> 5) & 0x1F); bool flag2 = instruction.TestBit(4); uint num6 = instruction & 0xFu; if (!flag) { throw new Arm64UndefinedInstructionException("ConditionalCompareImmediate: sFlag == 0"); } if (num4 || flag2) { throw new Arm64UndefinedInstructionException("ConditionalCompareImmediate: o2 or o3 is set"); } Arm64Mnemonic mnemonic = (num2 ? Arm64Mnemonic.CCMP : Arm64Mnemonic.CCMN); Arm64Register arm64Register = ((!num) ? Arm64Register.W0 : Arm64Register.X0); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = (secondOpIsReg ? Arm64OperandKind.Register : Arm64OperandKind.Immediate); result.Op2Kind = Arm64OperandKind.Immediate; result.Op0Reg = arm64Register + num5; result.Op1Imm = ((!secondOpIsReg) ? num3 : 0); result.Op1Reg = (secondOpIsReg ? ((Arm64Register)((int)arm64Register + (int)num3)) : Arm64Register.INVALID); result.Op2Imm = num6; result.FinalOpConditionCode = finalOpConditionCode; result.MnemonicCategory = Arm64MnemonicCategory.Comparison; return result; } private static Arm64Instruction ConditionalSelect(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(30); bool num3 = instruction.TestBit(29); int num4 = (int)((instruction >> 16) & 0x1F); Arm64ConditionCode finalOpConditionCode = (Arm64ConditionCode)((instruction >> 12) & 0xFu); uint num5 = (instruction >> 10) & 3u; int num6 = (int)((instruction >> 5) & 0x1F); int num7 = (int)(instruction & 0x1F); if (num3) { throw new Arm64UndefinedInstructionException("ConditionalSelect: S flag set"); } if (num5 > 1) { throw new Arm64UndefinedInstructionException("ConditionalSelect: op2 > 1"); } Arm64Mnemonic arm64Mnemonic = ((!num2) ? ((num5 != 0) ? Arm64Mnemonic.CSINC : Arm64Mnemonic.CSEL) : ((num5 != 0) ? Arm64Mnemonic.CSNEG : Arm64Mnemonic.CSINV)); Arm64Mnemonic mnemonic = arm64Mnemonic; int num8 = ((!num) ? 1 : 33); Arm64Register op0Reg = (Arm64Register)(num8 + num7); Arm64Register op1Reg = (Arm64Register)(num8 + num6); Arm64Register op2Reg = (Arm64Register)(num8 + num4); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op3Kind = Arm64OperandKind.None; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.FinalOpConditionCode = finalOpConditionCode; result.MnemonicCategory = Arm64MnemonicCategory.Comparison; return result; } private static Arm64Instruction DataProcessing3Source(uint instruction) { bool flag = instruction.TestBit(31); uint num = (instruction >> 29) & 3; uint num2 = (instruction >> 21) & 7u; int num3 = (int)((instruction >> 16) & 0x1F); bool flag2 = instruction.TestBit(15); int num4 = (int)((instruction >> 10) & 0x1F); int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); if (num != 0) { throw new Arm64UndefinedInstructionException("DataProcessing3Source: op54 != 0"); } Arm64Mnemonic arm64Mnemonic; switch (num2) { case 0u: arm64Mnemonic = ((!flag2) ? Arm64Mnemonic.MADD : Arm64Mnemonic.MSUB); break; case 1u: if (!flag) { throw new Arm64UndefinedInstructionException("DataProcessing3Source: op31 == 0b001 && sf == 0"); } arm64Mnemonic = ((!flag2) ? Arm64Mnemonic.SMADDL : Arm64Mnemonic.SMSUBL); break; case 2u: if (!flag2 && flag) { arm64Mnemonic = Arm64Mnemonic.SMULH; break; } goto default; case 5u: if (flag2 && flag) { arm64Mnemonic = Arm64Mnemonic.UMSUBL; break; } if (!flag2 && flag) { arm64Mnemonic = Arm64Mnemonic.UMADDL; break; } goto default; case 6u: if (flag2 && flag) { arm64Mnemonic = Arm64Mnemonic.UMULH; break; } goto default; default: throw new Arm64UndefinedInstructionException($"DataProcessing3Source: unallocated operand combination: op31 = {num2} o0 = {flag2} sf = {(flag ? 1 : 0)}"); } Arm64Mnemonic mnemonic = arm64Mnemonic; int num7 = ((!flag) ? 1 : 33); Arm64Register op2Reg = (Arm64Register)(num7 + num3); Arm64Register op1Reg = (Arm64Register)(num7 + num5); Arm64Register op0Reg = (Arm64Register)(num7 + num6); Arm64Register op3Reg = (Arm64Register)(num7 + num4); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op3Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.Op3Reg = op3Reg; result.MnemonicCategory = Arm64MnemonicCategory.Math; return result; } } internal static class Arm64ExceptionGeneration { public static Arm64Instruction Disassemble(uint instruction) { uint num = (instruction >> 21) & 3u; uint num2 = (instruction >> 5) & 0xFFFFu; uint num3 = (instruction >> 2) & 7; uint num4 = instruction & 3u; if (num3 != 0) { throw new Arm64UndefinedInstructionException("Exception generation: op2 != 0"); } Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (num4 == 1) { arm64Mnemonic = Arm64Mnemonic.SVC; break; } if (num4 == 2) { arm64Mnemonic = Arm64Mnemonic.HVC; break; } if (num4 == 3) { arm64Mnemonic = Arm64Mnemonic.SMC; break; } goto default; case 1u: if (num4 == 0) { arm64Mnemonic = Arm64Mnemonic.BRK; break; } goto default; case 2u: if (num4 == 0) { arm64Mnemonic = Arm64Mnemonic.HLT; break; } goto default; case 3u: if (num4 == 0) { arm64Mnemonic = Arm64Mnemonic.TCANCEL; break; } goto default; case 5u: if (num4 == 1) { arm64Mnemonic = Arm64Mnemonic.DCPS1; break; } if (num4 == 2) { arm64Mnemonic = Arm64Mnemonic.DCPS2; break; } if (num4 == 3) { arm64Mnemonic = Arm64Mnemonic.DCPS3; break; } goto default; default: throw new Arm64UndefinedInstructionException($"Exception generation: invalid opc/ll combination: {num}/{num4}"); } Arm64Mnemonic mnemonic = arm64Mnemonic; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.MnemonicCategory = Arm64MnemonicCategory.Exception; result.Op0Kind = Arm64OperandKind.Immediate; result.Op0Imm = num2; return result; } } internal static class Arm64FloatingPoint { internal static Arm64Instruction ConversionToAndFromFixedPoint(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.FloatingPointConversion; return result; } internal static Arm64Instruction ConversionToAndFromInteger(uint instruction) { bool flag = instruction.TestBit(31); bool num = instruction.TestBit(29); uint num2 = (instruction >> 22) & 3u; uint num3 = (instruction >> 19) & 3u; uint num4 = (instruction >> 16) & 7u; int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); if (num3 != 0 && (num4 == 2 || num4 == 3 || num4 == 4 || num4 == 5)) { throw new Arm64UndefinedInstructionException($"Floating-point conversion to/from integer: rmode != 0 not allowed with opcode 0x{num4:X}"); } if (num) { throw new Arm64UndefinedInstructionException("Floating-point conversion to/from integer: S is reserved"); } if (num2 == 2 && (num4 >> 2 == 0 || num4 >> 1 == 2)) { throw new Arm64UndefinedInstructionException($"Floating-point conversion to/from integer: ptype 0b10 not allowed with opcode 0x{num4:X}"); } Arm64Mnemonic arm64Mnemonic; switch (num4) { case 0u: case 4u: arm64Mnemonic = num3 switch { 0u => Arm64Mnemonic.FCVTNS, 1u => Arm64Mnemonic.FCVTPS, 2u => Arm64Mnemonic.FCVTMS, 3u => Arm64Mnemonic.FCVTZS, _ => throw new Exception("Impossible rmode"), }; break; case 1u: case 5u: arm64Mnemonic = num3 switch { 0u => Arm64Mnemonic.FCVTNU, 1u => Arm64Mnemonic.FCVTPU, 2u => Arm64Mnemonic.FCVTMU, 3u => Arm64Mnemonic.FCVTZU, _ => throw new Exception("Impossible rmode"), }; break; case 2u: arm64Mnemonic = Arm64Mnemonic.SCVTF; break; case 3u: arm64Mnemonic = Arm64Mnemonic.UCVTF; break; case 6u: case 7u: arm64Mnemonic = Arm64Mnemonic.FMOV; break; default: throw new Exception("Impossible opcode"); } Arm64Mnemonic mnemonic = arm64Mnemonic; bool flag2 = num4 == 0 || num4 == 4 || num4 == 1 || num4 == 5 || num4 == 6; Arm64Register arm64Register = num2 switch { 0u => Arm64Register.S0, 1u => Arm64Register.D0, 2u => Arm64Register.V0, 3u => Arm64Register.H0, _ => throw new Exception("Impossible ptype"), }; if (arm64Register == Arm64Register.V0 && (num3 != 1 || num4 != 6)) { throw new Exception("Floating-point conversion to/from integer: ptype 0b10 only allowed with rmode 0b01 and opcode 0b110 or 0b111"); } Arm64Register arm64Register2 = ((!flag) ? Arm64Register.W0 : Arm64Register.X0); Arm64Register op0Reg = (flag2 ? arm64Register2 : arm64Register) + num6; Arm64Register op1Reg = (flag2 ? arm64Register : arm64Register2) + num5; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.MnemonicCategory = Arm64MnemonicCategory.FloatingPointConversion; return result; } public static Arm64Instruction DataProcessingOneSource(uint instruction) { bool num = instruction.TestBit(31); bool flag = instruction.TestBit(29); uint num2 = (instruction >> 22) & 3u; uint num3 = (instruction >> 15) & 0x3Fu; int num4 = (int)((instruction >> 5) & 0x1F); int num5 = (int)(instruction & 0x1F); if (num) { throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): M is reserved"); } if (flag) { throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): S is reserved"); } if (num3.TestBit(5)) { throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): top bit of opcode is reserved"); } if (num2 == 3 && num3 > 15) { throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): ptype 0b11 only allowed with opcode 0b0000 to 0b1111"); } if (num2 == 2) { throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): ptype 0b10 is reserved"); } Arm64Mnemonic arm64Mnemonic = num3 switch { 0u => Arm64Mnemonic.FMOV, 1u => Arm64Mnemonic.FABS, 2u => Arm64Mnemonic.FNEG, 3u => Arm64Mnemonic.FSQRT, 4u => throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): opcode 0b000100 is reserved"), 5u => Arm64Mnemonic.FCVT, 6u => throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): opcode 0b000110 is reserved"), 7u => Arm64Mnemonic.FCVT, 8u => Arm64Mnemonic.FRINTN, 9u => Arm64Mnemonic.FRINTP, 10u => Arm64Mnemonic.FRINTM, 11u => Arm64Mnemonic.FRINTZ, 12u => Arm64Mnemonic.FRINTA, 13u => throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): opcode 0b001101 is reserved"), 14u => Arm64Mnemonic.FRINTX, 15u => Arm64Mnemonic.FRINTI, 16u => Arm64Mnemonic.FRINT32Z, 17u => Arm64Mnemonic.FRINT32X, 18u => Arm64Mnemonic.FRINT64Z, 19u => Arm64Mnemonic.FRINT64X, _ => throw new Arm64UndefinedInstructionException($"Floating-point data-processing (1 source): opcode 0x{num3:X2} is reserved"), }; Arm64MnemonicCategory arm64MnemonicCategory = ((arm64Mnemonic != Arm64Mnemonic.FABS && arm64Mnemonic != Arm64Mnemonic.FNEG && arm64Mnemonic != Arm64Mnemonic.FSQRT) ? Arm64MnemonicCategory.FloatingPointDataProcessing : Arm64MnemonicCategory.FloatingPointMath); Arm64MnemonicCategory mnemonicCategory = arm64MnemonicCategory; int num6 = num2 switch { 0u => 129, 1u => 97, 3u => 161, _ => throw new Exception("Impossible ptype"), }; Arm64Register op0Reg = (Arm64Register)(num6 + num5); Arm64Register op1Reg = (Arm64Register)(num6 + num4); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.MnemonicCategory = mnemonicCategory; return result; } public static Arm64Instruction DataProcessingTwoSource(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(29); uint num3 = (instruction >> 22) & 3u; int num4 = (int)((instruction >> 16) & 0x1F); uint num5 = (instruction >> 12) & 0xFu; int num6 = (int)((instruction >> 5) & 0x1F); int num7 = (int)(instruction & 0x1F); if (num2) { throw new Arm64UndefinedInstructionException("Floating point: Data processing 2-source: S flag is reserved"); } if (num) { throw new Arm64UndefinedInstructionException("Floating point: Data processing 2-source: M flag is reserved"); } if (num5.TestPattern(9) || num5.TestPattern(10) || num5.TestPattern(12)) { throw new Arm64UndefinedInstructionException($"Floating point: Data processing 2-source: Reserved opcode used: 0x{num5:X}"); } if (num3 == 2) { throw new Arm64UndefinedInstructionException("Floating point: Data processing 2-source: ptype 0b10 is reserved"); } Arm64Mnemonic mnemonic = num5 switch { 0u => Arm64Mnemonic.FMUL, 1u => Arm64Mnemonic.FDIV, 2u => Arm64Mnemonic.FADD, 3u => Arm64Mnemonic.FSUB, 4u => Arm64Mnemonic.FMAX, 5u => Arm64Mnemonic.FMIN, 6u => Arm64Mnemonic.FMAXNM, 7u => Arm64Mnemonic.FMINNM, 8u => Arm64Mnemonic.FNMUL, _ => throw new Exception("Impossible opcode"), }; int num8 = num3 switch { 0u => 129, 1u => 97, 3u => 161, _ => throw new Exception("Impossible ptype"), }; Arm64Register op0Reg = (Arm64Register)(num8 + num7); Arm64Register op1Reg = (Arm64Register)(num8 + num6); Arm64Register op2Reg = (Arm64Register)(num8 + num4); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.MnemonicCategory = Arm64MnemonicCategory.FloatingPointMath; return result; } public static Arm64Instruction DataProcessingThreeSource(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.FloatingPointMath; return result; } public static Arm64Instruction Compare(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(29); uint num3 = (instruction >> 22) & 3u; int num4 = (int)((instruction >> 16) & 0x1F); uint num5 = (instruction >> 14) & 3u; int num6 = (int)((instruction >> 5) & 0x1F); uint num7 = instruction & 0x1Fu; if (num2) { throw new Arm64UndefinedInstructionException("Floating point: Compare: S flag is reserved"); } if (num) { throw new Arm64UndefinedInstructionException("Floating point: Compare: M flag is reserved"); } if (num3 == 2) { throw new Arm64UndefinedInstructionException("Floating point: Compare: ptype 0b10 is reserved"); } if (num5 != 0) { throw new Arm64UndefinedInstructionException("Floating point: Compare: values other than 0 for op are reserved"); } if (num7.TestPattern(1) || num7.TestPattern(2) || num7.TestPattern(4)) { throw new Arm64UndefinedInstructionException($"Floating point: Compare: Reserved opcode2: 0x{num7:X}"); } Arm64Mnemonic mnemonic = num7 switch { 0u => Arm64Mnemonic.FCMP, 8u => Arm64Mnemonic.FCMP, 16u => Arm64Mnemonic.FCMPE, 24u => Arm64Mnemonic.FCMPE, _ => throw new Exception("Impossible opcode2"), }; int num8 = num3 switch { 0u => 129, 1u => 97, 3u => 161, _ => throw new Exception("Impossible ptype"), }; Arm64Register op0Reg = (Arm64Register)(num8 + num6); Arm64Register op1Reg = (Arm64Register)(num8 + num4); Arm64Instruction result; if (num7.TestBit(3)) { result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Immediate; result.Op0Reg = op0Reg; result.Op1Imm = 0L; return result; } result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; return result; } public static Arm64Instruction Immediate(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(29); uint num3 = (instruction >> 22) & 3u; uint imm = (instruction >> 13) & 0xFFu; uint num4 = (instruction >> 5) & 0x1F; int num5 = (int)(instruction & 0x1F); if (num4 != 0) { throw new Arm64UndefinedInstructionException("Floating point: Immediate: all bits of imm5 are reserved"); } if (num2) { throw new Arm64UndefinedInstructionException("Floating point: Immediate: S flag is reserved"); } if (num) { throw new Arm64UndefinedInstructionException("Floating point: Immediate: M flag is reserved"); } Arm64Register arm64Register = num3 switch { 2u => throw new Arm64UndefinedInstructionException("Floating point: Immediate: ptype 0b10 is reserved"), 0u => Arm64Register.S0, 1u => Arm64Register.D0, 3u => Arm64Register.H0, _ => throw new Exception("Impossible ptype"), }; double op1FpImm = Arm64CommonUtils.DecodeFPImm(num3, imm); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.FMOV; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.FloatingPointImmediate; result.Op0Reg = arm64Register + num5; result.Op1FpImm = op1FpImm; result.MnemonicCategory = Arm64MnemonicCategory.FloatingPointDataProcessing; return result; } public static Arm64Instruction ConditionalCompare(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Comparison; return result; } public static Arm64Instruction ConditionalSelect(uint instruction) { bool num = instruction.TestBit(31); bool num2 = instruction.TestBit(29); uint num3 = (instruction >> 22) & 3u; int num4 = (int)((instruction >> 16) & 0x1F); uint num5 = (instruction >> 12) & 0xFu; int num6 = (int)((instruction >> 5) & 0x1F); int num7 = (int)(instruction & 0x1F); if (num2) { throw new Arm64UndefinedInstructionException("Floating point: Conditional select: S flag is reserved"); } if (num) { throw new Arm64UndefinedInstructionException("Floating point: Conditional select: M flag is reserved"); } int num8 = num3 switch { 2u => throw new Arm64UndefinedInstructionException("Floating point: Conditional select: ptype 0b10 is reserved"), 0u => 129, 1u => 97, 3u => 161, _ => throw new Exception("Impossible ptype"), }; Arm64Register op0Reg = (Arm64Register)(num8 + num7); Arm64Register op1Reg = (Arm64Register)(num8 + num6); Arm64Register op2Reg = (Arm64Register)(num8 + num4); Arm64ConditionCode finalOpConditionCode = (Arm64ConditionCode)num5; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.FCSEL; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.FinalOpConditionCode = finalOpConditionCode; result.MnemonicCategory = Arm64MnemonicCategory.FloatingPointComparison; return result; } } internal static class Arm64Hints { public static Arm64Instruction Disassemble(uint instruction) { uint num = (instruction >> 8) & 0xF; uint num2 = (instruction >> 5) & 7u; Arm64Instruction result; if (num == 0 && num2 == 0) { result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.NOP; return result; } result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Hint; return result; } } internal static class Arm64LoadsStores { public static Arm64Instruction Disassemble(uint instruction) { uint num = instruction >> 28; uint num2 = (instruction >> 26) & 1u; uint num3 = (instruction >> 23) & 3u; uint num4 = (instruction >> 16) & 0x3Fu; if ((num & 0xB) == 0) { return DisassembleAdvancedLoadStore(instruction); } if (num == 13 && num2 == 0 && num3 >> 1 == 1 && num4 >> 5 == 1) { return DisassembleLoadStoreMemoryTags(instruction); } if ((num & 0xB) == 8) { if (num2 == 0 && num3 == 0 && num4.TestBit(5)) { return LoadStoreExclusivePair(instruction); } throw new Arm64UndefinedInstructionException($"Load/store: Undefined instruction - op0={num}, op1={num2}, op2={num3}, op3={num4}"); } return (num & 3) switch { 0u => DisassembleLoadStoreExclusiveRegOrderedOrCompareSwap(instruction), 1u => DisassembleLdAprRegisterLiteralOrMemoryCopySet(instruction), 2u => DisassembleLoadStorePairs(instruction), 3u => DisassembleLoadStoreRegisterOrAtomic(instruction), _ => throw new Exception("Loads/stores: Impossible op0 value"), }; } private static Arm64Instruction DisassembleAdvancedLoadStore(uint instruction) { uint num = (instruction >> 23) & 3u; uint num2 = (instruction >> 16) & 0x3Fu; if (num == 3) { return Arm64Simd.LoadStoreSingleStructurePostIndexed(instruction); } if ((num2 & 0x1F) == 0) { return Arm64Simd.LoadStoreSingleStructure(instruction); } throw new Arm64UndefinedInstructionException($"Advanced load/store: Congrats, you hit the minefield of undefined instructions. op2: {num}, op3: {num2}"); } private static Arm64Instruction DisassembleLoadStoreMemoryTags(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryTagging; return result; } private static Arm64Instruction DisassembleLoadStoreExclusiveRegOrderedOrCompareSwap(uint instruction) { bool num = instruction.TestBit(26); uint num2 = (instruction >> 23) & 3u; uint instruction2 = (instruction >> 16) & 0x3Fu; if (num) { throw new Arm64UndefinedInstructionException("Load/store (exclusive register|ordered)|compare/swap: op1 set"); } if (num2 == 0 && instruction2.TestBit(6)) { throw new Arm64UndefinedInstructionException("Load/store (exclusive register|ordered)|compare/swap: op2=0, op3 hi bit set"); } switch (num2) { case 0u: return LoadStoreExclusiveRegister(instruction); default: throw new Arm64UndefinedInstructionException("Load/store (exclusive register|ordered)|compare/swap: op2 was not 0 or 1"); case 1u: if (instruction2.TestBit(6)) { return CompareAndSwap(instruction); } return LoadStoreOrdered(instruction); } } private static Arm64Instruction LoadStoreExclusiveRegister(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction CompareAndSwap(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Comparison; return result; } private static Arm64Instruction LoadStoreOrdered(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction DisassembleLdAprRegisterLiteralOrMemoryCopySet(uint instruction) { instruction.TestBit(26); uint instruction2 = (instruction >> 23) & 3; uint instruction3 = (instruction >> 16) & 0x3Fu; uint instruction4 = (instruction >> 10) & 3u; if (!instruction2.TestBit(1)) { return LoadRegisterLiteral(instruction); } if (instruction3.TestBit(5)) { throw new Arm64UndefinedInstructionException("LdAprRegisterLiteralOrMemoryCopySet: op3 hi bit set"); } if (!instruction4.TestBit(0)) { return LdaprOrStlr(instruction); } return MemoryCopyOrSet(instruction); } private static Arm64Instruction LoadRegisterLiteral(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction MemoryCopyOrSet(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Move; return result; } private static Arm64Instruction LdaprOrStlr(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction DisassembleLoadStorePairs(uint instruction) { return ((instruction >> 23) & 3) switch { 0u => LoadStoreNoAllocatePairs(instruction), 1u => LoadStoreRegisterPair(instruction, MemoryAccessMode.PostIndex), 2u => LoadStoreRegisterPair(instruction, MemoryAccessMode.Offset), 3u => LoadStoreRegisterPair(instruction, MemoryAccessMode.PreIndex), _ => throw new Exception("Loads/store pairs: Impossible op2 value"), }; } private static Arm64Instruction DisassembleLoadStoreRegisterOrAtomic(uint instruction) { uint num = (instruction >> 23) & 3; uint num2 = (instruction >> 16) & 0x3Fu; uint num3 = (instruction >> 10) & 3u; if (num >> 1 == 1) { return LoadStoreRegFromImmUnsigned(instruction); } if (num2 >> 5 == 1) { return num3 switch { 0u => AtomicMemoryOperation(instruction), 2u => LoadStoreRegisterFromRegisterOffset(instruction), _ => LoadStoreRegisterFromPac(instruction), }; } return num3 switch { 0u => LoadStoreRegisterFromImmUnscaled(instruction), 1u => LoadStoreRegisterFromImm(instruction, MemoryAccessMode.PostIndex), 2u => LoadStoreRegisterUnprivileged(instruction), 3u => LoadStoreRegisterFromImm(instruction, MemoryAccessMode.PreIndex), _ => throw new Exception("Impossible op4"), }; } private static Arm64Instruction LoadStoreRegisterFromImm(uint instruction, MemoryAccessMode memoryAccessMode) { uint num = (instruction >> 30) & 3u; bool flag = instruction.TestBit(26); uint num2 = (instruction >> 22) & 3u; uint num3 = (instruction >> 12) & 0x1FFu; int num4 = (int)((instruction >> 5) & 0x1F); int num5 = (int)(instruction & 0x1F); if (num == 2 || num == 3) { bool num6; if (!flag) { num6 = num2 == 3; } else { if (num2 == 2) { goto IL_004e; } num6 = num2 == 3; } if (num6) { goto IL_004e; } } Arm64Mnemonic arm64Mnemonic2; switch (num2) { case 0u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STRB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STRH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 1u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 2u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSB; break; } if (flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSH; break; } goto default; case 2u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSW; break; } goto default; default: throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 3u: { uint num7 = num; Arm64Mnemonic arm64Mnemonic; if (num7 != 0) { if (num7 != 1 || flag) { goto IL_0235; } arm64Mnemonic = Arm64Mnemonic.LDRSH; } else if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSB; } else { if (!flag) { goto IL_0235; } arm64Mnemonic = Arm64Mnemonic.LDR; } arm64Mnemonic2 = arm64Mnemonic; break; } default: { throw new Exception("Impossible opc value"); } IL_0235: throw new Exception($"Impossible size: {num}"); } Arm64Mnemonic arm64Mnemonic3 = arm64Mnemonic2; Arm64Register arm64Register; switch (arm64Mnemonic3) { case Arm64Mnemonic.LDR: case Arm64Mnemonic.STR: arm64Register = ((flag && num2 == 0) ? (num switch { 0u => Arm64Register.B0, 1u => Arm64Register.H0, 2u => Arm64Register.S0, 3u => Arm64Register.D0, _ => throw new Exception("Impossible size"), }) : ((!flag) ? ((num == 2) ? Arm64Register.W0 : Arm64Register.X0) : Arm64Register.V0)); break; case Arm64Mnemonic.LDRB: case Arm64Mnemonic.LDRH: case Arm64Mnemonic.STRB: case Arm64Mnemonic.STRH: arm64Register = Arm64Register.W0; break; case Arm64Mnemonic.LDRSH: arm64Register = ((num2 != 2) ? Arm64Register.W0 : Arm64Register.X0); break; case Arm64Mnemonic.LDRSW: arm64Register = Arm64Register.X0; break; default: throw new Exception("Impossible mnemonic"); } Arm64Register op0Reg = arm64Register + num5; Arm64Register memBase = (Arm64Register)(33 + num4); long memOffset = Arm64CommonUtils.SignExtend(num3, 9, 64); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic3; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Memory; result.MemIsPreIndexed = memoryAccessMode == MemoryAccessMode.PreIndex; result.Op0Reg = op0Reg; result.MemBase = memBase; result.MemOffset = memOffset; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; IL_004e: throw new Arm64UndefinedInstructionException($"Load/store immediate pre-indexed: Invalid size/opc combination. size: {num}, opc: {num2}"); } private static Arm64Instruction LoadStoreNoAllocatePairs(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction LoadStoreRegisterPair(uint instruction, MemoryAccessMode mode) { uint num = (instruction >> 30) & 3u; uint original = (instruction >> 15) & 0x7Fu; int num2 = (int)((instruction >> 10) & 0x1F); int num3 = (int)((instruction >> 5) & 0x1F); int num4 = (int)(instruction & 0x1F); bool flag = instruction.TestBit(26); bool flag2 = instruction.TestBit(22); if (num == 3) { throw new Arm64UndefinedInstructionException("Load/store register pair (pre-indexed): opc == 0b11"); } Arm64Mnemonic arm64Mnemonic = (flag2 ? Arm64Mnemonic.LDP : Arm64Mnemonic.STP); if (num == 1 && !flag) { arm64Mnemonic = (flag2 ? Arm64Mnemonic.LDPSW : Arm64Mnemonic.STGP); } Arm64Register arm64Register = num switch { 0u => (!flag) ? Arm64Register.W0 : Arm64Register.S0, 1u => (arm64Mnemonic == Arm64Mnemonic.STGP) ? Arm64Register.W0 : Arm64Register.D0, 2u => (!flag) ? Arm64Register.X0 : Arm64Register.V0, _ => throw new Exception("Impossible opc value"), }; int num5 = num switch { 0u => 32, 1u => (arm64Mnemonic != Arm64Mnemonic.STGP) ? 64 : 32, 2u => (!flag) ? 64 : 128, _ => throw new Exception("Impossible opc value"), } / 8; int num6 = Arm64CommonUtils.CorrectSignBit(original, 7); Arm64Register op0Reg = arm64Register + num4; Arm64Register op1Reg = arm64Register + num2; Arm64Register memBase = (Arm64Register)(33 + num3); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Memory; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.MemBase = memBase; result.MemOffset = num6 * num5; result.MemIsPreIndexed = mode == MemoryAccessMode.PreIndex; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) { uint num = (instruction >> 30) & 3u; bool flag = instruction.TestBit(26); uint num2 = (instruction >> 22) & 3u; uint num3 = (instruction >> 10) & 0xFFFu; int num4 = (int)((instruction >> 5) & 0x1F); int num5 = (int)(instruction & 0x1F); Arm64Mnemonic arm64Mnemonic2; switch (num2) { case 0u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STRB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STRH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 1u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 2u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSB; break; } if (flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSH; break; } goto default; case 2u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSW; break; } goto default; case 3u: throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b10 unallocated for size 0b11"); default: if (flag) { throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b10 unallocated for vectors when size > 0"); } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 3u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSB; break; } if (flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSH; break; } goto default; case 2u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.PRFM; break; } goto default; case 3u: throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b11 unallocated for size 0b11"); default: if (flag) { throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b11 unallocated for vectors when size > 0"); } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } default: throw new Exception("Impossible opc value"); } Arm64Mnemonic arm64Mnemonic3 = arm64Mnemonic2; if (arm64Mnemonic3 == Arm64Mnemonic.PRFM) { throw new NotImplementedException("If you're seeing this, reach out, because PRFM is not implemented."); } Arm64Register arm64Register; switch (arm64Mnemonic3) { case Arm64Mnemonic.LDR: case Arm64Mnemonic.STR: arm64Register = ((flag && num2 == 0) ? (num switch { 0u => Arm64Register.B0, 1u => Arm64Register.H0, 2u => Arm64Register.S0, 3u => Arm64Register.D0, _ => throw new Exception("Impossible size"), }) : ((!flag) ? ((num == 2) ? Arm64Register.W0 : Arm64Register.X0) : Arm64Register.V0)); break; case Arm64Mnemonic.LDRB: case Arm64Mnemonic.LDRH: case Arm64Mnemonic.STRB: case Arm64Mnemonic.STRH: arm64Register = Arm64Register.W0; break; case Arm64Mnemonic.LDRSH: arm64Register = ((num2 != 2) ? Arm64Register.W0 : Arm64Register.X0); break; case Arm64Mnemonic.LDRSW: arm64Register = Arm64Register.X0; break; default: throw new Exception("Impossible mnemonic"); } Arm64Register op0Reg = arm64Register + num5; Arm64Register memBase = (Arm64Register)(33 + num4); long num6 = num3; num6 <<= (int)num; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic3; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Memory; result.Op0Reg = op0Reg; result.MemBase = memBase; result.MemOffset = num6; result.MemIsPreIndexed = false; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction AtomicMemoryOperation(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction LoadStoreRegisterFromRegisterOffset(uint instruction) { uint num = (instruction >> 30) & 3u; bool flag = instruction.TestBit(26); uint num2 = (instruction >> 22) & 3u; int num3 = (int)((instruction >> 16) & 0x1F); uint num4 = (instruction >> 13) & 7u; bool flag2 = instruction.TestBit(12); int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); Arm64Mnemonic arm64Mnemonic2; switch (num2) { case 0u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STRB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STRH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 1u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 2u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSB; break; } if (flag) { arm64Mnemonic = Arm64Mnemonic.STR; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSH; break; } goto default; case 2u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSW; break; } goto default; case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.PRFM; break; } goto default; default: if (flag) { throw new Arm64UndefinedInstructionException("Load/store register from register offset: opc 0b10 unallocated for vectors when size > 0"); } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 3u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSB; break; } if (flag) { arm64Mnemonic = Arm64Mnemonic.LDR; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDRSH; break; } goto default; case 2u: case 3u: throw new Arm64UndefinedInstructionException("Load/store register from register offset: opc 0b11 unallocated for size 0b1x"); default: if (flag) { throw new Arm64UndefinedInstructionException("Load/store register from register offset: opc 0b11 unallocated for vectors when size > 0"); } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } default: throw new Exception("Impossible opc value"); } Arm64Mnemonic arm64Mnemonic3 = arm64Mnemonic2; bool flag3 = num4 == 3; if (arm64Mnemonic3 == Arm64Mnemonic.PRFM) { throw new NotImplementedException("If you're seeing this, reach out, because PRFM is not implemented."); } Arm64Register arm64Register; switch (arm64Mnemonic3) { case Arm64Mnemonic.LDR: case Arm64Mnemonic.STR: arm64Register = ((flag && num2 == 0) ? (num switch { 0u => Arm64Register.B0, 1u => Arm64Register.H0, 2u => Arm64Register.S0, 3u => Arm64Register.D0, _ => throw new Exception("Impossible size"), }) : ((!flag) ? ((num == 2) ? Arm64Register.W0 : Arm64Register.X0) : Arm64Register.V0)); break; case Arm64Mnemonic.LDRB: case Arm64Mnemonic.LDRH: case Arm64Mnemonic.STRB: case Arm64Mnemonic.STRH: arm64Register = Arm64Register.W0; break; case Arm64Mnemonic.LDRSH: arm64Register = ((num2 != 2) ? Arm64Register.W0 : Arm64Register.X0); break; case Arm64Mnemonic.LDRSW: arm64Register = Arm64Register.X0; break; default: throw new Exception("Impossible mnemonic"); } Arm64Register arm64Register2 = arm64Register; Arm64Register arm64Register3 = ((!num4.TestBit(0)) ? Arm64Register.W0 : Arm64Register.X0); Arm64ExtendType arm64ExtendType = (Arm64ExtendType)num4; int memExtendOrShiftAmount = 0; if (flag2 && flag3) { memExtendOrShiftAmount = num switch { 0u => (flag && num2 == 3) ? 4 : 0, 1u => 1, 2u => 2, 3u => 3, _ => throw new Exception("Impossible size"), }; } Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic3; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Memory; result.Op0Reg = arm64Register2 + num6; result.MemBase = (Arm64Register)(33 + num5); result.MemAddendReg = arm64Register3 + num3; result.MemIsPreIndexed = false; result.MemExtendType = (flag3 ? Arm64ExtendType.NONE : arm64ExtendType); result.MemShiftType = ((!flag3) ? Arm64ShiftType.NONE : Arm64ShiftType.LSL); result.MemExtendOrShiftAmount = memExtendOrShiftAmount; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction LoadStoreRegisterFromPac(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.PointerAuthentication; return result; } private static Arm64Instruction LoadStoreRegisterFromImmUnscaled(uint instruction) { uint num = (instruction >> 30) & 3u; bool flag = instruction.TestBit(26); uint num2 = (instruction >> 22) & 3u; uint num3 = (instruction >> 12) & 0x1FFu; int num4 = (int)((instruction >> 5) & 0x1F); int num5 = (int)(instruction & 0x1F); if ((num == 1 || num == 3) && flag && num2 > 1) { throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc > 1 unallocated for vectors when size > 1"); } Arm64Mnemonic arm64Mnemonic2; switch (num2) { case 0u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STURB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STURH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.STUR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.STUR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 1u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDURB; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDURH; break; } goto default; case 2u: case 3u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDUR; break; } goto default; default: if (flag) { arm64Mnemonic = Arm64Mnemonic.LDUR; break; } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 2u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDURSB; break; } if (flag) { arm64Mnemonic = Arm64Mnemonic.STUR; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDURSH; break; } goto default; case 2u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDURSW; break; } goto default; default: if (flag) { throw new Arm64UndefinedInstructionException("Load/store register from immediate (unscaled): opc 0b10 unallocated for vectors when size > 0"); } throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } case 3u: { Arm64Mnemonic arm64Mnemonic; switch (num) { case 0u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDURSB; break; } if (flag) { arm64Mnemonic = Arm64Mnemonic.LDUR; break; } goto default; case 1u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.LDURSH; break; } goto default; case 2u: if (!flag) { arm64Mnemonic = Arm64Mnemonic.PRFUM; break; } goto default; case 3u: throw new Arm64UndefinedInstructionException("Load/store register from immediate (unscaled): opc 0b11 unallocated for size 0b11"); default: throw new Exception($"Impossible size: {num}"); } arm64Mnemonic2 = arm64Mnemonic; break; } default: throw new Exception("Impossible opc value"); } Arm64Mnemonic arm64Mnemonic3 = arm64Mnemonic2; if (arm64Mnemonic3 == Arm64Mnemonic.PRFUM) { throw new NotImplementedException("If you're seeing this, reach out, because PRFUM is not implemented."); } Arm64Register arm64Register; switch (arm64Mnemonic3) { case Arm64Mnemonic.LDUR: case Arm64Mnemonic.STUR: arm64Register = ((flag && num2 == 0) ? (num switch { 0u => Arm64Register.B0, 1u => Arm64Register.H0, 2u => Arm64Register.S0, 3u => Arm64Register.D0, _ => throw new Exception("Impossible size"), }) : ((!flag) ? ((num == 2) ? Arm64Register.W0 : Arm64Register.X0) : Arm64Register.V0)); break; case Arm64Mnemonic.LDURB: case Arm64Mnemonic.LDURH: case Arm64Mnemonic.STURB: case Arm64Mnemonic.STURH: arm64Register = Arm64Register.W0; break; case Arm64Mnemonic.LDURSH: arm64Register = ((num2 != 2) ? Arm64Register.W0 : Arm64Register.X0); break; case Arm64Mnemonic.LDURSW: arm64Register = Arm64Register.X0; break; default: throw new Exception("Impossible mnemonic"); } Arm64Register op0Reg = arm64Register + num5; Arm64Register memBase = (Arm64Register)(33 + num4); long memOffset = Arm64CommonUtils.SignExtend(num3, 9, 64); Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic3; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Memory; result.Op0Reg = op0Reg; result.MemBase = memBase; result.MemOffset = memOffset; result.MemIsPreIndexed = false; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction LoadStoreRegisterUnprivileged(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } private static Arm64Instruction LoadStoreExclusivePair(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister; return result; } } internal static class Arm64NonScalarAdvancedSimd { public static Arm64Instruction Disassemble(uint instruction) { uint num = (instruction >> 28) & 0xFu; uint num2 = (instruction >> 23) & 3u; uint num3 = (instruction >> 19) & 0xFu; uint num4 = (instruction >> 10) & 0x1FFu; bool flag = num2 >> 1 == 1; uint num5 = num3 >> 2; bool flag2 = (num4 & 1) == 1; switch (num2) { case 3u: throw new Arm64UndefinedInstructionException("Advanced SIMD instruction with op1 == 11"); case 2u: if (!flag2) { return AdvancedSimdVectorXIndexedElement(instruction); } if (num3 != 0) { return AdvancedSimdShiftByImmediate(instruction); } return AdvancedSimdModifiedImmediate(instruction); case 0u: if (num5 == 0 && (num4 & 0x21) == 1) { return AdvancedSimdCopy(instruction); } break; } if ((num & 0xB) == 0 && !flag && (num5 & 1) == 0) { switch (num4 & 0x23) { case 0u: return AdvancedSimdTableLookup(instruction); case 2u: return AdvancedSimdPermute(instruction); } } if ((num & 0xB) == 2 && !flag && (num5 & 1) == 0 && (num4 & 0x21) == 0) { return AdvancedSimdExtract(instruction); } if (num2 == 0 && num5 == 0 && (num4 & 0x21) == 1) { return AdvancedSimdCopy(instruction); } if (num5 == 2 && (num4 & 0x31) == 1) { return AdvancedSimdThreeSameFp16(instruction); } if (num3 == 15 && (num4 & 0x183) == 2) { return AdvancedSimdTwoRegisterMiscFp16(instruction); } if ((num5 & 1) == 0 && num4 * 33 == 33) { return AdvancedSimdThreeRegExtension(instruction); } if ((num3 == 4 || num3 == 12) && (num4 & 0x183) == 2) { return AdvancedSimdTwoRegisterMisc(instruction); } if ((num3 == 6 || num3 == 14) && (num4 & 0x183) == 2) { return AdvancedSimdAcrossLanes(instruction); } if ((num5 & 1) == 1) { if ((num4 & 3) == 0) { return AdvancedSimdThreeDifferent(instruction); } if (flag2) { return AdvancedSimdThreeSame(instruction); } } throw new Arm64UndefinedInstructionException($"Advanced SIMD instruction (non-scalar): op0: {num}, op1: {num2}, op2: {num3}, op3: {num4}"); } private static Arm64Instruction AdvancedSimdModifiedImmediate(uint instruction) { bool flag = instruction.TestBit(30); bool flag2 = instruction.TestBit(29); uint num = (instruction >> 16) & 7; uint num2 = (instruction >> 12) & 0xFu; bool flag3 = instruction.TestBit(11); uint num3 = (instruction >> 5) & 0x1Fu; int num4 = (int)(instruction & 0x1F); long num5 = (num << 5) | num3; if (flag2 && flag3) { throw new Arm64UndefinedInstructionException("Advanced SIMD: modified immediate: op == 1 and o2 == 1"); } if (!flag && flag2 && num2 == 15 && !flag3) { throw new Arm64UndefinedInstructionException("Advanced SIMD: modified immediate: q == 0, op == 1, cmode == 1111 and o2 == 0"); } if (!flag2 && flag3 && !num2.TestBit(3)) { throw new Arm64UndefinedInstructionException("Advanced SIMD: modified immediate: op == 0, o2 == 1 and high bit of cmode not set"); } if (!flag2 && flag3 && num2.TestPattern(12, 8)) { throw new Arm64UndefinedInstructionException("Advanced SIMD: modified immediate: op == 0, o2 == 1 and cmode matches 10xx"); } if (!flag2 && flag3 && num2.TestPattern(14, 12)) { throw new Arm64UndefinedInstructionException("Advanced SIMD: modified immediate: op == 0, o2 == 1 and cmode matches 110x"); } Arm64ArrangementSpecifier op0Arrangement; Arm64Instruction result; if (num2 == 15) { op0Arrangement = (flag2 ? Arm64ArrangementSpecifier.TwoD : ((!flag3) ? (flag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS) : (flag ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH))); ulong op1Imm = Arm64CommonUtils.AdvancedSimdExpandImmediate(flag2, (byte)num2, (byte)num5); result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.FMOV; result.Op0Kind = Arm64OperandKind.Register; result.Op0Reg = (Arm64Register)(65 + num4); result.Op0Arrangement = op0Arrangement; result.Op1Kind = Arm64OperandKind.Immediate; result.Op1Imm = (long)op1Imm; result.MnemonicCategory = Arm64MnemonicCategory.SimdConstantToRegister; return result; } Arm64Register arm64Register = Arm64Register.V0; Arm64Mnemonic mnemonic; int num7; if (!flag2) { if (num2.TestPattern(9, 0)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS); uint num6 = 8 * ((num2 >> 1) & 3); mnemonic = Arm64Mnemonic.MOVI; op0Arrangement = arm64ArrangementSpecifier; num7 = (int)num6; } else if (num2.TestPattern(13, 8)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH); int num8 = (num2.TestBit(1) ? 8 : 0); mnemonic = Arm64Mnemonic.MOVI; op0Arrangement = arm64ArrangementSpecifier; num7 = num8; } else if (num2.TestPattern(14, 12)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS); int num9 = (num2.TestBit(0) ? 16 : 8); mnemonic = Arm64Mnemonic.MOVI; op0Arrangement = arm64ArrangementSpecifier; num7 = num9; } else if (num2 == 14) { int num10 = (flag ? 7 : 6); mnemonic = Arm64Mnemonic.MOVI; op0Arrangement = (Arm64ArrangementSpecifier)num10; num7 = 0; } else if (num2.TestPattern(9, 1)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS); uint num11 = 8 * ((num2 >> 1) & 3); mnemonic = Arm64Mnemonic.ORR; op0Arrangement = arm64ArrangementSpecifier; num7 = (int)num11; } else { if (!num2.TestPattern(13, 9)) { throw new Exception("Impossible cmode"); } Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH); int num12 = (num2.TestBit(1) ? 8 : 0); mnemonic = Arm64Mnemonic.ORR; op0Arrangement = arm64ArrangementSpecifier; num7 = num12; } } else if (num2.TestPattern(9, 0)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS); uint num13 = 8 * ((num2 >> 1) & 3); mnemonic = Arm64Mnemonic.MVNI; op0Arrangement = arm64ArrangementSpecifier; num7 = (int)num13; } else if (num2.TestPattern(13, 8)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH); int num14 = (num2.TestBit(1) ? 8 : 0); mnemonic = Arm64Mnemonic.MVNI; op0Arrangement = arm64ArrangementSpecifier; num7 = num14; } else if (num2.TestPattern(14, 12)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS); int num15 = (num2.TestBit(0) ? 16 : 8); mnemonic = Arm64Mnemonic.MVNI; op0Arrangement = arm64ArrangementSpecifier; num7 = num15; } else if (num2.TestPattern(9, 1)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS); uint num16 = 8 * ((num2 >> 1) & 3); mnemonic = Arm64Mnemonic.BIC; op0Arrangement = arm64ArrangementSpecifier; num7 = (int)num16; } else if (num2.TestPattern(13, 9)) { Arm64ArrangementSpecifier arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH); int num17 = (num2.TestBit(1) ? 8 : 0); mnemonic = Arm64Mnemonic.BIC; op0Arrangement = arm64ArrangementSpecifier; num7 = num17; } else { if (num2 != 14) { throw new Exception("Impossible cmode"); } num5 = (long)Arm64CommonUtils.AdvancedSimdExpandImmediate(flag2, (byte)num2, (byte)num5); if (flag) { mnemonic = Arm64Mnemonic.MOVI; op0Arrangement = Arm64ArrangementSpecifier.TwoD; num7 = 0; } else { arm64Register = Arm64Register.D0; mnemonic = Arm64Mnemonic.MOVI; op0Arrangement = Arm64ArrangementSpecifier.None; num7 = 0; } } result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op0Reg = arm64Register + num4; result.Op0Arrangement = op0Arrangement; result.Op1Kind = Arm64OperandKind.Immediate; result.Op1Imm = num5; result.Op2Kind = ((num7 > 0) ? Arm64OperandKind.Immediate : Arm64OperandKind.None); result.Op2Imm = num7; result.Op2ShiftType = ((num7 <= 0) ? Arm64ShiftType.NONE : Arm64ShiftType.LSL); result.MnemonicCategory = Arm64MnemonicCategory.SimdConstantToRegister; return result; } private static Arm64Instruction AdvancedSimdShiftByImmediate(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath; return result; } private static Arm64Instruction AdvancedSimdVectorXIndexedElement(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath; return result; } private static Arm64Instruction AdvancedSimdCopy(uint instruction) { bool flag = instruction.TestBit(30); bool num = instruction.TestBit(29); uint num2 = (instruction >> 16) & 0x1Fu; uint num3 = (instruction >> 11) & 0xFu; byte b = (byte)((instruction >> 5) & 0x1Fu); byte b2 = (byte)(instruction & 0x1Fu); if ((num2 & 0xF) == 0) { throw new Arm64UndefinedInstructionException("AdvancedSimdCopy: bottom 4 bits of imm5 must not be zero"); } if (num && !flag) { throw new Arm64UndefinedInstructionException("AdvancedSimdCopy: op must be zero when qFlag is zero"); } Arm64Instruction result; if (num && flag) { Arm64VectorElementWidth width; uint index; uint index2; if (num2.TestBit(0)) { uint num4 = num2 >> 1; uint num5 = num3 & 0xF; width = Arm64VectorElementWidth.B; index = num4; index2 = num5; } else if (num2.TestBit(1)) { uint num4 = num2 >> 2; uint num6 = (num3 >> 1) & 7; width = Arm64VectorElementWidth.H; index = num4; index2 = num6; } else if (num2.TestBit(2)) { uint num4 = num2 >> 3; uint num7 = (num3 >> 2) & 3; width = Arm64VectorElementWidth.S; index = num4; index2 = num7; } else { uint num4 = num2 >> 4; uint num8 = (num3 >> 3) & 1; width = Arm64VectorElementWidth.D; index = num4; index2 = num8; } result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.INS; result.Op0Kind = Arm64OperandKind.VectorRegisterElement; result.Op0Reg = (Arm64Register)(65 + b2); result.Op0VectorElement = new Arm64VectorElement(width, (int)index); result.Op1Kind = Arm64OperandKind.VectorRegisterElement; result.Op1Reg = (Arm64Register)(65 + b); result.Op1VectorElement = new Arm64VectorElement(width, (int)index2); result.MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister; return result; } switch (num3) { case 0u: { Arm64Mnemonic arm64Mnemonic = Arm64Mnemonic.DUP; break; } case 1u: { Arm64Mnemonic arm64Mnemonic = Arm64Mnemonic.DUP; break; } case 5u: { Arm64Mnemonic arm64Mnemonic = Arm64Mnemonic.SMOV; break; } case 7u: { Arm64Mnemonic arm64Mnemonic = Arm64Mnemonic.UMOV; break; } case 3u: if (flag) { Arm64Mnemonic arm64Mnemonic = Arm64Mnemonic.INS; break; } goto default; default: throw new Arm64UndefinedInstructionException($"AdvancedSimdCopy: imm4 0x{num3:X} is reserved"); } result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister; return result; } private static Arm64Instruction AdvancedSimdTableLookup(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister; return result; } private static Arm64Instruction AdvancedSimdPermute(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister; return result; } private static Arm64Instruction AdvancedSimdExtract(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister; return result; } private static Arm64Instruction AdvancedSimdThreeSameFp16(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath; return result; } private static Arm64Instruction AdvancedSimdTwoRegisterMiscFp16(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; return result; } private static Arm64Instruction AdvancedSimdThreeRegExtension(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath; return result; } private static Arm64Instruction AdvancedSimdTwoRegisterMisc(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; return result; } private static Arm64Instruction AdvancedSimdAcrossLanes(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath; return result; } private static Arm64Instruction AdvancedSimdThreeDifferent(uint instruction) { bool flag = instruction.TestBit(30); bool num = instruction.TestBit(29); uint num2 = (instruction >> 22) & 3u; int num3 = (int)((instruction >> 16) & 0x1F); uint num4 = (instruction >> 12) & 0xFu; int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); if (num4 == 15) { throw new Arm64UndefinedInstructionException("AdvancedSimdThreeSame: opcode == 1111"); } if (num2 == 3) { throw new Arm64UndefinedInstructionException("AdvancedSimdThreeSame: size = 11"); } Arm64Mnemonic mnemonic = ((!num) ? (num4 switch { 0u => (!flag) ? Arm64Mnemonic.SADDL : Arm64Mnemonic.SADDL2, 1u => (!flag) ? Arm64Mnemonic.SADDW : Arm64Mnemonic.SADDW2, 2u => (!flag) ? Arm64Mnemonic.SSUBL : Arm64Mnemonic.SSUBL2, 3u => (!flag) ? Arm64Mnemonic.SSUBW : Arm64Mnemonic.SSUBW2, 4u => (!flag) ? Arm64Mnemonic.ADDHN : Arm64Mnemonic.ADDHN2, 5u => (!flag) ? Arm64Mnemonic.SABAL : Arm64Mnemonic.SABAL2, 6u => (!flag) ? Arm64Mnemonic.SUBHN : Arm64Mnemonic.SUBHN2, 7u => (!flag) ? Arm64Mnemonic.SABDL : Arm64Mnemonic.SABDL2, 8u => (!flag) ? Arm64Mnemonic.SMLAL : Arm64Mnemonic.SMLAL2, 9u => (!flag) ? Arm64Mnemonic.SQDMLAL : Arm64Mnemonic.SQDMLAL2, 10u => (!flag) ? Arm64Mnemonic.SMLSL : Arm64Mnemonic.SMLSL2, 11u => (!flag) ? Arm64Mnemonic.SQDMLSL : Arm64Mnemonic.SQDMLSL2, 12u => (!flag) ? Arm64Mnemonic.SMULL : Arm64Mnemonic.SMULL2, 13u => (!flag) ? Arm64Mnemonic.SQDMULL : Arm64Mnemonic.SQDMULL2, 14u => (!flag) ? Arm64Mnemonic.PMULL : Arm64Mnemonic.PMULL2, _ => throw new Exception("Impossible opcode"), }) : (num4 switch { 0u => (!flag) ? Arm64Mnemonic.UADDL : Arm64Mnemonic.UADDL2, 1u => (!flag) ? Arm64Mnemonic.UADDW : Arm64Mnemonic.UADDW2, 2u => (!flag) ? Arm64Mnemonic.USUBL : Arm64Mnemonic.USUBL2, 3u => (!flag) ? Arm64Mnemonic.USUBW : Arm64Mnemonic.USUBW2, 4u => (!flag) ? Arm64Mnemonic.RADDHN : Arm64Mnemonic.RADDHN2, 5u => (!flag) ? Arm64Mnemonic.UABAL : Arm64Mnemonic.UABAL2, 6u => (!flag) ? Arm64Mnemonic.RSUBHN : Arm64Mnemonic.RSUBHN2, 7u => (!flag) ? Arm64Mnemonic.UABDL : Arm64Mnemonic.UABDL2, 8u => (!flag) ? Arm64Mnemonic.UMLAL : Arm64Mnemonic.UMLAL2, 9u => throw new Arm64UndefinedInstructionException("AdvancedSimdThreeSame: U && opcode == 1001"), 10u => (!flag) ? Arm64Mnemonic.UMLSL : Arm64Mnemonic.UMLSL2, 11u => throw new Arm64UndefinedInstructionException("AdvancedSimdThreeSame: U && opcode == 1011"), 12u => (!flag) ? Arm64Mnemonic.UMULL : Arm64Mnemonic.UMULL2, 13u => throw new Arm64UndefinedInstructionException("AdvancedSimdThreeSame: U && opcode == 1101"), 14u => throw new Arm64UndefinedInstructionException("AdvancedSimdThreeSame: U && opcode == 1110"), _ => throw new Exception("Impossible opcode"), })); Arm64Register arm64Register = Arm64Register.V0; Arm64ArrangementSpecifier op0Arrangement = num2 switch { 0u => Arm64ArrangementSpecifier.EightH, 1u => Arm64ArrangementSpecifier.FourS, 2u => Arm64ArrangementSpecifier.TwoD, _ => throw new Exception("Impossible size"), }; Arm64ArrangementSpecifier arm64ArrangementSpecifier = num2 switch { 0u => (!flag) ? Arm64ArrangementSpecifier.SixteenB : Arm64ArrangementSpecifier.EightB, 1u => (!flag) ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH, 2u => (!flag) ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS, _ => throw new Exception("Impossible size"), }; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op0Reg = arm64Register + num6; result.Op1Reg = arm64Register + num5; result.Op2Reg = arm64Register + num3; result.Op0Arrangement = op0Arrangement; result.Op1Arrangement = arm64ArrangementSpecifier; result.Op2Arrangement = arm64ArrangementSpecifier; result.MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath; return result; } private static Arm64Instruction AdvancedSimdThreeSame(uint instruction) { bool flag = instruction.TestBit(30); bool num = instruction.TestBit(29); uint num2 = (instruction >> 22) & 3u; int num3 = (int)((instruction >> 16) & 0x1F); uint num4 = (instruction >> 11) & 0x1Fu; int num5 = (int)((instruction >> 5) & 0x1F); int num6 = (int)(instruction & 0x1F); bool flag2 = num2.TestBit(1); if (num) { throw new NotImplementedException(); } Arm64Mnemonic arm64Mnemonic; switch (num4) { case 0u: arm64Mnemonic = Arm64Mnemonic.SHADD; break; case 1u: arm64Mnemonic = Arm64Mnemonic.SQADD; break; case 2u: arm64Mnemonic = Arm64Mnemonic.SRHADD; break; case 3u: if (num2 == 0) { arm64Mnemonic = Arm64Mnemonic.AND; break; } if (num2 == 1) { arm64Mnemonic = Arm64Mnemonic.BIC; break; } if (num2 == 2) { arm64Mnemonic = Arm64Mnemonic.ORR; break; } if (num2 == 3) { arm64Mnemonic = Arm64Mnemonic.ORN; break; } goto default; case 4u: arm64Mnemonic = Arm64Mnemonic.SHSUB; break; case 5u: arm64Mnemonic = Arm64Mnemonic.SQSUB; break; case 6u: arm64Mnemonic = Arm64Mnemonic.CMGT; break; case 7u: arm64Mnemonic = Arm64Mnemonic.CMGE; break; case 8u: arm64Mnemonic = Arm64Mnemonic.SSHL; break; case 9u: arm64Mnemonic = Arm64Mnemonic.SQSHL; break; case 10u: arm64Mnemonic = Arm64Mnemonic.SRSHL; break; case 11u: arm64Mnemonic = Arm64Mnemonic.SQRSHL; break; case 12u: arm64Mnemonic = Arm64Mnemonic.SMAX; break; case 13u: arm64Mnemonic = Arm64Mnemonic.SMIN; break; case 14u: arm64Mnemonic = Arm64Mnemonic.SABD; break; case 15u: arm64Mnemonic = Arm64Mnemonic.SABA; break; case 16u: arm64Mnemonic = Arm64Mnemonic.ADD; break; case 17u: arm64Mnemonic = Arm64Mnemonic.CMTST; break; case 18u: arm64Mnemonic = Arm64Mnemonic.MLA; break; case 19u: arm64Mnemonic = Arm64Mnemonic.MUL; break; case 20u: arm64Mnemonic = Arm64Mnemonic.SMAXP; break; case 21u: arm64Mnemonic = Arm64Mnemonic.SMINP; break; case 22u: arm64Mnemonic = Arm64Mnemonic.SQDMULH; break; case 23u: arm64Mnemonic = Arm64Mnemonic.ADDP; break; case 24u: arm64Mnemonic = (flag2 ? Arm64Mnemonic.FMINNM : Arm64Mnemonic.FMAXNM); break; case 25u: arm64Mnemonic = (flag2 ? Arm64Mnemonic.FMLS : Arm64Mnemonic.FMLA); break; case 26u: arm64Mnemonic = (flag2 ? Arm64Mnemonic.FSUB : Arm64Mnemonic.FADD); break; case 27u: if (!flag2) { arm64Mnemonic = Arm64Mnemonic.FMULX; break; } throw new Arm64UndefinedInstructionException("Advanced SIMD three same: opcode 0b11011 with high size bit set"); case 28u: if (!flag2) { arm64Mnemonic = Arm64Mnemonic.FCMEQ; break; } throw new Arm64UndefinedInstructionException("Advanced SIMD three same: opcode 0b11100 with high size bit set"); case 29u: if (num2 == 0) { arm64Mnemonic = Arm64Mnemonic.FMLAL; break; } if (num2 == 1) { throw new Arm64UndefinedInstructionException("Advanced SIMD three same: opcode 0b11101 with size 0b01"); } if (num2 == 2) { arm64Mnemonic = Arm64Mnemonic.FMLSL; break; } if (num2 == 3) { throw new Arm64UndefinedInstructionException("Advanced SIMD three same: opcode 0b11101 with size 0b11"); } goto default; case 30u: arm64Mnemonic = (flag2 ? Arm64Mnemonic.FMIN : Arm64Mnemonic.FMAX); break; case 31u: arm64Mnemonic = (flag2 ? Arm64Mnemonic.FRSQRTS : Arm64Mnemonic.FRECPS); break; default: throw new Exception("Impossible opcode"); } Arm64Mnemonic arm64Mnemonic2 = arm64Mnemonic; Arm64MnemonicCategory arm64MnemonicCategory = (((uint)(arm64Mnemonic2 - 26) > 1u && arm64Mnemonic2 != Arm64Mnemonic.CMTST) ? Arm64MnemonicCategory.SimdVectorMath : Arm64MnemonicCategory.SimdComparison); Arm64MnemonicCategory mnemonicCategory = arm64MnemonicCategory; Arm64Register arm64Register; Arm64ArrangementSpecifier arm64ArrangementSpecifier; if (arm64Mnemonic2 == Arm64Mnemonic.AND || arm64Mnemonic2 == Arm64Mnemonic.BIC || arm64Mnemonic2 == Arm64Mnemonic.ORR || arm64Mnemonic2 == Arm64Mnemonic.ORN) { arm64Register = Arm64Register.V0; arm64ArrangementSpecifier = (flag ? Arm64ArrangementSpecifier.SixteenB : Arm64ArrangementSpecifier.EightB); } else { switch (num4) { case 0u: case 1u: case 2u: case 3u: case 4u: case 5u: case 6u: case 7u: case 8u: case 9u: case 10u: case 11u: case 12u: case 13u: case 14u: case 15u: case 16u: case 17u: case 18u: case 19u: case 20u: case 21u: case 22u: case 23u: arm64Register = num2 switch { 0u => Arm64Register.B0, 1u => Arm64Register.H0, 2u => Arm64Register.S0, 3u => Arm64Register.D0, _ => throw new Exception("Impossible size"), }; arm64ArrangementSpecifier = num2 switch { 0u => (!flag) ? Arm64ArrangementSpecifier.EightB : Arm64ArrangementSpecifier.SixteenB, 1u => (!flag) ? Arm64ArrangementSpecifier.FourH : Arm64ArrangementSpecifier.EightH, 2u => (!flag) ? Arm64ArrangementSpecifier.TwoS : Arm64ArrangementSpecifier.FourS, _ => throw new Exception("Impossible size"), }; break; case 29u: throw new NotImplementedException(); default: arm64ArrangementSpecifier = (((num2 & 1) << 1) | (uint)(flag ? 1 : 0)) switch { 0u => Arm64ArrangementSpecifier.TwoS, 1u => Arm64ArrangementSpecifier.FourS, 2u => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: arrangement: sz = 1, Q = 0: reserved"), 3u => Arm64ArrangementSpecifier.TwoD, _ => throw new Exception("Impossible arrangement bits"), }; arm64Register = Arm64Register.V0; break; } } Arm64Register op0Reg = arm64Register + num6; Arm64Register op1Reg = arm64Register + num5; Arm64Register op2Reg = arm64Register + num3; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = arm64Mnemonic2; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op2Kind = Arm64OperandKind.Register; result.Op0Arrangement = arm64ArrangementSpecifier; result.Op1Arrangement = arm64ArrangementSpecifier; result.Op2Arrangement = arm64ArrangementSpecifier; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.Op2Reg = op2Reg; result.MnemonicCategory = mnemonicCategory; return result; } } internal static class Arm64Pstate { public static Arm64Instruction Disassemble(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Pstate; return result; } } public enum Arm64Register { INVALID, W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, W16, W17, W18, W19, W20, W21, W22, W23, W24, W25, W26, W27, W28, W29, W30, W31, X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30, V31, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31, H0, H1, H2, H3, H4, H5, H6, H7, H8, H9, H10, H11, H12, H13, H14, H15, H16, H17, H18, H19, H20, H21, H22, H23, H24, H25, H26, H27, H28, H29, H30, H31, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B20, B21, B22, B23, B24, B25, B26, B27, B28, B29, B30, B31 } internal static class Arm64ScalarAdvancedSimd { public static Arm64Instruction Disassemble(uint instruction) { uint num = (instruction >> 23) & 3u; uint num2 = (instruction >> 19) & 0xFu; uint num3 = (instruction >> 10) & 0x1FFu; if (num == 0 && num2 >> 2 == 0 && num3.TestPattern(33, 1)) { return Copy(instruction); } if (num == 2 || num == 3) { if (num3.TestBit(0)) { if (num.TestBit(0)) { throw new Arm64UndefinedInstructionException("Advanced SIMD (scalar): Unallocated"); } return ShiftByImmediate(instruction); } return ScalarXIndexedElement(instruction); } if (num2 == 15) { if (!num3.TestPattern(387, 2)) { throw new Arm64UndefinedInstructionException("Advanced SIMD (scalar): Unallocated"); } return TwoRegisterMiscFp16(instruction); } if (num2.TestBit(2)) { if (num2.TestPattern(7, 4) && num3.TestPattern(387, 2)) { return TwoRegisterMisc(instruction); } if (num2.TestPattern(7, 6) && num3.TestPattern(387, 2)) { return Pairwise(instruction); } if (num3.TestPattern(3, 0)) { return ThreeDifferent(instruction); } if (num3.TestBit(0)) { return ThreeSame(instruction); } throw new Arm64UndefinedInstructionException($"Advanced SIMD (scalar): Unallocated x1xx family: op2 = 0x{num2:X2}, op3 = {num3:X3}"); } if (num2.TestPattern(12, 8) && num3.TestPattern(49, 1)) { return ThreeSameFp16(instruction); } if (num2.TestPattern(4, 0) && num3.TestPattern(33)) { return ThreeSameExtra(instruction); } throw new Arm64UndefinedInstructionException($"Advanced SIMD (scalar): Unallocated fall-through, op1 = 0x{num:X2}, op2 = 0x{num2:X2}, op3 = {num3:X3}"); } public static Arm64Instruction Copy(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdScalarRegisterToRegister; return result; } public static Arm64Instruction ShiftByImmediate(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath; return result; } public static Arm64Instruction ScalarXIndexedElement(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath; return result; } public static Arm64Instruction TwoRegisterMiscFp16(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; return result; } public static Arm64Instruction TwoRegisterMisc(uint instruction) { bool flag = instruction.TestBit(29); uint num = (instruction >> 22) & 3u; uint num2 = (instruction >> 12) & 0x1F; int num3 = (int)((instruction >> 5) & 0x1F); int num4 = (int)(instruction & 0x1F); bool flag2 = num.TestBit(0); Arm64Instruction result; if (num2 == 29 && !flag && (num == 0 || num == 1)) { Arm64Register arm64Register = (flag2 ? Arm64Register.D0 : Arm64Register.S0); Arm64Mnemonic mnemonic = Arm64Mnemonic.SCVTF; Arm64MnemonicCategory mnemonicCategory = Arm64MnemonicCategory.SimdScalarConversion; Arm64Register op0Reg = arm64Register + num4; Arm64Register op1Reg = arm64Register + num3; result = new Arm64Instruction(); result.Mnemonic = mnemonic; result.Op0Kind = Arm64OperandKind.Register; result.Op1Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Reg = op1Reg; result.MnemonicCategory = mnemonicCategory; return result; } result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; return result; } public static Arm64Instruction Pairwise(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath; return result; } public static Arm64Instruction ThreeDifferent(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath; return result; } public static Arm64Instruction ThreeSame(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; return result; } public static Arm64Instruction ThreeSameFp16(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.Unspecified; return result; } public static Arm64Instruction ThreeSameExtra(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath; return result; } } internal static class Arm64Simd { public static Arm64Instruction Disassemble(uint instruction) { uint num = (instruction >> 28) & 0xFu; uint num2 = (instruction >> 23) & 3u; uint num3 = (instruction >> 19) & 0xFu; uint num4 = (instruction >> 10) & 0x1FFu; uint num5 = num2 >> 1; switch (num) { case 4u: if (num5 == 0 && num3.TestPattern(7, 5) && num4.TestPattern(387, 2)) { return CryptoAes(instruction); } break; case 5u: if (num5 == 0 && num3.TestPattern(7, 5) && num4.TestPattern(387, 2)) { return CryptoTwoRegSha(instruction); } if (num5 == 0 && num3.TestPattern(4, 0) && num4.TestPattern(35, 0)) { return CryptoThreeRegSha(instruction); } goto case 7u; case 7u: if (num2 == 0 && num3.TestPattern(12, 0) && num4.TestPattern(33, 1)) { return AdvancedSimdScalarCopy(instruction); } break; } if (num.TestPattern(9, 0)) { return Arm64NonScalarAdvancedSimd.Disassemble(instruction); } if (num.TestPattern(13, 5)) { return Arm64ScalarAdvancedSimd.Disassemble(instruction); } if (num == 12) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdCryptographic; return result; } if (num.TestPattern(5, 1)) { if (num2.TestBit(1)) { return Arm64FloatingPoint.DataProcessingThreeSource(instruction); } if (!num3.TestBit(2)) { return Arm64FloatingPoint.ConversionToAndFromFixedPoint(instruction); } if ((num4 & 0x3F) == 0) { return Arm64FloatingPoint.ConversionToAndFromInteger(instruction); } if ((num4 & 0x1F) == 16) { return Arm64FloatingPoint.DataProcessingOneSource(instruction); } if ((num4 & 0xF) == 8) { return Arm64FloatingPoint.Compare(instruction); } if ((num4 & 7) == 4) { return Arm64FloatingPoint.Immediate(instruction); } return (num4 & 3) switch { 1u => Arm64FloatingPoint.ConditionalCompare(instruction), 2u => Arm64FloatingPoint.DataProcessingTwoSource(instruction), 3u => Arm64FloatingPoint.ConditionalSelect(instruction), _ => throw new Exception("Impossible op3"), }; } throw new Arm64UndefinedInstructionException($"Unimplemented SIMD instruction. Op0: {num}, Op1: {num2}, Op2: {num3}, Op3: {num4}"); } private static Arm64Instruction CryptoAes(uint instruction) { uint num = (instruction >> 22) & 3; uint num2 = (instruction >> 12) & 0x1Fu; if (num != 0) { throw new Arm64UndefinedInstructionException("AES instruction with size != 0"); } if (num2.TestBit(3) || instruction.TestBit(4) || instruction >> 2 == 0) { throw new Arm64UndefinedInstructionException($"AES: Reserved opcode 0x{num2:X}"); } Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdCryptographic; return result; } private static Arm64Instruction CryptoTwoRegSha(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdCryptographic; return result; } private static Arm64Instruction CryptoThreeRegSha(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdCryptographic; return result; } internal static Arm64Instruction LoadStoreSingleStructure(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdStructureLoadOrStore; return result; } internal static Arm64Instruction LoadStoreSingleStructurePostIndexed(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.SimdStructureLoadOrStore; return result; } public static Arm64Instruction AdvancedSimdScalarCopy(uint instruction) { bool flag = instruction.TestBit(29); uint num = (instruction >> 16) & 0x1Fu; uint num2 = (instruction >> 11) & 0xF; int num3 = (int)((instruction >> 5) & 0x1F); int num4 = (int)(instruction & 0x1F); if (flag) { throw new Arm64UndefinedInstructionException("Advanced SIMD: scalar copy: op flag is reserved"); } if (num2 != 0) { throw new Arm64UndefinedInstructionException("Advanced SIMD: scalar copy: all bits of imm4 are reserved"); } int num5; if (!num.TestBit(0)) { if (!num.TestBit(1)) { if (!num.TestBit(2)) { if (!num.TestBit(3)) { throw new Arm64UndefinedInstructionException("Advanced SIMD: scalar copy: high bit of imm5 is reserved"); } num5 = 97; } else { num5 = 129; } } else { num5 = 161; } } else { num5 = 193; } Arm64Register arm64Register = (Arm64Register)num5; Arm64Register op0Reg = arm64Register + num4; Arm64Register op1Reg = (Arm64Register)(65 + num3); Arm64VectorElementWidth arm64VectorElementWidth = arm64Register switch { Arm64Register.B0 => Arm64VectorElementWidth.B, Arm64Register.H0 => Arm64VectorElementWidth.H, Arm64Register.S0 => Arm64VectorElementWidth.S, Arm64Register.D0 => Arm64VectorElementWidth.D, _ => throw new Exception("Impossible baseDestReg"), }; uint index = arm64VectorElementWidth switch { Arm64VectorElementWidth.B => num >> 1, Arm64VectorElementWidth.H => num >> 2, Arm64VectorElementWidth.S => num >> 3, Arm64VectorElementWidth.D => num >> 4, _ => throw new Exception("Impossible srcVectorElementWidth"), }; Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.DUP; result.Op0Kind = Arm64OperandKind.Register; result.Op0Reg = op0Reg; result.Op1Kind = Arm64OperandKind.VectorRegisterElement; result.Op1Reg = op1Reg; result.Op1VectorElement = new Arm64VectorElement(arm64VectorElementWidth, (int)index); result.MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister; return result; } } internal static class Arm64Sve { public static Arm64Instruction Disassemble(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.ScalableVectorExtension; return result; } } internal static class Arm64System { public static Arm64Instruction WithResult(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.System; return result; } public static Arm64Instruction General(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.System; return result; } public static Arm64Instruction RegisterMove(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.System; return result; } public static Arm64Instruction WithRegisterArgument(uint instruction) { Arm64Instruction result = new Arm64Instruction(); result.Mnemonic = Arm64Mnemonic.UNIMPLEMENTED; result.MnemonicCategory = Arm64MnemonicCategory.System; return result; } } internal static class DisassembleExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TestBit(this uint instruction, int bit) { return (instruction & (uint)(1 << bit)) != 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TestPattern(this uint original, int maskAndPattern) { return (original & maskAndPattern) == maskAndPattern; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TestPattern(this uint original, int mask, int pattern) { return (original & mask) == pattern; } } internal enum MemoryAccessMode { PreIndex, PostIndex, Offset } }