public static bool IsJump(ArmInstruction instruction) { return(!instruction.Details.BelongsToGroup(ArmInstructionGroupId.ARM_GRP_CALL) && (instruction.Details.BelongsToGroup(ArmInstructionGroupId.ARM_GRP_BRANCH_RELATIVE) || instruction.Details.BelongsToGroup(ArmInstructionGroupId.ARM_GRP_JUMP) || instruction.Details.IsRegisterExplicitlyWritten(ArmRegisterId.ARM_REG_PC))); }
private IArmInstruction[] ConvertToArm(uint[] aRawInstructions, uint aStartingAddress) { // TODO: optimise this List <IArmInstruction> ret = new List <IArmInstruction>(); // uint address = aStartingAddress; for (int i = 0; i < aRawInstructions.Length; i++, address += 4) { uint raw = aRawInstructions[i]; foreach (ArmInstruction inst in iArmInstructions) { if (inst.Matches(raw)) { Type type = inst.GetType(); ConstructorInfo ctor = type.GetConstructor(new Type[] { }); ArmInstruction copy = (ArmInstruction)ctor.Invoke(new object[] { }); copy.AIAddress = address; copy.AIRawValue = raw; ret.Add(copy); Disassemble(copy); break; } } } // return(ret.ToArray()); }
private void Read() { ulong absoluteFirstOffset = AbsolutePokemonIndexOffset(ActorDataList.First()); // TODO: get rid of the ArmInstruction class and add encoding and decoding functions for // the instructions used here to CodeGenerationHelper instead. var firstOffsetInstruction = new ArmInstruction(BitConverter.ToUInt32(executable.Data, (int)absoluteFirstOffset)); if (!firstOffsetInstruction.IsSupported) { throw new InvalidOperationException("Cannot read Actor database - maybe an incompatible version was used?"); } foreach (var actorData in ActorDataList.Where(actorData => actorData.PokemonIndexEditable)) { var instruction = new ArmInstruction(BitConverter.ToUInt32(executable.Data, (int)AbsolutePokemonIndexOffset(actorData))); if (instruction.IsSupported) { // It doesn't matter if the instruction is unsupported here because we can rely // on the hardcoded values PegasusActDatabase.Data.cs and it will be readable after edits. actorData.PokemonIndex = (CreatureIndex)instruction.Value; } } }
public void Write() { // TODO: get rid of the ArmInstruction class and add encoding and decoding functions for // the instructions used here to CodeGenerationHelper instead. foreach (var actorData in ActorDataList.Where(actorData => actorData.PokemonIndexEditable)) { var instruction = new ArmInstruction(BitConverter.ToUInt32(executable.Data, (int)AbsolutePokemonIndexOffset(actorData))); if (instruction.IsSupported) { instruction.Value = (ushort)actorData.PokemonIndex; } else if (instruction.Code == ArmInstructionCode.MovBitmaskImmediateToWRegister) { // Replace the unsupported instruction with an equivalent one instruction = new ArmInstruction(ArmInstructionCode.MovImmediateToWRegister, instruction.Register, (ushort)actorData.PokemonIndex); } BitConverter.GetBytes(instruction.RawInstruction).CopyTo(executable.Data, (int)AbsolutePokemonIndexOffset(actorData)); } }
public ArmMachineInstruction(ArmInstruction instruction, Variable[] regVars) : base(instruction.Details.ConditionCode) { Instruction = instruction; var defs = instruction.Details.AllWrittenRegisters .Where(reg => reg.Id != ArmRegisterId.ARM_REG_PC) .Select(reg => regVars[ArmUtil.GetRegisterNumber(reg.Id)]); if (instruction.Details.BelongsToGroup(ArmInstructionGroupId.ARM_GRP_CALL)) { defs = defs.Append(regVars[0]).Append(regVars[1]) .Append(regVars[2]).Append(regVars[3]).Append(regVars[16]); } if (instruction.Details.UpdateFlags && !instruction.Details.IsRegisterWritten(ArmRegisterId.ARM_REG_CPSR)) { defs = defs.Append(regVars[16]); } VariableDefs.UnionWith(defs); var uses = instruction.Details.AllReadRegisters .Where(reg => reg.Id != ArmRegisterId.ARM_REG_PC) .Select(reg => regVars[ArmUtil.GetRegisterNumber(reg.Id)]); if (instruction.Details.ConditionCode != ArmConditionCode.ARM_CC_AL) { uses = uses.Append(regVars[16]); } if (instruction.Id == ArmInstructionId.ARM_INS_BX) { uses = uses.Append(regVars[ArmUtil.GetRegisterNumber(instruction.Details.Operands[0].Register.Id)]); } if (instruction.Details.BelongsToGroup(ArmInstructionGroupId.ARM_GRP_CALL) || instruction.Id == ArmInstructionId.ARM_INS_BX) { uses = uses.Append(regVars[0]).Append(regVars[1]).Append(regVars[2]).Append(regVars[3]) .Append(regVars[13]); } VariableUses.UnionWith(uses); for (int i = 0; i < Instruction.Details.Operands.Length; i++) { var op = Instruction.Details.Operands[i]; switch (op.Type) { case ArmOperandType.Register: if (op.AccessType == OperandAccessType.Write || (Instruction.DisassembleMode == ArmDisassembleMode.Thumb && op.AccessType == (OperandAccessType.Read | OperandAccessType.Write) && i == 0)) { Operands.Add((true, VariableDefs.FirstOrDefault(v => v.Location == VariableLocation.Register && v.Address == ArmUtil.GetRegisterNumber(op.Register.Id)))); } else { Operands.Add((false, VariableUses.FirstOrDefault(v => v.Location == VariableLocation.Register && v.Address == ArmUtil.GetRegisterNumber(op.Register.Id)))); if (op.ShiftOperation >= ArmShiftOperation.ARM_SFT_LSL_REG) { Operands.Add((false, VariableUses.First(v => v.Location == VariableLocation.Register && v.Address == ArmUtil.GetRegisterNumber(op.ShiftRegister.Id)))); } } break; case ArmOperandType.Memory: Operands.Add((false, VariableUses.First(v => v.Location == VariableLocation.Register && v.Address == ArmUtil.GetRegisterNumber(op.Memory.Base.Id)))); if (op.Memory.Index == null) { Operands.Add((false, new Constant((uint)op.Memory.Displacement))); } else { Operands.Add((false, VariableUses.First(v => v.Location == VariableLocation.Register && v.Address == ArmUtil.GetRegisterNumber(op.Memory.Index.Id)))); } if (instruction.Details.WriteBack) { Operands.Add((true, VariableDefs.First(v => v.Location == VariableLocation.Register && v.Address == ArmUtil.GetRegisterNumber(op.Memory.Base.Id)))); } break; case ArmOperandType.Immediate: Operands.Add((false, new Constant((uint)op.Immediate))); break; default: Operands.Add((false, null)); break; } } if (VariableUses.Contains(regVars[16])) { FlagsUseOperand = regVars[16]; } if (VariableDefs.Contains(regVars[16])) { FlagsDefOperand = regVars[16]; } }
internal override void Process(ArmPrologueHelper aProlog) { IArmInstruction instruction = base.Instruction; // Only unconditional instructions are handled if (instruction.AIConditionCode == TArmInstructionCondition.AL) { if (instruction is ArmInstruction) { ArmInstruction armInst = (ArmInstruction)instruction; // if (armInst is Arm_LoadOrStoreMultiple) { Arm_LoadOrStoreMultiple lsmInstruction = (Arm_LoadOrStoreMultiple)instruction; // We're looking for store operations if (lsmInstruction.DataTransferType == TArmDataTransferType.EStore) { // We're looking for LSM's that involve SP. if (lsmInstruction.BaseRegister == TArmRegisterType.EArmReg_SP) { if (lsmInstruction is Arm_LoadOrStoreMultiple_GP) { Arm_LoadOrStoreMultiple_GP gpLsmInstruction = (Arm_LoadOrStoreMultiple_GP)lsmInstruction; HandleDTOperation(aProlog, gpLsmInstruction.Registers); } else if (lsmInstruction is Arm_LoadOrStoreMultiple_VFP) { Arm_LoadOrStoreMultiple_VFP vfpLsmInstruction = (Arm_LoadOrStoreMultiple_VFP)lsmInstruction; HandleDTOperation(aProlog, vfpLsmInstruction.Registers); } } } } } else if (instruction is ThumbInstruction) { ThumbInstruction thumbInst = (ThumbInstruction)instruction; // if (thumbInst is Thumb_LoadOrStoreMultiple) { // Special case that loads or stores multiple registers Thumb_LoadOrStoreMultiple lsmThumb = (Thumb_LoadOrStoreMultiple)thumbInst; if (lsmThumb.DataTransferType == TArmDataTransferType.EStore && lsmThumb.Rd == TArmRegisterType.EArmReg_SP) { HandleDTOperation(aProlog, lsmThumb.Registers); } else { } } else if (thumbInst is Thumb_LDR_RelativeToPC) { // When the Prologue needs to establish a working stack slurry, then often // the scratch registers are used to build up a large subtraction from SP. HandleDTLoad(aProlog, thumbInst as Thumb_LDR_RelativeToPC); } } else { throw new NotSupportedException("Instruction type not supported"); } } }