From 95dca6f5215a34f4a8e865cc5586e76a7a2fecac Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Wed, 30 Apr 2025 11:08:35 +0800 Subject: [PATCH 01/28] fix when STR LDR V0 Register this immediate must << 4 ins : E0 0B 80 3D ==> str q0, [sp, #0x20] --- Disarm/InternalDisassembly/Arm64LoadsStores.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Disarm/InternalDisassembly/Arm64LoadsStores.cs b/Disarm/InternalDisassembly/Arm64LoadsStores.cs index 80a2e43..008f315 100644 --- a/Disarm/InternalDisassembly/Arm64LoadsStores.cs +++ b/Disarm/InternalDisassembly/Arm64LoadsStores.cs @@ -702,6 +702,7 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) mnemonic = opc == 0b10 ? Arm64Mnemonic.STR : Arm64Mnemonic.LDR; baseReg = Arm64Register.V0; //128-bit variant + immediate <<= 4; } else { From d9591efdd7d75c0e9c1e7a3e0ac19af4da49bad1 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Thu, 8 May 2025 18:09:52 +0800 Subject: [PATCH 02/28] fix movz when shift is not zero and this result is int64 , it can change to MOV like IDA --- .../Arm64DataProcessingImmediate.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs b/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs index c7ed1a6..5f1aa15 100644 --- a/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs +++ b/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs @@ -206,16 +206,24 @@ public static Arm64Instruction MoveWideImmediate(uint instruction) var regD = baseReg + rd; var shift = (int) hw * 16; - - imm16 <<= shift; - + + long immValue = (long)imm16 << shift; + + // If the instruction is 32-bit, we need to mask the immediate value to 32 bits + if (!is64Bit) + immValue &= 0xFFFFFFFF; + if (mnemonic==Arm64Mnemonic.MOVZ) + { + mnemonic = Arm64Mnemonic.MOV; + } + return new() { Mnemonic = mnemonic, Op0Kind = Arm64OperandKind.Register, Op1Kind = Arm64OperandKind.Immediate, Op0Reg = regD, - Op1Imm = imm16, + Op1Imm = immValue, MnemonicCategory = Arm64MnemonicCategory.Move, }; } From 336dab3c25f769fd183adcc1926df4766931e4f9 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Thu, 15 May 2025 17:38:06 +0800 Subject: [PATCH 03/28] fix FCVT --- .../InternalDisassembly/Arm64FloatingPoint.cs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Disarm/InternalDisassembly/Arm64FloatingPoint.cs b/Disarm/InternalDisassembly/Arm64FloatingPoint.cs index 8f2ffcd..000c92e 100644 --- a/Disarm/InternalDisassembly/Arm64FloatingPoint.cs +++ b/Disarm/InternalDisassembly/Arm64FloatingPoint.cs @@ -240,7 +240,32 @@ public static Arm64Instruction DataProcessingOneSource(uint instruction) var regD = baseReg + rd; var regN = baseReg + rn; - +// Fix FCVT + if (mnemonic == Arm64Mnemonic.FCVT) + { + if (opcode == 0b000101) // FCVT D/S + { + + regD = ptype switch + { + 0b00 => Arm64Register.D0 + rd, // S => D + 0b01 => Arm64Register.S0 + rd, // D => S + 0b11 => Arm64Register.S0 + rd, // H => S + _ => throw new("Impossible ptype") + }; + } + else if (opcode == 0b000111) // FCVT H/D + { + + regD = ptype switch + { + 0b00 => Arm64Register.H0 + rd, // S => H + 0b01 => Arm64Register.H0 + rd, // D => H + 0b11 => Arm64Register.D0 + rd, // H => D + _ => throw new("Impossible ptype") + }; + } + } return new() { Mnemonic = mnemonic, From 63356b9aaeb6e7d207a1f6e54f73a14c39f10c09 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Thu, 29 May 2025 20:45:50 +0800 Subject: [PATCH 04/28] fix E8 07 45 FC LDR D8, [SP+0x50+var_50],#0x50 parser error registername --- Disarm/InternalDisassembly/Arm64LoadsStores.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64LoadsStores.cs b/Disarm/InternalDisassembly/Arm64LoadsStores.cs index 008f315..a961ec3 100644 --- a/Disarm/InternalDisassembly/Arm64LoadsStores.cs +++ b/Disarm/InternalDisassembly/Arm64LoadsStores.cs @@ -441,7 +441,8 @@ private static Arm64Instruction LoadStoreRegisterFromImm(uint instruction, Arm64 var baseReg = mnemonic switch { - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0 => size switch + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0b10 or 0b11 && size == 0 => Arm64Register.V0, //128-bit vector for opc 10/11 with size 00 + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => size switch { 0 => Arm64Register.B0, 1 => Arm64Register.H0, @@ -449,7 +450,6 @@ private static Arm64Instruction LoadStoreRegisterFromImm(uint instruction, Arm64 3 => Arm64Register.D0, _ => throw new("Impossible size") }, - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => Arm64Register.V0, //128-bit vector Arm64Mnemonic.STRB or Arm64Mnemonic.LDRB or Arm64Mnemonic.STRH or Arm64Mnemonic.LDRH => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when size is 0b10 => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR => Arm64Register.X0, @@ -674,7 +674,7 @@ private static Arm64Instruction LoadStoreRegisterPair(uint instruction, Arm64Mem }; } - private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) + private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) { var size = (instruction >> 30) & 0b11; //Bits 30-31 var isVector = instruction.TestBit(26); @@ -702,7 +702,6 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) mnemonic = opc == 0b10 ? Arm64Mnemonic.STR : Arm64Mnemonic.LDR; baseReg = Arm64Register.V0; //128-bit variant - immediate <<= 4; } else { @@ -865,7 +864,8 @@ private static Arm64Instruction LoadStoreRegisterFromRegisterOffset(uint instruc var baseReg = mnemonic switch { - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0 => size switch + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0b10 or 0b11 && size == 0 => Arm64Register.V0, //128-bit vector for opc 10/11 with size 00 + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => size switch { 0 => Arm64Register.B0, 1 => Arm64Register.H0, @@ -873,7 +873,6 @@ private static Arm64Instruction LoadStoreRegisterFromRegisterOffset(uint instruc 3 => Arm64Register.D0, _ => throw new("Impossible size") }, - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => Arm64Register.V0, //128-bit vector Arm64Mnemonic.STRB or Arm64Mnemonic.LDRB or Arm64Mnemonic.STRH or Arm64Mnemonic.LDRH => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when size is 0b10 => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR => Arm64Register.X0, From 3488c8122bdd8351765dc6c8519093b631515eb2 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Thu, 29 May 2025 21:50:21 +0800 Subject: [PATCH 05/28] rollback --- Disarm/InternalDisassembly/Arm64LoadsStores.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64LoadsStores.cs b/Disarm/InternalDisassembly/Arm64LoadsStores.cs index a961ec3..008f315 100644 --- a/Disarm/InternalDisassembly/Arm64LoadsStores.cs +++ b/Disarm/InternalDisassembly/Arm64LoadsStores.cs @@ -441,8 +441,7 @@ private static Arm64Instruction LoadStoreRegisterFromImm(uint instruction, Arm64 var baseReg = mnemonic switch { - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0b10 or 0b11 && size == 0 => Arm64Register.V0, //128-bit vector for opc 10/11 with size 00 - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => size switch + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0 => size switch { 0 => Arm64Register.B0, 1 => Arm64Register.H0, @@ -450,6 +449,7 @@ private static Arm64Instruction LoadStoreRegisterFromImm(uint instruction, Arm64 3 => Arm64Register.D0, _ => throw new("Impossible size") }, + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => Arm64Register.V0, //128-bit vector Arm64Mnemonic.STRB or Arm64Mnemonic.LDRB or Arm64Mnemonic.STRH or Arm64Mnemonic.LDRH => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when size is 0b10 => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR => Arm64Register.X0, @@ -674,7 +674,7 @@ private static Arm64Instruction LoadStoreRegisterPair(uint instruction, Arm64Mem }; } - private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) + private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) { var size = (instruction >> 30) & 0b11; //Bits 30-31 var isVector = instruction.TestBit(26); @@ -702,6 +702,7 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction) mnemonic = opc == 0b10 ? Arm64Mnemonic.STR : Arm64Mnemonic.LDR; baseReg = Arm64Register.V0; //128-bit variant + immediate <<= 4; } else { @@ -864,8 +865,7 @@ private static Arm64Instruction LoadStoreRegisterFromRegisterOffset(uint instruc var baseReg = mnemonic switch { - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0b10 or 0b11 && size == 0 => Arm64Register.V0, //128-bit vector for opc 10/11 with size 00 - Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => size switch + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0 => size switch { 0 => Arm64Register.B0, 1 => Arm64Register.H0, @@ -873,6 +873,7 @@ private static Arm64Instruction LoadStoreRegisterFromRegisterOffset(uint instruc 3 => Arm64Register.D0, _ => throw new("Impossible size") }, + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => Arm64Register.V0, //128-bit vector Arm64Mnemonic.STRB or Arm64Mnemonic.LDRB or Arm64Mnemonic.STRH or Arm64Mnemonic.LDRH => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when size is 0b10 => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR => Arm64Register.X0, From b6a443135d3b630672b4a14522e873091de5a2c7 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Thu, 29 May 2025 23:23:37 +0800 Subject: [PATCH 06/28] bug fix --- Disarm/InternalDisassembly/Arm64LoadsStores.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64LoadsStores.cs b/Disarm/InternalDisassembly/Arm64LoadsStores.cs index 008f315..647e8ea 100644 --- a/Disarm/InternalDisassembly/Arm64LoadsStores.cs +++ b/Disarm/InternalDisassembly/Arm64LoadsStores.cs @@ -449,6 +449,14 @@ private static Arm64Instruction LoadStoreRegisterFromImm(uint instruction, Arm64 3 => Arm64Register.D0, _ => throw new("Impossible size") }, + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 1 => size switch + { + 0 => Arm64Register.B0, + 1 => Arm64Register.H0, + 2 => Arm64Register.S0, + 3 => Arm64Register.D0, + _ => throw new("Impossible size") + }, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => Arm64Register.V0, //128-bit vector Arm64Mnemonic.STRB or Arm64Mnemonic.LDRB or Arm64Mnemonic.STRH or Arm64Mnemonic.LDRH => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when size is 0b10 => Arm64Register.W0, From 093ccea78e155bc89625456b11377425f69468c5 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Tue, 3 Jun 2025 15:03:35 +0800 Subject: [PATCH 07/28] fix D0 parser v0 --- Disarm/InternalDisassembly/Arm64LoadsStores.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64LoadsStores.cs b/Disarm/InternalDisassembly/Arm64LoadsStores.cs index 647e8ea..b4ba453 100644 --- a/Disarm/InternalDisassembly/Arm64LoadsStores.cs +++ b/Disarm/InternalDisassembly/Arm64LoadsStores.cs @@ -1002,6 +1002,14 @@ private static Arm64Instruction LoadStoreRegisterFromImmUnscaled(uint instructio 3 => Arm64Register.D0, _ => throw new("Impossible size") }, + Arm64Mnemonic.STUR or Arm64Mnemonic.LDUR when isVector && opc is 1 => size switch + { + 0 => Arm64Register.B0, + 1 => Arm64Register.H0, + 2 => Arm64Register.S0, + 3 => Arm64Register.D0, + _ => throw new("Impossible size") + }, Arm64Mnemonic.STUR or Arm64Mnemonic.LDUR when isVector => Arm64Register.V0, //128-bit vector Arm64Mnemonic.STURB or Arm64Mnemonic.LDURB or Arm64Mnemonic.STURH or Arm64Mnemonic.LDURH => Arm64Register.W0, Arm64Mnemonic.STUR or Arm64Mnemonic.LDUR when size is 0b10 => Arm64Register.W0, From 723623d541f28a07ce3b1798624fb06c2b46d0c3 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Mon, 9 Jun 2025 18:13:35 +0800 Subject: [PATCH 08/28] =?UTF-8?q?fix=20MOVK=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Disarm/Arm64Instruction.cs | 14 ++++----- .../Arm64DataProcessingImmediate.cs | 29 +++++++++++++++---- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Disarm/Arm64Instruction.cs b/Disarm/Arm64Instruction.cs index efb0b01..8eb029c 100644 --- a/Disarm/Arm64Instruction.cs +++ b/Disarm/Arm64Instruction.cs @@ -147,13 +147,13 @@ public override string ToString() sb.Append(' '); //Ew yes I'm using goto. - if (!AppendOperand(sb, Op0Kind, Op0Reg, Op0VectorElement, Op0Arrangement, Op1ShiftType, Op0Imm, Op0FpImm)) + if (!AppendOperand(sb, Op0Kind, Op0Reg, Op0VectorElement, Op0Arrangement, Op0ShiftType, Op0Imm, Op0FpImm, false, MemExtendOrShiftAmount)) goto doneops; - if (!AppendOperand(sb, Op1Kind, Op1Reg, Op1VectorElement, Op1Arrangement, Op1ShiftType, Op1Imm, Op1FpImm, true)) + if (!AppendOperand(sb, Op1Kind, Op1Reg, Op1VectorElement, Op1Arrangement, Op1ShiftType, Op1Imm, Op1FpImm, true, MemExtendOrShiftAmount)) goto doneops; - if (!AppendOperand(sb, Op2Kind, Op2Reg, Op2VectorElement, Op2Arrangement, Op1ShiftType, Op2Imm, Op2FpImm, true)) + if (!AppendOperand(sb, Op2Kind, Op2Reg, Op2VectorElement, Op2Arrangement, Op2ShiftType, Op2Imm, Op2FpImm, true, MemExtendOrShiftAmount)) goto doneops; - if (!AppendOperand(sb, Op3Kind, Op3Reg, Op3VectorElement, Op3Arrangement, Op1ShiftType, Op3Imm, Op3FpImm, true)) + if (!AppendOperand(sb, Op3Kind, Op3Reg, Op3VectorElement, Op3Arrangement, Op3ShiftType, Op3Imm, Op3FpImm, true, MemExtendOrShiftAmount)) goto doneops; doneops: @@ -167,7 +167,7 @@ public override string ToString() return sb.ToString(); } - private bool AppendOperand(StringBuilder sb, Arm64OperandKind kind, Arm64Register reg, Arm64VectorElement vectorElement, Arm64ArrangementSpecifier regArrangement, Arm64ShiftType shiftType, long imm, double fpImm, bool comma = false) + private bool AppendOperand(StringBuilder sb, Arm64OperandKind kind, Arm64Register reg, Arm64VectorElement vectorElement, Arm64ArrangementSpecifier regArrangement, Arm64ShiftType shiftType, long imm, double fpImm, bool comma = false, int shiftAmount = 0) { if (kind == Arm64OperandKind.None) return false; @@ -189,9 +189,9 @@ private bool AppendOperand(StringBuilder sb, Arm64OperandKind kind, Arm64Registe } else if (kind == Arm64OperandKind.Immediate) { + sb.Append("#0x").Append(imm.ToString("X")); if (shiftType != Arm64ShiftType.NONE) - sb.Append(shiftType).Append(' '); - sb.Append("0x").Append(imm.ToString("X")); + sb.Append(",").Append(shiftType).Append("#").Append(shiftAmount); } else if (kind == Arm64OperandKind.FloatingPointImmediate) { sb.Append(fpImm.ToString(CultureInfo.InvariantCulture)); diff --git a/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs b/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs index 5f1aa15..2c06c4d 100644 --- a/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs +++ b/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs @@ -207,11 +207,28 @@ public static Arm64Instruction MoveWideImmediate(uint instruction) var regD = baseReg + rd; var shift = (int) hw * 16; - long immValue = (long)imm16 << shift; - - // If the instruction is 32-bit, we need to mask the immediate value to 32 bits - if (!is64Bit) - immValue &= 0xFFFFFFFF; + // For MOVK, we store the original immediate and shift info + // For other instructions, we calculate the shifted value + long immValue; + Arm64ShiftType shiftType = Arm64ShiftType.NONE; + int shiftAmount = 0; + + if (mnemonic == Arm64Mnemonic.MOVK && shift > 0) + { + // For MOVK, store the original 16-bit immediate + immValue = (long)imm16; + shiftType = Arm64ShiftType.LSL; + shiftAmount = shift; + } + else + { + // For MOVN and MOVZ, calculate the shifted value + immValue = (long)imm16 << shift; + // If the instruction is 32-bit, we need to mask the immediate value to 32 bits + if (!is64Bit) + immValue &= 0xFFFFFFFF; + } + if (mnemonic==Arm64Mnemonic.MOVZ) { mnemonic = Arm64Mnemonic.MOV; @@ -224,6 +241,8 @@ public static Arm64Instruction MoveWideImmediate(uint instruction) Op1Kind = Arm64OperandKind.Immediate, Op0Reg = regD, Op1Imm = immValue, + Op1ShiftType = shiftType, + MemExtendOrShiftAmount = shiftAmount, MnemonicCategory = Arm64MnemonicCategory.Move, }; } From 6f852a119cbcba4ad1b57092fcb229cdc5efffe1 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Fri, 13 Jun 2025 09:25:22 +0800 Subject: [PATCH 09/28] support fcvt --- Disarm/InternalDisassembly/Arm64FloatingPoint.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64FloatingPoint.cs b/Disarm/InternalDisassembly/Arm64FloatingPoint.cs index 000c92e..170ab8b 100644 --- a/Disarm/InternalDisassembly/Arm64FloatingPoint.cs +++ b/Disarm/InternalDisassembly/Arm64FloatingPoint.cs @@ -45,6 +45,7 @@ internal static Arm64Instruction ConversionToAndFromFixedPoint(uint instruction) 0b001 => Arm64Mnemonic.FCVTZU, 0b010 => Arm64Mnemonic.SCVTF, 0b011 => Arm64Mnemonic.UCVTF, + 0b000100 => Arm64Mnemonic.FCVT, _ => throw new("Impossible opcode") }; @@ -205,7 +206,7 @@ public static Arm64Instruction DataProcessingOneSource(uint instruction) 0b000001 => Arm64Mnemonic.FABS, 0b000010 => Arm64Mnemonic.FNEG, 0b000011 => Arm64Mnemonic.FSQRT, - 0b000100 => throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): opcode 0b000100 is reserved"), + 0b000100 => Arm64Mnemonic.FCVT, 0b000101 => Arm64Mnemonic.FCVT, 0b000110 => throw new Arm64UndefinedInstructionException("Floating-point data-processing (1 source): opcode 0b000110 is reserved"), 0b000111 => Arm64Mnemonic.FCVT, @@ -243,7 +244,17 @@ public static Arm64Instruction DataProcessingOneSource(uint instruction) // Fix FCVT if (mnemonic == Arm64Mnemonic.FCVT) { - if (opcode == 0b000101) // FCVT D/S + if (opcode == 0b000100) // FCVT additional variant + { + regD = ptype switch + { + 0b00 => Arm64Register.H0 + rd, // S => H + 0b01 => Arm64Register.S0 + rd, // D => S + 0b11 => Arm64Register.S0 + rd, // H => S + _ => throw new("Impossible ptype") + }; + } + else if (opcode == 0b000101) // FCVT D/S { regD = ptype switch From d875ce3a8f34ca68d84a0e62edd1af6e1ecf030a Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Fri, 13 Jun 2025 18:03:04 +0800 Subject: [PATCH 10/28] fix s0 parser error to v0 --- Disarm/InternalDisassembly/Arm64LoadsStores.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64LoadsStores.cs b/Disarm/InternalDisassembly/Arm64LoadsStores.cs index b4ba453..7773f1a 100644 --- a/Disarm/InternalDisassembly/Arm64LoadsStores.cs +++ b/Disarm/InternalDisassembly/Arm64LoadsStores.cs @@ -881,6 +881,14 @@ private static Arm64Instruction LoadStoreRegisterFromRegisterOffset(uint instruc 3 => Arm64Register.D0, _ => throw new("Impossible size") }, + Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 1 => size switch + { + 0 => Arm64Register.B0, + 1 => Arm64Register.H0, + 2 => Arm64Register.S0, + 3 => Arm64Register.D0, + _ => throw new("Impossible size") + }, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => Arm64Register.V0, //128-bit vector Arm64Mnemonic.STRB or Arm64Mnemonic.LDRB or Arm64Mnemonic.STRH or Arm64Mnemonic.LDRH => Arm64Register.W0, Arm64Mnemonic.STR or Arm64Mnemonic.LDR when size is 0b10 => Arm64Register.W0, From 6df0faac8f8830ded552ab18574edaab4aae69f0 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Sat, 14 Jun 2025 15:48:58 +0800 Subject: [PATCH 11/28] support more ins --- .../Arm64NonScalarAdvancedSimd.cs | 153 +++++++++++++++++- 1 file changed, 150 insertions(+), 3 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index 6e1d7bb..73cf23e 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -14,7 +14,7 @@ public static Arm64Instruction Disassemble(uint instruction) var op3Lo = (op3 & 1) == 1; if (op1 == 0b11) - throw new Arm64UndefinedInstructionException("Advanced SIMD instruction with op1 == 11"); + return AdvancedSimdVectorXIndexedElement(instruction); //Handle the couple of cases where op1 is not simply 0b0x if (op1 == 0b10) @@ -234,11 +234,158 @@ private static Arm64Instruction AdvancedSimdShiftByImmediate(uint instruction) private static Arm64Instruction AdvancedSimdVectorXIndexedElement(uint instruction) { - return new() + var q = instruction.TestBit(30); // Bit 30 + var u = instruction.TestBit(29); // Bit 29 + var size = (instruction >> 22) & 0b11; // Bits 22-23 + var l = instruction.TestBit(21); // Bit 21 + var m = instruction.TestBit(20); // Bit 20 + var rm = (int)(instruction >> 16) & 0b1111; // Bits 16-19 + var opcode = (instruction >> 12) & 0b1111; // Bits 12-15 + var h = instruction.TestBit(11); // Bit 11 + var rn = (int)(instruction >> 5) & 0b1_1111; // Bits 5-9 + var rd = (int)instruction & 0b1_1111; // Bits 0-4 + + // Determine mnemonic based on U and opcode + Arm64Mnemonic mnemonic; + if (u) { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, + mnemonic = opcode switch + { + 0b1001 when size != 0b01 => Arm64Mnemonic.FMULX, + 0b0010 => Arm64Mnemonic.UMLAL, + 0b0110 => Arm64Mnemonic.UMLSL, + 0b1010 => Arm64Mnemonic.UMULL, + 0b1101 => Arm64Mnemonic.SQRDMLAH, + 0b1111 => Arm64Mnemonic.SQRDMLSH, + _ => throw new Arm64UndefinedInstructionException("AdvancedSimdVectorXIndexedElement: Unallocated U=1 opcode") + }; + } + else + { + mnemonic = opcode switch + { + 0b0001 when size != 0b01 => Arm64Mnemonic.FMLA, + 0b0101 when size != 0b01 => Arm64Mnemonic.FMLS, + 0b1001 when size != 0b01 => Arm64Mnemonic.FMUL, + 0b0010 => Arm64Mnemonic.SMLAL, + 0b0110 => Arm64Mnemonic.SMLSL, + 0b1010 => Arm64Mnemonic.SMULL, + 0b0011 => Arm64Mnemonic.SQDMLAL, + 0b0111 => Arm64Mnemonic.SQDMLSL, + 0b1011 => Arm64Mnemonic.SQDMULL, + 0b1100 => Arm64Mnemonic.SQDMULH, + 0b1101 => Arm64Mnemonic.SQRDMULH, + _ => throw new Arm64UndefinedInstructionException("AdvancedSimdVectorXIndexedElement: Unallocated U=0 opcode") + }; + } + + var result = new Arm64Instruction() + { + Mnemonic = mnemonic, MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath, + Op0Kind = Arm64OperandKind.Register, + Op1Kind = Arm64OperandKind.Register, + Op2Kind = Arm64OperandKind.VectorRegisterElement, }; + + // Set up operands based on instruction type + if (mnemonic is Arm64Mnemonic.FMLA or Arm64Mnemonic.FMLS or Arm64Mnemonic.FMUL or Arm64Mnemonic.FMULX) + { + // Floating-point instructions + var arrangement = size switch + { + 0b00 => q ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH, // FP16 + 0b10 => q ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS, // Single + 0b11 => q ? Arm64ArrangementSpecifier.TwoD : throw new Arm64UndefinedInstructionException("Reserved"), // Double + _ => throw new Arm64UndefinedInstructionException("Reserved size for FP") + }; + + var elementWidth = size switch + { + 0b00 => Arm64VectorElementWidth.H, + 0b10 => Arm64VectorElementWidth.S, + 0b11 => Arm64VectorElementWidth.D, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + + var elementIndex = size switch + { + 0b00 => (h ? 4 : 0) | (l ? 2 : 0) | (m ? 1 : 0), // H:L:M for FP16 + 0b10 => (h ? 2 : 0) | (l ? 1 : 0), // H:L for Single + 0b11 => h ? 1 : 0, // H for Double + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + + result = result with + { + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = arrangement, + Op1Reg = Arm64Register.V0 + rn, + Op1Arrangement = arrangement, + Op2Reg = Arm64Register.V0 + (rm | (m ? 16 : 0)), + Op2VectorElement = new Arm64VectorElement(elementWidth, elementIndex) + }; + } + else + { + // Integer instructions - these have different source and destination arrangements + var srcArrangement = size switch + { + 0b01 => q ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH, + 0b10 => q ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS, + _ => throw new Arm64UndefinedInstructionException("Reserved size for integer") + }; + + var dstArrangement = size switch + { + 0b01 => q ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS, + 0b10 => q ? Arm64ArrangementSpecifier.TwoD : Arm64ArrangementSpecifier.None, + _ => throw new Arm64UndefinedInstructionException("Reserved size for integer") + }; + + var elementWidth = size switch + { + 0b01 => Arm64VectorElementWidth.H, + 0b10 => Arm64VectorElementWidth.S, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + + var elementIndex = size switch + { + 0b01 => (h ? 4 : 0) | (l ? 2 : 0) | (m ? 1 : 0), // H:L:M for 16-bit + 0b10 => (h ? 2 : 0) | (l ? 1 : 0), // H:L for 32-bit + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + + // For SQDMULH and SQRDMULH, source and destination have same arrangement + if (mnemonic is Arm64Mnemonic.SQDMULH or Arm64Mnemonic.SQRDMULH or Arm64Mnemonic.SQRDMLAH or Arm64Mnemonic.SQRDMLSH) + { + result = result with + { + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = srcArrangement, + Op1Reg = Arm64Register.V0 + rn, + Op1Arrangement = srcArrangement, + Op2Reg = Arm64Register.V0 + (rm | (m ? 16 : 0)), + Op2VectorElement = new Arm64VectorElement(elementWidth, elementIndex) + }; + } + else + { + // For other integer instructions, destination is wider + result = result with + { + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = dstArrangement, + Op1Reg = Arm64Register.V0 + rn, + Op1Arrangement = srcArrangement, + Op2Reg = Arm64Register.V0 + (rm | (m ? 16 : 0)), + Op2VectorElement = new Arm64VectorElement(elementWidth, elementIndex) + }; + } + } + + return result; } private static Arm64Instruction AdvancedSimdCopy(uint instruction) From 72a9e18095909269593bf6fec6c91e94b71fe567 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Sat, 14 Jun 2025 16:03:44 +0800 Subject: [PATCH 12/28] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Arm64NonScalarAdvancedSimd.cs | 67 +++++++++++++++---- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index 73cf23e..f9dd203 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -51,7 +51,7 @@ public static Arm64Instruction Disassemble(uint instruction) if (op2 == 0b1111 && (op3 & 0b1_1000_0011) == 0b10) return AdvancedSimdTwoRegisterMiscFp16(instruction); - if ((op2UpperHalf & 1) == 0 && (op3 * 0b100001) == 0b100001) + if ((op2UpperHalf & 1) == 0 && (op3 & 0b100001) == 0b100001) return AdvancedSimdThreeRegExtension(instruction); if (op2 is 0b0100 or 0b1100 && (op3 & 0b110000011) == 0b10) @@ -658,7 +658,51 @@ private static Arm64Instruction AdvancedSimdThreeSame(uint instruction) if (u) mnemonic = opcode switch { - _ => throw new NotImplementedException() + 0b00000 => Arm64Mnemonic.UHADD, + 0b00001 => Arm64Mnemonic.UQADD, + 0b00010 => Arm64Mnemonic.URHADD, + 0b00011 when size is 0b00 => Arm64Mnemonic.EOR, + 0b00011 when size is 0b01 => Arm64Mnemonic.BSL, + 0b00011 when size is 0b10 => Arm64Mnemonic.BIT, + 0b00011 when size is 0b11 => Arm64Mnemonic.BIF, + 0b00100 => Arm64Mnemonic.UHSUB, + 0b00101 => Arm64Mnemonic.UQSUB, + 0b00110 => Arm64Mnemonic.CMHI, + 0b00111 => Arm64Mnemonic.CMHS, + 0b01000 => Arm64Mnemonic.USHL, + 0b01001 => Arm64Mnemonic.UQSHL, + 0b01010 => Arm64Mnemonic.URSHL, + 0b01011 => Arm64Mnemonic.UQRSHL, + 0b01100 => Arm64Mnemonic.UMAX, + 0b01101 => Arm64Mnemonic.UMIN, + 0b01110 => Arm64Mnemonic.UABD, + 0b01111 => Arm64Mnemonic.UABA, + 0b10000 => Arm64Mnemonic.SUB, + 0b10001 => Arm64Mnemonic.CMEQ, + 0b10010 => Arm64Mnemonic.MLS, + 0b10011 => Arm64Mnemonic.PMUL, + 0b10100 => Arm64Mnemonic.UMAXP, + 0b10101 => Arm64Mnemonic.UMINP, + 0b10110 => Arm64Mnemonic.SQRDMULH, + 0b10111 when size is 0b00 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b10111, size=0b00"), + 0b10111 when size is 0b01 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b10111, size=0b01"), + 0b10111 when size is 0b10 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b10111, size=0b10"), + 0b10111 when size is 0b11 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b10111, size=0b11"), + 0b11000 when !sizeHi => Arm64Mnemonic.FMAXNMP, + 0b11000 => Arm64Mnemonic.FMINNMP, + 0b11001 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b11001"), + 0b11010 when !sizeHi => Arm64Mnemonic.FADDP, + 0b11010 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b11010 with high size bit set"), + 0b11011 when !sizeHi => Arm64Mnemonic.FMUL, + 0b11011 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b11011 with high size bit set"), + 0b11100 when !sizeHi => Arm64Mnemonic.FCMGE, + 0b11100 => Arm64Mnemonic.FCMGT, + 0b11101 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b11101"), + 0b11110 when !sizeHi => Arm64Mnemonic.FMAXP, + 0b11110 => Arm64Mnemonic.FMINP, + 0b11111 when !sizeHi => Arm64Mnemonic.FDIV, + 0b11111 => throw new Arm64UndefinedInstructionException("Advanced SIMD three same: U=1, opcode=0b11111 with high size bit set"), + _ => throw new("Impossible opcode") }; else mnemonic = opcode switch @@ -713,7 +757,9 @@ private static Arm64Instruction AdvancedSimdThreeSame(uint instruction) var category = mnemonic switch { - Arm64Mnemonic.CMGT or Arm64Mnemonic.CMGE or Arm64Mnemonic.CMTST => Arm64MnemonicCategory.SimdComparison, + Arm64Mnemonic.CMGT or Arm64Mnemonic.CMGE or Arm64Mnemonic.CMTST or + Arm64Mnemonic.CMHI or Arm64Mnemonic.CMHS or Arm64Mnemonic.CMEQ or + Arm64Mnemonic.FCMEQ or Arm64Mnemonic.FCMGE or Arm64Mnemonic.FCMGT => Arm64MnemonicCategory.SimdComparison, _ => Arm64MnemonicCategory.SimdVectorMath, }; @@ -725,7 +771,8 @@ private static Arm64Instruction AdvancedSimdThreeSame(uint instruction) Arm64ArrangementSpecifier arrangement; Arm64Register baseReg; - if (mnemonic is Arm64Mnemonic.AND or Arm64Mnemonic.BIC or Arm64Mnemonic.ORR or Arm64Mnemonic.ORN) + if (mnemonic is Arm64Mnemonic.AND or Arm64Mnemonic.BIC or Arm64Mnemonic.ORR or Arm64Mnemonic.ORN or + Arm64Mnemonic.EOR or Arm64Mnemonic.BSL or Arm64Mnemonic.BIT or Arm64Mnemonic.BIF) { baseReg = Arm64Register.V0; arrangement = q ? Arm64ArrangementSpecifier.SixteenB : Arm64ArrangementSpecifier.EightB; @@ -733,15 +780,7 @@ private static Arm64Instruction AdvancedSimdThreeSame(uint instruction) else if (opcode < 0b11000) { //"Simple" instructions - baseReg = size switch - { - //TODO This logic is wrong for some instructions (e.g. SMIN), revisit - 0b00 => Arm64Register.B0, - 0b01 => Arm64Register.H0, - 0b10 => Arm64Register.S0, - 0b11 => Arm64Register.D0, - _ => throw new("Impossible size") - }; + baseReg = Arm64Register.V0; //This logic should be ok though arrangement = size switch @@ -752,6 +791,8 @@ private static Arm64Instruction AdvancedSimdThreeSame(uint instruction) 0b01 => Arm64ArrangementSpecifier.FourH, 0b10 when q => Arm64ArrangementSpecifier.FourS, 0b10 => Arm64ArrangementSpecifier.TwoS, + 0b11 when q => Arm64ArrangementSpecifier.TwoD, + 0b11 => Arm64ArrangementSpecifier.None, // Scalar D register _ => throw new("Impossible size") }; } From 7d82bda08ff8d3df64677846c7896ed74a05260c Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Sat, 14 Jun 2025 16:11:15 +0800 Subject: [PATCH 13/28] fix SIMD DUP ins --- .../Arm64NonScalarAdvancedSimd.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index f9dd203..6acfb32 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -442,6 +442,59 @@ private static Arm64Instruction AdvancedSimdCopy(uint instruction) _ => throw new Arm64UndefinedInstructionException($"AdvancedSimdCopy: imm4 0x{imm4:X} is reserved") }; + if (mnemonic == Arm64Mnemonic.DUP && imm4 == 0b0000) + { + // DUP (element) - duplicate vector element to vector or scalar + Arm64VectorElementWidth elementWidth; + uint elementIndex; + Arm64ArrangementSpecifier arrangement; + + if (imm5.TestBit(0)) + { + // 8-bit elements + elementWidth = Arm64VectorElementWidth.B; + elementIndex = imm5 >> 1; + arrangement = qFlag ? Arm64ArrangementSpecifier.SixteenB : Arm64ArrangementSpecifier.EightB; + } + else if (imm5.TestBit(1)) + { + // 16-bit elements + elementWidth = Arm64VectorElementWidth.H; + elementIndex = imm5 >> 2; + arrangement = qFlag ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH; + } + else if (imm5.TestBit(2)) + { + // 32-bit elements + elementWidth = Arm64VectorElementWidth.S; + elementIndex = imm5 >> 3; + arrangement = qFlag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS; + } + else if (imm5.TestBit(3)) + { + // 64-bit elements + elementWidth = Arm64VectorElementWidth.D; + elementIndex = imm5 >> 4; + arrangement = qFlag ? Arm64ArrangementSpecifier.TwoD : throw new Arm64UndefinedInstructionException("DUP: 64-bit scalar not supported in this context"); + } + else + { + throw new Arm64UndefinedInstructionException("DUP: invalid imm5 value"); + } + + return new() + { + Mnemonic = Arm64Mnemonic.DUP, + Op0Kind = Arm64OperandKind.Register, + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = arrangement, + Op1Kind = Arm64OperandKind.VectorRegisterElement, + Op1Reg = Arm64Register.V0 + rn, + Op1VectorElement = new Arm64VectorElement(elementWidth, (int)elementIndex), + MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister, + }; + } + return new() { Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, From cd0877f9194502053c48c3fbd6d02dccb465e3dc Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Sat, 14 Jun 2025 17:08:09 +0800 Subject: [PATCH 14/28] fix REV64 --- Disarm/Arm64Mnemonic.cs | 2 + .../Arm64NonScalarAdvancedSimd.cs | 101 +++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/Disarm/Arm64Mnemonic.cs b/Disarm/Arm64Mnemonic.cs index 4232e0a..315b425 100644 --- a/Disarm/Arm64Mnemonic.cs +++ b/Disarm/Arm64Mnemonic.cs @@ -102,6 +102,7 @@ public enum Arm64Mnemonic CLREX, CLS, CLZ, + CNT, CMN, CMP, CMPP, @@ -717,6 +718,7 @@ public enum Arm64Mnemonic WFI, WFIT, XAFLAG, + XTN, XPACD,XPACI,XPACLRI, YIELD, CMHL, diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index 6acfb32..c8a0fc8 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -558,10 +558,107 @@ private static Arm64Instruction AdvancedSimdThreeRegExtension(uint instruction) private static Arm64Instruction AdvancedSimdTwoRegisterMisc(uint instruction) { + var q = instruction.TestBit(30); + var u = instruction.TestBit(29); + var size = (instruction >> 22) & 0b11; + var opcode = (instruction >> 12) & 0b1_1111; + var rn = (int)((instruction >> 5) & 0b1_1111); + var rd = (int)(instruction & 0b1_1111); + + Arm64Mnemonic mnemonic; + + if (u) + { + mnemonic = opcode switch + { + 0b00000 when size != 0b11 => Arm64Mnemonic.REV32, + 0b00001 when size is 0b00 or 0b01 => Arm64Mnemonic.REV16, + 0b00010 => Arm64Mnemonic.UADDLP, + 0b00011 => Arm64Mnemonic.USQADD, + 0b00100 => Arm64Mnemonic.CLZ, + 0b00101 => Arm64Mnemonic.CLZ, + 0b00111 => Arm64Mnemonic.SQNEG, + 0b01000 => Arm64Mnemonic.CMGE, + 0b01001 => Arm64Mnemonic.CMLE, + 0b01010 => Arm64Mnemonic.FCMGT, + 0b01011 => Arm64Mnemonic.FCMGE, + 0b10010 => Arm64Mnemonic.SQXTUN, + 0b10100 => Arm64Mnemonic.UQXTN, + 0b10110 when size != 0b11 => Arm64Mnemonic.FCVTXN, + 0b11000 when size != 0b11 => Arm64Mnemonic.FRINTA, + 0b11001 when size != 0b11 => Arm64Mnemonic.FRINTX, + 0b11010 when size != 0b11 => Arm64Mnemonic.FCVTNU, + 0b11011 when size != 0b11 => Arm64Mnemonic.FCVTMU, + 0b11100 when size != 0b11 => Arm64Mnemonic.FCVTAU, + 0b11101 when size != 0b11 => Arm64Mnemonic.UCVTF, + 0b11111 when size != 0b11 => Arm64Mnemonic.FRSQRTE, + _ => throw new Arm64UndefinedInstructionException($"AdvancedSimdTwoRegisterMisc: U=1, opcode=0x{opcode:X}, size=0x{size:X}") + }; + } + else + { + mnemonic = opcode switch + { + 0b00000 when size != 0b11 => Arm64Mnemonic.REV64, + 0b00001 when size is 0b00 or 0b01 => Arm64Mnemonic.REV32, + 0b00010 => Arm64Mnemonic.SADDLP, + 0b00011 => Arm64Mnemonic.SUQADD, + 0b00100 => Arm64Mnemonic.CLS, + 0b00101 when size is 0b00 => Arm64Mnemonic.CNT, + 0b00101 => throw new Arm64UndefinedInstructionException($"AdvancedSimdTwoRegisterMisc: U=0, opcode=0b00101, size=0x{size:X} (CNT only valid for size=0b00)"), + 0b00110 => Arm64Mnemonic.SADALP, + 0b00111 => Arm64Mnemonic.SQABS, + 0b01000 => Arm64Mnemonic.CMGT, + 0b01001 => Arm64Mnemonic.CMEQ, + 0b01010 => Arm64Mnemonic.CMLT, + 0b01011 => Arm64Mnemonic.ABS, + 0b10010 => Arm64Mnemonic.XTN, + 0b10100 => Arm64Mnemonic.SQXTN, + 0b10110 when size != 0b11 => Arm64Mnemonic.FCVTN, + 0b10111 when size != 0b11 => Arm64Mnemonic.FCVTL, + 0b11000 when size != 0b11 => Arm64Mnemonic.FRINTN, + 0b11001 when size != 0b11 => Arm64Mnemonic.FRINTM, + 0b11010 when size != 0b11 => Arm64Mnemonic.FCVTNS, + 0b11011 when size != 0b11 => Arm64Mnemonic.FCVTMS, + 0b11100 when size != 0b11 => Arm64Mnemonic.FCVTAS, + 0b11101 when size != 0b11 => Arm64Mnemonic.SCVTF, + 0b11111 when size != 0b11 => Arm64Mnemonic.FRECPE, + _ => throw new Arm64UndefinedInstructionException($"AdvancedSimdTwoRegisterMisc: U=0, opcode=0x{opcode:X}, size=0x{size:X}") + }; + } + + // Determine arrangement based on size and q + Arm64ArrangementSpecifier arrangement = size switch + { + 0b00 when q => Arm64ArrangementSpecifier.SixteenB, + 0b00 => Arm64ArrangementSpecifier.EightB, + 0b01 when q => Arm64ArrangementSpecifier.EightH, + 0b01 => Arm64ArrangementSpecifier.FourH, + 0b10 when q => Arm64ArrangementSpecifier.FourS, + 0b10 => Arm64ArrangementSpecifier.TwoS, + 0b11 when q => Arm64ArrangementSpecifier.TwoD, + 0b11 => Arm64ArrangementSpecifier.None, // Scalar D register + _ => throw new("Impossible size") + }; + + var category = mnemonic switch + { + Arm64Mnemonic.CMGT or Arm64Mnemonic.CMEQ or Arm64Mnemonic.CMLT or + Arm64Mnemonic.CMGE or Arm64Mnemonic.CMLE or + Arm64Mnemonic.FCMGT or Arm64Mnemonic.FCMGE => Arm64MnemonicCategory.SimdComparison, + _ => Arm64MnemonicCategory.SimdVectorMath, + }; + return new() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, - MnemonicCategory = Arm64MnemonicCategory.Unspecified, //could be comparison, math, general data processing, or comparison + Mnemonic = mnemonic, + Op0Kind = Arm64OperandKind.Register, + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = arrangement, + Op1Kind = Arm64OperandKind.Register, + Op1Reg = Arm64Register.V0 + rn, + Op1Arrangement = arrangement, + MnemonicCategory = category, }; } From 742ea72a5a55f59d3b5893fd4541eaddea93ed86 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Sat, 14 Jun 2025 23:44:14 +0800 Subject: [PATCH 15/28] 1 --- Disarm/Arm64Mnemonic.cs | 6 +++ .../Arm64NonScalarAdvancedSimd.cs | 46 ++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Disarm/Arm64Mnemonic.cs b/Disarm/Arm64Mnemonic.cs index 315b425..143fa84 100644 --- a/Disarm/Arm64Mnemonic.cs +++ b/Disarm/Arm64Mnemonic.cs @@ -553,6 +553,8 @@ public enum Arm64Mnemonic TLBI, TSB_CSYNC, TST, + TRN1, + TRN2, RSUBHN, RSUBHN2, SABA, SABAL, SABAL2, @@ -713,6 +715,8 @@ public enum Arm64Mnemonic UMULL, UXTB, UXTH, + UZP1, + UZP2, WFE, WFET, WFI, @@ -721,6 +725,8 @@ public enum Arm64Mnemonic XTN, XPACD,XPACI,XPACLRI, YIELD, + ZIP1, + ZIP2, CMHL, CMHS, CMHI, diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index c8a0fc8..09ed03e 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -513,10 +513,52 @@ private static Arm64Instruction AdvancedSimdTableLookup(uint instruction) private static Arm64Instruction AdvancedSimdPermute(uint instruction) { + var q = instruction.TestBit(30); + var size = (instruction >> 22) & 0b11; + var rm = (int)(instruction >> 16) & 0b11111; + var opcode = (instruction >> 12) & 0b111; + var rn = (int)(instruction >> 5) & 0b11111; + var rd = (int)instruction & 0b11111; + + // Determine mnemonic based on opcode + Arm64Mnemonic mnemonic = opcode switch + { + 0b001 => Arm64Mnemonic.UZP1, + 0b101 => Arm64Mnemonic.TRN1, + 0b011 => Arm64Mnemonic.ZIP1, + 0b000 => Arm64Mnemonic.UZP2, + 0b100 => Arm64Mnemonic.TRN2, + 0b010 => Arm64Mnemonic.ZIP2, + _ => throw new Arm64UndefinedInstructionException($"AdvancedSimdPermute: Invalid opcode 0x{opcode:X}") + }; + + // Determine arrangement based on size and q + Arm64ArrangementSpecifier arrangement = size switch + { + 0b00 when q => Arm64ArrangementSpecifier.SixteenB, + 0b00 => Arm64ArrangementSpecifier.EightB, + 0b01 when q => Arm64ArrangementSpecifier.EightH, + 0b01 => Arm64ArrangementSpecifier.FourH, + 0b10 when q => Arm64ArrangementSpecifier.FourS, + 0b10 => Arm64ArrangementSpecifier.TwoS, + 0b11 when q => Arm64ArrangementSpecifier.TwoD, + 0b11 => throw new Arm64UndefinedInstructionException("AdvancedSimdPermute: size=11, q=0 is reserved"), + _ => throw new("Impossible size") + }; + return new() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, - MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister, + Mnemonic = mnemonic, + Op0Kind = Arm64OperandKind.Register, + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = arrangement, + Op1Kind = Arm64OperandKind.Register, + Op1Reg = Arm64Register.V0 + rn, + Op1Arrangement = arrangement, + Op2Kind = Arm64OperandKind.Register, + Op2Reg = Arm64Register.V0 + rm, + Op2Arrangement = arrangement, + MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath, }; } From 1c2721ab3090624e892fdc2aa1d2a6e6e9231cec Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Mon, 16 Jun 2025 18:12:52 +0800 Subject: [PATCH 16/28] bug fix --- Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index 09ed03e..ef39ad9 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -216,9 +216,11 @@ private static Arm64Instruction AdvancedSimdModifiedImmediate(uint instruction) Op0Arrangement = arrangement, Op1Kind = Arm64OperandKind.Immediate, Op1Imm = immediate, - Op2Kind = shiftAmount > 0 ? Arm64OperandKind.Immediate : Arm64OperandKind.None, - Op2Imm = shiftAmount, - Op2ShiftType = shiftAmount > 0 ? Arm64ShiftType.LSL : Arm64ShiftType.NONE, + Op1ShiftType = shiftAmount > 0 ? Arm64ShiftType.LSL : Arm64ShiftType.NONE, + Op2Kind = Arm64OperandKind.None, + Op2Imm = 0, + Op2ShiftType = Arm64ShiftType.NONE, + MemExtendOrShiftAmount = shiftAmount, MnemonicCategory = Arm64MnemonicCategory.SimdConstantToRegister, }; } From 0692f00a0b55464440f56a688035419fd13dda3a Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Wed, 18 Jun 2025 00:28:36 +0800 Subject: [PATCH 17/28] support more aliases --- Disarm/InternalDisassembly/Arm64Aliases.cs | 108 +++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index e608472..be255bb 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -148,5 +148,113 @@ public static void CheckForAlias(ref Arm64Instruction instruction) instruction.Mnemonic = Arm64Mnemonic.MOV; return; } + + // UBFM to LSL alias conversion + if (instruction.Mnemonic == Arm64Mnemonic.UBFM && instruction.Op2Kind == Arm64OperandKind.Immediate && instruction.Op3Kind == Arm64OperandKind.Immediate) + { + var immr = instruction.Op2Imm; + var imms = instruction.Op3Imm; + var is64Bit = instruction.Op0Reg >= Arm64Register.X0 && instruction.Op0Reg <= Arm64Register.X31; + var regWidth = is64Bit ? 64 : 32; + + // Check if this matches LSL pattern: UBFM Rd, Rn, #(-shift MOD width), #(width-1-shift) + // For LSL: immr = (-shift) MOD width, imms = (width-1-shift) + // So: shift = (width - immr) MOD width, and imms should equal (width-1-shift) + var shift = (regWidth - immr) % regWidth; + if (imms == regWidth - 1 - shift) + { + // Convert to LSL + instruction.Mnemonic = Arm64Mnemonic.LSL; + instruction.Op2Imm = shift; + instruction.Op3Kind = Arm64OperandKind.None; + instruction.Op3Imm = 0; + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + + // Check if this matches LSR pattern: UBFM Rd, Rn, #shift, #(width-1) + if (imms == regWidth - 1) + { + // Convert to LSR + instruction.Mnemonic = Arm64Mnemonic.LSR; + instruction.Op2Imm = immr; + instruction.Op3Kind = Arm64OperandKind.None; + instruction.Op3Imm = 0; + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + + // Check if this matches UBFIZ pattern: UBFM Rd, Rn, #(-lsb MOD width), #(width-lsb-1) + // where lsb is the least significant bit position and width is the field width + var lsb = (regWidth - immr) % regWidth; + var fieldWidth = imms + 1; + if (lsb + fieldWidth <= regWidth && immr == (regWidth - lsb) % regWidth && imms == fieldWidth - 1) + { + // Convert to UBFIZ + instruction.Mnemonic = Arm64Mnemonic.UBFIZ; + instruction.Op2Imm = lsb; + instruction.Op3Imm = fieldWidth; + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + + // Check if this matches UBFX pattern: UBFM Rd, Rn, #lsb, #(lsb+width-1) + if (immr <= imms) + { + var ubfxWidth = imms - immr + 1; + // Convert to UBFX + instruction.Mnemonic = Arm64Mnemonic.UBFX; + instruction.Op2Imm = immr; // lsb + instruction.Op3Imm = ubfxWidth; // width + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + } + + // SBFM to ASR/SBFIZ/SBFX alias conversion + if (instruction.Mnemonic == Arm64Mnemonic.SBFM && instruction.Op2Kind == Arm64OperandKind.Immediate && instruction.Op3Kind == Arm64OperandKind.Immediate) + { + var immr = instruction.Op2Imm; + var imms = instruction.Op3Imm; + var is64Bit = instruction.Op0Reg >= Arm64Register.X0 && instruction.Op0Reg <= Arm64Register.X31; + var regWidth = is64Bit ? 64 : 32; + + // Check if this matches ASR pattern: SBFM Rd, Rn, #shift, #(width-1) + if (imms == regWidth - 1) + { + // Convert to ASR + instruction.Mnemonic = Arm64Mnemonic.ASR; + instruction.Op2Imm = immr; + instruction.Op3Kind = Arm64OperandKind.None; + instruction.Op3Imm = 0; + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + + // Check if this matches SBFIZ pattern: SBFM Rd, Rn, #(-lsb MOD width), #(width-lsb-1) + var lsb = (regWidth - immr) % regWidth; + var fieldWidth = imms + 1; + if (lsb + fieldWidth <= regWidth && immr == (regWidth - lsb) % regWidth && imms == fieldWidth - 1) + { + // Convert to SBFIZ + instruction.Mnemonic = Arm64Mnemonic.SBFIZ; + instruction.Op2Imm = lsb; + instruction.Op3Imm = fieldWidth; + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + + // Check if this matches SBFX pattern: SBFM Rd, Rn, #lsb, #(lsb+width-1) + if (immr <= imms) + { + var sbfxWidth = imms - immr + 1; + // Convert to SBFX + instruction.Mnemonic = Arm64Mnemonic.SBFX; + instruction.Op2Imm = immr; // lsb + instruction.Op3Imm = sbfxWidth; // width + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + } } } From 8c6e5ec83ccba14ca84525782312ea10d7ba0234 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Wed, 18 Jun 2025 21:05:31 +0800 Subject: [PATCH 18/28] bug fix --- Disarm/InternalDisassembly/Arm64Aliases.cs | 14 ++ .../Arm64NonScalarAdvancedSimd.cs | 155 ++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index be255bb..36ea93a 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -101,6 +101,20 @@ public static void CheckForAlias(ref Arm64Instruction instruction) } + // CSNEG Rd, Rn, Rm, cond => CNEG Rd, Rn, !cond when Rn == Rm + if (instruction.Mnemonic == Arm64Mnemonic.CSNEG && instruction.FinalOpConditionCode is not Arm64ConditionCode.AL and not Arm64ConditionCode.NV && instruction.Op2Kind == Arm64OperandKind.Register && instruction.Op1Kind == Arm64OperandKind.Register) + { + if(!instruction.Op2Reg.IsSp() && !instruction.Op1Reg.IsSp() && instruction.Op1Reg == instruction.Op2Reg) + { + //CSNEG Rd, Rn, Rn, COND => CNEG Rd, Rn, !COND + instruction.FinalOpConditionCode = instruction.FinalOpConditionCode.Invert(); + instruction.Op2Kind = Arm64OperandKind.None; + instruction.Op2Reg = Arm64Register.INVALID; + instruction.Mnemonic = Arm64Mnemonic.CNEG; + return; + } + } + if (instruction.Mnemonic == Arm64Mnemonic.SBFM && instruction.Op2Kind == Arm64OperandKind.Immediate && instruction.Op3Kind == Arm64OperandKind.Immediate && instruction.Op2Imm == 0) { //Check imm3 diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index ef39ad9..98f9f40 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -497,6 +497,161 @@ private static Arm64Instruction AdvancedSimdCopy(uint instruction) }; } + if (mnemonic == Arm64Mnemonic.DUP && imm4 == 0b0001) + { + // DUP (general) - duplicate general register to vector + Arm64ArrangementSpecifier arrangement; + Arm64Register srcReg; + + if (imm5.TestBit(0)) + { + // 8-bit elements + arrangement = qFlag ? Arm64ArrangementSpecifier.SixteenB : Arm64ArrangementSpecifier.EightB; + srcReg = Arm64Register.W0 + rn; + } + else if (imm5.TestBit(1)) + { + // 16-bit elements + arrangement = qFlag ? Arm64ArrangementSpecifier.EightH : Arm64ArrangementSpecifier.FourH; + srcReg = Arm64Register.W0 + rn; + } + else if (imm5.TestBit(2)) + { + // 32-bit elements + arrangement = qFlag ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS; + srcReg = Arm64Register.W0 + rn; + } + else if (imm5.TestBit(3)) + { + // 64-bit elements + arrangement = qFlag ? Arm64ArrangementSpecifier.TwoD : throw new Arm64UndefinedInstructionException("DUP: 64-bit scalar not supported in this context"); + srcReg = Arm64Register.X0 + rn; + } + else + { + throw new Arm64UndefinedInstructionException("DUP: invalid imm5 value"); + } + + return new() + { + Mnemonic = Arm64Mnemonic.DUP, + Op0Kind = Arm64OperandKind.Register, + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = arrangement, + Op1Kind = Arm64OperandKind.Register, + Op1Reg = srcReg, + MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister, + }; + } + + if (mnemonic == Arm64Mnemonic.SMOV || mnemonic == Arm64Mnemonic.UMOV) + { + // SMOV/UMOV - move vector element to general register (with sign/zero extension) + Arm64VectorElementWidth elementWidth; + uint elementIndex; + Arm64Register dstReg; + + if (imm5.TestBit(0)) + { + // 8-bit elements + elementWidth = Arm64VectorElementWidth.B; + elementIndex = imm5 >> 1; + dstReg = qFlag ? Arm64Register.X0 + rd : Arm64Register.W0 + rd; + } + else if (imm5.TestBit(1)) + { + // 16-bit elements + elementWidth = Arm64VectorElementWidth.H; + elementIndex = imm5 >> 2; + dstReg = qFlag ? Arm64Register.X0 + rd : Arm64Register.W0 + rd; + } + else if (imm5.TestBit(2)) + { + // 32-bit elements (only valid for UMOV) + if (mnemonic == Arm64Mnemonic.SMOV) + throw new Arm64UndefinedInstructionException("SMOV: 32-bit elements not supported"); + elementWidth = Arm64VectorElementWidth.S; + elementIndex = imm5 >> 3; + dstReg = qFlag ? Arm64Register.X0 + rd : Arm64Register.W0 + rd; + } + else if (imm5.TestBit(3)) + { + // 64-bit elements (only valid for UMOV with qFlag set) + if (mnemonic == Arm64Mnemonic.SMOV || !qFlag) + throw new Arm64UndefinedInstructionException("UMOV: 64-bit elements only valid with qFlag set"); + elementWidth = Arm64VectorElementWidth.D; + elementIndex = imm5 >> 4; + dstReg = Arm64Register.X0 + rd; + } + else + { + throw new Arm64UndefinedInstructionException("SMOV/UMOV: invalid imm5 value"); + } + + return new() + { + Mnemonic = mnemonic, + Op0Kind = Arm64OperandKind.Register, + Op0Reg = dstReg, + Op1Kind = Arm64OperandKind.VectorRegisterElement, + Op1Reg = Arm64Register.V0 + rn, + Op1VectorElement = new Arm64VectorElement(elementWidth, (int)elementIndex), + MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister, + }; + } + + if (mnemonic == Arm64Mnemonic.INS && imm4 == 0b0011) + { + // INS (general) - insert general register into vector element + Arm64VectorElementWidth elementWidth; + uint elementIndex; + Arm64Register srcReg; + + if (imm5.TestBit(0)) + { + // 8-bit elements + elementWidth = Arm64VectorElementWidth.B; + elementIndex = imm5 >> 1; + srcReg = Arm64Register.W0 + rn; + } + else if (imm5.TestBit(1)) + { + // 16-bit elements + elementWidth = Arm64VectorElementWidth.H; + elementIndex = imm5 >> 2; + srcReg = Arm64Register.W0 + rn; + } + else if (imm5.TestBit(2)) + { + // 32-bit elements + elementWidth = Arm64VectorElementWidth.S; + elementIndex = imm5 >> 3; + srcReg = Arm64Register.W0 + rn; + } + else if (imm5.TestBit(3)) + { + // 64-bit elements + elementWidth = Arm64VectorElementWidth.D; + elementIndex = imm5 >> 4; + srcReg = Arm64Register.X0 + rn; + } + else + { + throw new Arm64UndefinedInstructionException("INS: invalid imm5 value"); + } + + return new() + { + Mnemonic = Arm64Mnemonic.INS, + Op0Kind = Arm64OperandKind.VectorRegisterElement, + Op0Reg = Arm64Register.V0 + rd, + Op0VectorElement = new Arm64VectorElement(elementWidth, (int)elementIndex), + Op1Kind = Arm64OperandKind.Register, + Op1Reg = srcReg, + MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister, + }; + } + return new() { Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, From a98e4dd4d1527cc14ce8d5cccf14e24df8487f6a Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Thu, 19 Jun 2025 01:15:56 +0800 Subject: [PATCH 19/28] fix FMOV with immdata --- Disarm/Arm64Instruction.cs | 2 ++ Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Disarm/Arm64Instruction.cs b/Disarm/Arm64Instruction.cs index 8eb029c..c42bce0 100644 --- a/Disarm/Arm64Instruction.cs +++ b/Disarm/Arm64Instruction.cs @@ -194,7 +194,9 @@ private bool AppendOperand(StringBuilder sb, Arm64OperandKind kind, Arm64Registe sb.Append(",").Append(shiftType).Append("#").Append(shiftAmount); } else if (kind == Arm64OperandKind.FloatingPointImmediate) { + sb.Append("#"); sb.Append(fpImm.ToString(CultureInfo.InvariantCulture)); + } else if(kind == Arm64OperandKind.ImmediatePcRelative) sb.Append("0x").Append(((long) Address + imm).ToString("X")); diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index 98f9f40..0f61ef7 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -129,7 +129,9 @@ private static Arm64Instruction AdvancedSimdModifiedImmediate(uint instruction) ? Arm64ArrangementSpecifier.FourS : Arm64ArrangementSpecifier.TwoS; //Single precision - var convertedImmediate = Arm64CommonUtils.AdvancedSimdExpandImmediate(op, (byte)cmode, (byte) immediate); + // Use DecodeFPImm for floating-point immediate values instead of AdvancedSimdExpandImmediate + uint pType = op ? 0b01U : o2 ? 0b10U : 0b00U; // 01=double, 10=half, 00=single + double fpValue = Arm64CommonUtils.DecodeFPImm(pType, (uint)immediate); return new() { @@ -137,8 +139,8 @@ private static Arm64Instruction AdvancedSimdModifiedImmediate(uint instruction) Op0Kind = Arm64OperandKind.Register, Op0Reg = Arm64Register.V0 + rd, Op0Arrangement = arrangement, - Op1Kind = Arm64OperandKind.Immediate, - Op1Imm = (long)convertedImmediate, + Op1Kind = Arm64OperandKind.FloatingPointImmediate, + Op1FpImm = fpValue, MnemonicCategory = Arm64MnemonicCategory.SimdConstantToRegister, }; } From 23c398f5f172ad8c281a30cad1ed8ff3e6c490e1 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Thu, 19 Jun 2025 18:42:18 +0800 Subject: [PATCH 20/28] UDP INS is better --- Disarm/InternalDisassembly/Arm64Aliases.cs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index 36ea93a..5924a74 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -144,24 +144,6 @@ public static void CheckForAlias(ref Arm64Instruction instruction) return; } - - if (instruction.Mnemonic == Arm64Mnemonic.INS && instruction.Op0Kind == Arm64OperandKind.VectorRegisterElement && instruction.Op1Kind == Arm64OperandKind.VectorRegisterElement) - { - //INS Vd.Ts[i1], Vn.Ts[i2] => MOV Vd.Ts[i1], Vn.Ts[i2] - //i.e. just change INS to MOV - instruction.Mnemonic = Arm64Mnemonic.MOV; - - //Category remains SimdRegisterToRegister - return; - } - - if (instruction.Mnemonic == Arm64Mnemonic.DUP && instruction.Op0Kind == Arm64OperandKind.Register && instruction.Op1Kind == Arm64OperandKind.VectorRegisterElement) - { - //DUP Rd, Vn.Ts[i] => MOV Rd, Vn.Ts[i] - //i.e. just change DUP to MOV - instruction.Mnemonic = Arm64Mnemonic.MOV; - return; - } // UBFM to LSL alias conversion if (instruction.Mnemonic == Arm64Mnemonic.UBFM && instruction.Op2Kind == Arm64OperandKind.Immediate && instruction.Op3Kind == Arm64OperandKind.Immediate) From 2162858e303084b399ded919ff53114c8433eb6e Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Tue, 24 Jun 2025 15:14:46 +0800 Subject: [PATCH 21/28] support more alia --- Disarm/InternalDisassembly/Arm64Aliases.cs | 18 +++++ .../InternalDisassembly/Arm64CommonUtils.cs | 71 ++++++++++++++----- 2 files changed, 73 insertions(+), 16 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index 5924a74..02bcfbe 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -25,6 +25,24 @@ public static void CheckForAlias(ref Arm64Instruction instruction) return; } + // ORR Xd, XZR, #imm => MOV Xd, #imm + if (instruction.Mnemonic == Arm64Mnemonic.ORR && instruction.Op1Reg is Arm64Register.X31 or Arm64Register.W31 && instruction.Op2Kind == Arm64OperandKind.Immediate) + { + instruction.Mnemonic = Arm64Mnemonic.MOV; + + // Move immediate to Op1 + instruction.Op1Kind = Arm64OperandKind.Immediate; + instruction.Op1Imm = instruction.Op2Imm; + + // Clear Op2 + instruction.Op2Kind = Arm64OperandKind.None; + instruction.Op2Imm = 0; + + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + + return; + } + if (instruction.Mnemonic == Arm64Mnemonic.ORR && instruction.Op1Kind == Arm64OperandKind.Register && instruction.Op2Kind == Arm64OperandKind.Register && instruction.Op1Reg == instruction.Op2Reg) { //Change ORR R0, R1, R1 => MOV R0, R1 diff --git a/Disarm/InternalDisassembly/Arm64CommonUtils.cs b/Disarm/InternalDisassembly/Arm64CommonUtils.cs index a9065e5..58a28ff 100644 --- a/Disarm/InternalDisassembly/Arm64CommonUtils.cs +++ b/Disarm/InternalDisassembly/Arm64CommonUtils.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Linq; namespace Disarm.InternalDisassembly; @@ -69,14 +70,17 @@ private static long BitsToLong(BitArray bits) return result; } - private static ulong RotateRight(ulong original, int numBits, int shift) + public static ulong RotateRight(ulong original, int numBits, int shift) { var m = shift % numBits; var right = original >> m; var left = original << (numBits - m); - - return right | left; + + // 确保左移结果不会超出numBits的范围 + var mask = numBits == 64 ? ulong.MaxValue : (1UL << numBits) - 1; + + return (right | left) & mask; } private static BitArray LongToBits(long value, int numBits) @@ -155,31 +159,43 @@ public static (long, long) DecodeBitMasks(bool nFlag, int desiredSize, byte imms //imms and immr are actually 6 bits not 8. var combined = (short)((nFlag ? 1 << 6 : 0) | (~imms & 0b11_1111)); - var bits = LongToBits(combined, 12); - var len = HighestSetBit(bits); + var len = HighestSetBit(combined, 12); if (len < 1) throw new Arm64UndefinedInstructionException("DecodeBitMasks: highestBit < 1"); - if ((1 << len) > desiredSize) - throw new Arm64UndefinedInstructionException("DecodeBitMasks: (1 << highestBit) > desiredSize"); + // 计算element size + var esize = 1 << len; + + if (esize > desiredSize) + { + throw new Arm64UndefinedInstructionException("DecodeBitMasks: (1 << len) > desiredSize"); + } var levels = (1 << len) - 1; - if (immediate && (imms & levels) == levels) - throw new Arm64UndefinedInstructionException("DecodeBitMasks: imms & levels == levels not allowed in immediate mode"); - var s = imms & levels; var r = immr & levels; var diff = s - r; - var esize = 1 << len; var d = diff & ((1 << (len - 1)) - 1); //UInt(diff) - var wElem = (1 << (s + 1)) - 1; - var tElem = (1 << (d + 1)) - 1; - - var wMask = Replicate(LongToBits((long)RotateRight((ulong)wElem, esize, r), esize), desiredSize); - var tMask = Replicate(LongToBits(tElem, esize), desiredSize); + + // 计算wElem和tElem + long wElem = (1L << (s + 1)) - 1; + long tElem = (1L << (d + 1)) - 1; + + // 创建在esize范围内的位模式,然后旋转 + var maskedWElem = esize == 64 ? wElem : wElem & ((1L << esize) - 1); + + ulong rotatedWElem = RotateRight((ulong)maskedWElem, esize, (int)r); + + // 使用原始的esize位模式,而不是旋转后的64位值 + BitArray rotatedBits = LongToBits(maskedWElem, esize); // 使用原始的maskedWElem + RotateRightInPlace(rotatedBits, (int)r); // 在位数组上直接进行旋转 + + BitArray wMask = Replicate(rotatedBits, desiredSize); + + BitArray tMask = Replicate(LongToBits(tElem, esize), desiredSize); return (BitsToLong(wMask), BitsToLong(tMask)); } @@ -384,4 +400,27 @@ private static double ToFloat16(byte[] bytes) return sign == 1 ? -result : result; #endif } + + private static void RotateRightInPlace(BitArray bits, int shiftAmount) + { + int length = bits.Length; + if (length == 0 || shiftAmount == 0) return; + + shiftAmount %= length; + if (shiftAmount == 0) return; + + // 创建临时数组存储原始值 + bool[] temp = new bool[length]; + for (int i = 0; i < length; i++) + { + temp[i] = bits[i]; + } + + // 执行右旋转 + for (int i = 0; i < length; i++) + { + int newIndex = (i + shiftAmount) % length; + bits[newIndex] = temp[i]; + } + } } \ No newline at end of file From 3d6961cc970c15597a32422462f3a11b39f849e2 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Wed, 16 Jul 2025 14:24:31 +0800 Subject: [PATCH 22/28] add BFM to BFI alias conversion --- Disarm/InternalDisassembly/Arm64Aliases.cs | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index 02bcfbe..261b158 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -270,5 +270,29 @@ public static void CheckForAlias(ref Arm64Instruction instruction) return; } } + + // BFM to BFI alias conversion + if (instruction.Mnemonic == Arm64Mnemonic.BFM && instruction.Op2Kind == Arm64OperandKind.Immediate && instruction.Op3Kind == Arm64OperandKind.Immediate) + { + var immr = instruction.Op2Imm; + var imms = instruction.Op3Imm; + var is64Bit = instruction.Op0Reg >= Arm64Register.X0 && instruction.Op0Reg <= Arm64Register.X31; + var regWidth = is64Bit ? 64 : 32; + + // Check if this matches BFI pattern: BFM Rd, Rn, #(-lsb MOD width), #(width-1) + // where lsb is the insertion position and width is the field width + var lsb = (regWidth - immr) % regWidth; + var fieldWidth = imms + 1; + + if (lsb + fieldWidth <= regWidth && immr == (regWidth - lsb) % regWidth && imms == fieldWidth - 1) + { + // Convert to BFI + instruction.Mnemonic = Arm64Mnemonic.BFI; + instruction.Op2Imm = lsb; + instruction.Op3Imm = fieldWidth; + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + } } } From 8cc4324e3e9b078f0f1220ac0ef1bc1c1b212e04 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Mon, 21 Jul 2025 18:04:49 +0800 Subject: [PATCH 23/28] enhance BFM to BFXIL and BFI conversion logic --- Disarm/InternalDisassembly/Arm64Aliases.cs | 28 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index 261b158..3d35ac3 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -279,17 +279,35 @@ public static void CheckForAlias(ref Arm64Instruction instruction) var is64Bit = instruction.Op0Reg >= Arm64Register.X0 && instruction.Op0Reg <= Arm64Register.X31; var regWidth = is64Bit ? 64 : 32; + // Check if this matches BFXIL pattern: BFM Rd, Rn, #lsb, #(lsb+width-1) + // where lsb is the extraction start position and width is the field width + if (immr <= imms) + { + var lsb = immr; + var fieldWidth = imms - immr + 1; + + if (lsb + fieldWidth <= regWidth) + { + // Convert to BFXIL + instruction.Mnemonic = Arm64Mnemonic.BFXIL; + instruction.Op2Imm = lsb; + instruction.Op3Imm = fieldWidth; + instruction.MnemonicCategory = Arm64MnemonicCategory.Move; + return; + } + } + // Check if this matches BFI pattern: BFM Rd, Rn, #(-lsb MOD width), #(width-1) // where lsb is the insertion position and width is the field width - var lsb = (regWidth - immr) % regWidth; - var fieldWidth = imms + 1; + var bfiLsb = (regWidth - immr) % regWidth; + var bfiFieldWidth = imms + 1; - if (lsb + fieldWidth <= regWidth && immr == (regWidth - lsb) % regWidth && imms == fieldWidth - 1) + if (bfiLsb + bfiFieldWidth <= regWidth && immr == (regWidth - bfiLsb) % regWidth && imms == bfiFieldWidth - 1) { // Convert to BFI instruction.Mnemonic = Arm64Mnemonic.BFI; - instruction.Op2Imm = lsb; - instruction.Op3Imm = fieldWidth; + instruction.Op2Imm = bfiLsb; + instruction.Op3Imm = bfiFieldWidth; instruction.MnemonicCategory = Arm64MnemonicCategory.Move; return; } From d18c557033d5e63c3045f48d99d3e2c2a68e6f6b Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Tue, 22 Jul 2025 17:17:41 +0800 Subject: [PATCH 24/28] refactor SMADDL instruction handling for optimized operand management --- Disarm/InternalDisassembly/Arm64Aliases.cs | 13 +++++++++++++ .../Arm64DataProcessingRegister.cs | 9 +++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index 3d35ac3..5bf7567 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -78,7 +78,20 @@ public static void CheckForAlias(ref Arm64Instruction instruction) return; } + if (instruction is { Mnemonic: Arm64Mnemonic.SMADDL, Op3Reg: Arm64Register.X31 }) + { + //SMADDL Xd, Wn, Wm, XZR => SMULL Xd, Wn, Wm + //because SMADDL is (Xd = Wn * Wm + Xa) so when Xa = XZR => Xd = Wn * Wm + + //Simply clear the last operand and change mnemonic + instruction.Mnemonic = Arm64Mnemonic.SMULL; + instruction.Op3Kind = Arm64OperandKind.None; + instruction.Op3Reg = Arm64Register.INVALID; + + //Category doesn't change (math => math) + return; + } if (instruction.Mnemonic == Arm64Mnemonic.MADD && instruction.Op3Reg is Arm64Register.X31 or Arm64Register.W31) { //MADD Rd, Rn, Rm, ZR => MUL Rd, Rn, Rm diff --git a/Disarm/InternalDisassembly/Arm64DataProcessingRegister.cs b/Disarm/InternalDisassembly/Arm64DataProcessingRegister.cs index 7cb6962..763ac07 100644 --- a/Disarm/InternalDisassembly/Arm64DataProcessingRegister.cs +++ b/Disarm/InternalDisassembly/Arm64DataProcessingRegister.cs @@ -566,10 +566,15 @@ private static Arm64Instruction DataProcessing3Source(uint instruction) _ => throw new Arm64UndefinedInstructionException($"DataProcessing3Source: unallocated operand combination: op31 = {op31} o0 = {o0} sf = {(is64Bit ? 1 : 0)}") }; + // For SMADDL, SMSUBL, UMADDL, UMSUBL: destination and accumulator are 64-bit, sources are 32-bit + var isLongMultiply = mnemonic is Arm64Mnemonic.SMADDL or Arm64Mnemonic.SMSUBL or Arm64Mnemonic.UMADDL or Arm64Mnemonic.UMSUBL; + var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0; + var sourceBaseReg = (isLongMultiply && is64Bit) ? Arm64Register.W0 : baseReg; - var regM = baseReg + rm; - var regN = baseReg + rn; + var regM = sourceBaseReg + rm; + var regN = sourceBaseReg + rn; + var regD = baseReg + rd; var regA = baseReg + ra; From c756c21dc79440c917f98eeac44d85223d3e8091 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Wed, 23 Jul 2025 15:47:44 +0800 Subject: [PATCH 25/28] refactor SMADDL and UMADDL instruction handling for proper aliasing to SMULL and UMULL --- Disarm/InternalDisassembly/Arm64Aliases.cs | 67 ++++++++++++++++++---- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index 5bf7567..f1c317f 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -78,13 +78,14 @@ public static void CheckForAlias(ref Arm64Instruction instruction) return; } - if (instruction is { Mnemonic: Arm64Mnemonic.SMADDL, Op3Reg: Arm64Register.X31 }) + + if (instruction.Mnemonic == Arm64Mnemonic.MADD && instruction.Op3Reg is Arm64Register.X31 or Arm64Register.W31) { - //SMADDL Xd, Wn, Wm, XZR => SMULL Xd, Wn, Wm - //because SMADDL is (Xd = Wn * Wm + Xa) so when Xa = XZR => Xd = Wn * Wm + //MADD Rd, Rn, Rm, ZR => MUL Rd, Rn, Rm + //because MADD is (Rd = Rn * Rm + Ra) so when Ra = ZR => Rd = Rn * Rm - //Simply clear the last operand and change mnemonic - instruction.Mnemonic = Arm64Mnemonic.SMULL; + //Simply clear the last operand + instruction.Mnemonic = Arm64Mnemonic.MUL; instruction.Op3Kind = Arm64OperandKind.None; instruction.Op3Reg = Arm64Register.INVALID; @@ -92,18 +93,62 @@ public static void CheckForAlias(ref Arm64Instruction instruction) return; } - if (instruction.Mnemonic == Arm64Mnemonic.MADD && instruction.Op3Reg is Arm64Register.X31 or Arm64Register.W31) + + // SMADDL Rd, Rn, Rm, X31 => SMULL Rd, Wn, Wm + // According to ARM64 specification, when the accumulator is X31 (zero register), + // SMADDL should be aliased to SMULL with 32-bit source operands + if (instruction.Mnemonic == Arm64Mnemonic.SMADDL && instruction.Op3Reg == Arm64Register.X31) { - //MADD Rd, Rn, Rm, ZR => MUL Rd, Rn, Rm - //because MADD is (Rd = Rn * Rm + Ra) so when Ra = ZR => Rd = Rn * Rm + instruction.Mnemonic = Arm64Mnemonic.SMULL; - //Simply clear the last operand - instruction.Mnemonic = Arm64Mnemonic.MUL; + // Convert source registers from X to W (e.g., X8 -> W8, X25 -> W25) + // The destination stays as X register + var regN = instruction.Op1Reg; + var regM = instruction.Op2Reg; + + if (regN >= Arm64Register.X0 && regN <= Arm64Register.X30) + { + instruction.Op1Reg = Arm64Register.W0 + (regN - Arm64Register.X0); + } + + if (regM >= Arm64Register.X0 && regM <= Arm64Register.X30) + { + instruction.Op2Reg = Arm64Register.W0 + (regM - Arm64Register.X0); + } + + // Clear the accumulator operand instruction.Op3Kind = Arm64OperandKind.None; instruction.Op3Reg = Arm64Register.INVALID; - //Category doesn't change (math => math) + return; + } + // UMADDL Rd, Rn, Rm, X31 => UMULL Rd, Wn, Wm + // According to ARM64 specification, when the accumulator is X31 (zero register), + // UMADDL should be aliased to UMULL with 32-bit source operands + if (instruction.Mnemonic == Arm64Mnemonic.UMADDL && instruction.Op3Reg == Arm64Register.X31) + { + instruction.Mnemonic = Arm64Mnemonic.UMULL; + + // Convert source registers from X to W (e.g., X26 -> W26, X9 -> W9) + // The destination stays as X register + var regN = instruction.Op1Reg; + var regM = instruction.Op2Reg; + + if (regN is >= Arm64Register.X0 and <= Arm64Register.X30) + { + instruction.Op1Reg = Arm64Register.W0 + (regN - Arm64Register.X0); + } + + if (regM is >= Arm64Register.X0 and <= Arm64Register.X30) + { + instruction.Op2Reg = Arm64Register.W0 + (regM - Arm64Register.X0); + } + + // Clear the accumulator operand + instruction.Op3Kind = Arm64OperandKind.None; + instruction.Op3Reg = Arm64Register.INVALID; + return; } From 9dbe694c999a3b9c2f5ab5af9338e8da44f15623 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Wed, 23 Jul 2025 16:10:12 +0800 Subject: [PATCH 26/28] refactor variable shift instruction handling for improved alias readability --- Disarm/InternalDisassembly/Arm64Aliases.cs | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Disarm/InternalDisassembly/Arm64Aliases.cs b/Disarm/InternalDisassembly/Arm64Aliases.cs index f1c317f..efcbd0e 100644 --- a/Disarm/InternalDisassembly/Arm64Aliases.cs +++ b/Disarm/InternalDisassembly/Arm64Aliases.cs @@ -370,5 +370,34 @@ public static void CheckForAlias(ref Arm64Instruction instruction) return; } } + + // Variable shift instructions to their more readable aliases + // LSLV Rd, Rn, Rm => LSL Rd, Rn, Rm + if (instruction.Mnemonic == Arm64Mnemonic.LSLV) + { + instruction.Mnemonic = Arm64Mnemonic.LSL; + return; + } + + // LSRV Rd, Rn, Rm => LSR Rd, Rn, Rm + if (instruction.Mnemonic == Arm64Mnemonic.LSRV) + { + instruction.Mnemonic = Arm64Mnemonic.LSR; + return; + } + + // ASRV Rd, Rn, Rm => ASR Rd, Rn, Rm + if (instruction.Mnemonic == Arm64Mnemonic.ASRV) + { + instruction.Mnemonic = Arm64Mnemonic.ASR; + return; + } + + // RORV Rd, Rn, Rm => ROR Rd, Rn, Rm + if (instruction.Mnemonic == Arm64Mnemonic.RORV) + { + instruction.Mnemonic = Arm64Mnemonic.ROR; + return; + } } } From 598dae6a8413250035cfca10c0b87055fe7e1311 Mon Sep 17 00:00:00 2001 From: 295238641 <295238641@qq.com> Date: Wed, 23 Jul 2025 23:21:50 +0800 Subject: [PATCH 27/28] update EXT Ins --- Disarm/Arm64Mnemonic.cs | 1 + .../Arm64NonScalarAdvancedSimd.cs | 32 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Disarm/Arm64Mnemonic.cs b/Disarm/Arm64Mnemonic.cs index 143fa84..4b59a7f 100644 --- a/Disarm/Arm64Mnemonic.cs +++ b/Disarm/Arm64Mnemonic.cs @@ -140,6 +140,7 @@ public enum Arm64Mnemonic ERETAB, ESB, EXTR, + EXT, // Advanced SIMD extract FABD, FABS, FACGE, diff --git a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs index 0f61ef7..23be1d6 100644 --- a/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64NonScalarAdvancedSimd.cs @@ -723,10 +723,36 @@ private static Arm64Instruction AdvancedSimdPermute(uint instruction) private static Arm64Instruction AdvancedSimdExtract(uint instruction) { + var q = instruction.TestBit(30); // Bit 30 - 0 for 64-bit, 1 for 128-bit + var rm = (int)(instruction >> 16) & 0b1111; // Bits 16-19 + var imm4 = (instruction >> 11) & 0b1111; // Bits 11-14 - extraction index + var rn = (int)(instruction >> 5) & 0b11111; // Bits 5-9 + var rd = (int)instruction & 0b11111; // Bits 0-4 + + // EXT only operates on byte elements + var arrangement = q ? Arm64ArrangementSpecifier.SixteenB : Arm64ArrangementSpecifier.EightB; + + // For 64-bit operation (q=0), imm4 must be in range 0-7 + // For 128-bit operation (q=1), imm4 must be in range 0-15 + var maxIndex = q ? 15 : 7; + if (imm4 > maxIndex) + throw new Arm64UndefinedInstructionException($"AdvancedSimdExtract: imm4 {imm4} exceeds maximum {maxIndex} for {(q ? "128" : "64")}-bit operation"); + return new() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, - MnemonicCategory = Arm64MnemonicCategory.SimdRegisterToRegister, + Mnemonic = Arm64Mnemonic.EXT, + Op0Kind = Arm64OperandKind.Register, + Op0Reg = Arm64Register.V0 + rd, + Op0Arrangement = arrangement, + Op1Kind = Arm64OperandKind.Register, + Op1Reg = Arm64Register.V0 + rn, + Op1Arrangement = arrangement, + Op2Kind = Arm64OperandKind.Register, + Op2Reg = Arm64Register.V0 + rm, + Op2Arrangement = arrangement, + Op3Kind = Arm64OperandKind.Immediate, + Op3Imm = imm4, + MnemonicCategory = Arm64MnemonicCategory.SimdVectorMath, }; } @@ -846,7 +872,7 @@ private static Arm64Instruction AdvancedSimdTwoRegisterMisc(uint instruction) { Arm64Mnemonic.CMGT or Arm64Mnemonic.CMEQ or Arm64Mnemonic.CMLT or Arm64Mnemonic.CMGE or Arm64Mnemonic.CMLE or - Arm64Mnemonic.FCMGT or Arm64Mnemonic.FCMGE => Arm64MnemonicCategory.SimdComparison, + Arm64Mnemonic.FCMEQ or Arm64Mnemonic.FCMGE or Arm64Mnemonic.FCMGT => Arm64MnemonicCategory.SimdComparison, _ => Arm64MnemonicCategory.SimdVectorMath, }; From 5cbdb5bd3ecf15a5522b4617c1477a6758c8d0d1 Mon Sep 17 00:00:00 2001 From: Imy <295238641@qq.com> Date: Thu, 11 Sep 2025 13:55:28 +0800 Subject: [PATCH 28/28] refactor Arm64Branches to improve bit testing logic and register selection --- Disarm/InternalDisassembly/Arm64Branches.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Disarm/InternalDisassembly/Arm64Branches.cs b/Disarm/InternalDisassembly/Arm64Branches.cs index 5cee7fe..373727f 100644 --- a/Disarm/InternalDisassembly/Arm64Branches.cs +++ b/Disarm/InternalDisassembly/Arm64Branches.cs @@ -52,12 +52,16 @@ public static Arm64Instruction TestAndBranch(uint instruction) var mnemonic = isNegated ? Arm64Mnemonic.TBNZ : Arm64Mnemonic.TBZ; + // 计算要测试的位号:b5位决定是32位还是64位,b40是位号的高5位 var bitToTest = b40; if (b5) - bitToTest &= 1 << 5; + bitToTest |= 32; // 对于64位寄存器,b5=1时位号需要加上32 var jumpTo = Arm64CommonUtils.CorrectSignBit(imm14, 14) * 4; - var regT = Arm64Register.X0 + rt; + + // 根据b5位决定使用32位还是64位寄存器 + var baseReg = b5 ? Arm64Register.X0 : Arm64Register.W0; + var regT = baseReg + rt; return new() {