private void RewritePush() { RegisterOperand reg = instrCur.op1 as RegisterOperand; if (reg != null && reg.Register == Registers.cs) { if (dasm.Peek(1).code == Opcode.call && dasm.Peek(1).op1.Width == PrimitiveType.Word16) { dasm.MoveNext(); m.Assign(StackPointer(), m.ISub(StackPointer(), reg.Register.DataType.Size)); RewriteCall(dasm.Current.op1, dasm.Current.op1.Width); this.len = (byte)(this.len + dasm.Current.Length); return; } if ( dasm.Peek(1).code == Opcode.push && (dasm.Peek(1).op1 is ImmediateOperand) && dasm.Peek(2).code == Opcode.push && (dasm.Peek(2).op1 is ImmediateOperand) && dasm.Peek(3).code == Opcode.jmp && (dasm.Peek(3).op1 is X86AddressOperand)) { // That's actually a far call, but the callee thinks its a near call. RewriteCall(dasm.Peek(3).op1, instrCur.op1.Width); dasm.MoveNext(); dasm.MoveNext(); dasm.MoveNext(); return; } } var imm = instrCur.op1 as ImmediateOperand; var value = SrcOp(dasm.Current.op1, arch.StackRegister.DataType); Debug.Assert( value.DataType.Size == 2 || value.DataType.Size == 4 || value.DataType.Size == 8, string.Format("Unexpected size {0}", dasm.Current.dataWidth)); RewritePush(PrimitiveType.CreateWord(value.DataType.Size), value); }
/// <summary> /// Visitation function for <see cref="IR.IIRVisitor.IntegerCompareInstruction"/> instruction. /// </summary> /// <param name="ctx">The context.</param> void IR.IIRVisitor.IntegerCompareInstruction(Context ctx) { EmitOperandConstants(ctx); IR.ConditionCode condition = ctx.ConditionCode; ctx.SetInstruction(CPUx86.Instruction.CmpInstruction, ctx.Result, ctx.Operand1); if (IsUnsigned(ctx.Operand1) || IsUnsigned(ctx.Result)) { ctx.AppendInstruction(CPUx86.Instruction.SetccInstruction, GetUnsignedConditionCode(condition), ctx.Result); } else { ctx.AppendInstruction(CPUx86.Instruction.SetccInstruction, condition, ctx.Result); } if (ctx.Result is RegisterOperand) { RegisterOperand rop = new RegisterOperand(new SigType(CilElementType.U1), ((RegisterOperand)ctx.Result).Register); ctx.AppendInstruction(CPUx86.Instruction.MovzxInstruction, rop, rop); } }
/// <summary> /// Visitation function for <see cref="CIL.ICILVisitor.Ret"/>. /// </summary> /// <param name="ctx">The context.</param> void CIL.ICILVisitor.Ret(Context ctx) { bool eax = false; if (ctx.OperandCount != 0 && ctx.Operand1 != null) { Operand retval = ctx.Operand1; if (retval.IsRegister) { // Do not move, if return value is already in EAX RegisterOperand rop = (RegisterOperand)retval; if (System.Object.ReferenceEquals(rop.Register, GeneralPurposeRegister.EAX)) { eax = true; } } if (!eax) { ctx.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(new SigType(CilElementType.I), GeneralPurposeRegister.EAX), retval); } } }
private int CompareOperands(MachineOperand opA, MachineOperand opB) { if (!opA.GetType().IsAssignableFrom(opB.GetType())) { return(-1); } RegisterOperand regOpA = opA as RegisterOperand; if (regOpA != null) { RegisterOperand regOpB = (RegisterOperand)opB; return((int)regOpB.Register.Number - (int)regOpA.Register.Number); } ImmediateOperand immOpA = opA as ImmediateOperand; if (immOpA != null) { ImmediateOperand immOpB = (ImmediateOperand)opB; return(0); // disregard immediate values. } throw new NotImplementedException("NYI"); }
/// <summary> /// Visitation function for <see cref="CPUx86.IX86Visitor.Call"/> instructions. /// </summary> /// <param name="context">The context.</param> void CPUx86.IX86Visitor.Call(Context context) { Operand destinationOperand = context.Operand1; if (destinationOperand == null) { return; } if (destinationOperand is SymbolOperand) { return; } if (!(destinationOperand is RegisterOperand)) { Context before = context.InsertBefore(); RegisterOperand eax = new RegisterOperand(BuiltInSigType.IntPtr, GeneralPurposeRegister.EAX); before.SetInstruction(CPUx86.Instruction.MovInstruction, eax, destinationOperand); context.Operand1 = eax; } }
/* * if (i < 2) * return tc; * if (instrs[i-1].code != Opcode.test) * return tc; * var ah = instrs[i-1].op1 as RegisterOperand; * if (ah == null || ah.Register != Registers.ah) * return tc; * var m = instrs[i-1].op2 as ImmediateOperand; * if (m == null) * return tc; * * if (instrs[i-2].code != Opcode.fstsw) * return tc; * int mask = m.Value.ToInt32(); * * var fpuf = orw.FlagGroup(FlagM.FPUF); * switch (cc) * { * case ConditionCode.PE: * if (mask == 0x05) return new TestCondition(ConditionCode.LE, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.GE, fpuf); * if (mask == 0x44) return new TestCondition(ConditionCode.NE, fpuf); * break; * case ConditionCode.PO: * if (mask == 0x44) return new TestCondition(ConditionCode.EQ, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.GE, fpuf); * if (mask == 0x05) return new TestCondition(ConditionCode.GT, fpuf); * break; * case ConditionCode.EQ: * if (mask == 0x40) return new TestCondition(ConditionCode.NE, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.LT, fpuf); * break; * case ConditionCode.NE: * if (mask == 0x40) return new TestCondition(ConditionCode.EQ, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.GE, fpuf); * if (mask == 0x01) return new TestCondition(ConditionCode.GT, fpuf); * break; * } * throw new NotImplementedException(string.Format( * "FSTSW/TEST AH,0x{0:X2}/J{1} not implemented.", mask, cc)); */ private void RewriteCall(MachineOperand callTarget, PrimitiveType opsize) { Address addr = OperandAsCodeAddress(callTarget); if (addr != null) { if (addr.ToLinear() == (dasm.Current.Address + dasm.Current.Length).ToLinear()) { // Calling the following address. Is the call followed by a // pop? var next = dasm.Peek(1); RegisterOperand reg = next.op1 as RegisterOperand; if (next.code == Opcode.pop && reg != null) { // call $+5,pop<reg> idiom dasm.MoveNext(); m.Assign( orw.AluRegister(reg), addr); this.len += 1; return; } } m.Call(addr, (byte)opsize.Size); } else { var target = SrcOp(callTarget); if (target.DataType.Size == 2) { var seg = Constant.Create(PrimitiveType.SegmentSelector, instrCur.Address.Selector.Value); target = m.Seq(seg, target); } m.Call(target, (byte)opsize.Size); } rtlc = RtlClass.Transfer | RtlClass.Call; }
/* * if (i < 2) * return tc; * if (instrs[i-1].code != Opcode.test) * return tc; * var ah = instrs[i-1].op1 as RegisterOperand; * if (ah == null || ah.Register != Registers.ah) * return tc; * var m = instrs[i-1].op2 as ImmediateOperand; * if (m == null) * return tc; * * if (instrs[i-2].code != Opcode.fstsw) * return tc; * int mask = m.Value.ToInt32(); * * var fpuf = orw.FlagGroup(FlagM.FPUF); * switch (cc) * { * case ConditionCode.PE: * if (mask == 0x05) return new TestCondition(ConditionCode.LE, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.GE, fpuf); * if (mask == 0x44) return new TestCondition(ConditionCode.NE, fpuf); * break; * case ConditionCode.PO: * if (mask == 0x44) return new TestCondition(ConditionCode.EQ, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.GE, fpuf); * if (mask == 0x05) return new TestCondition(ConditionCode.GT, fpuf); * break; * case ConditionCode.EQ: * if (mask == 0x40) return new TestCondition(ConditionCode.NE, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.LT, fpuf); * break; * case ConditionCode.NE: * if (mask == 0x40) return new TestCondition(ConditionCode.EQ, fpuf); * if (mask == 0x41) return new TestCondition(ConditionCode.GE, fpuf); * if (mask == 0x01) return new TestCondition(ConditionCode.GT, fpuf); * break; * } * throw new NotImplementedException(string.Format( * "FSTSW/TEST AH,0x{0:X2}/J{1} not implemented.", mask, cc)); */ private void RewriteCall(MachineOperand callTarget, PrimitiveType opsize) { Address addr = OperandAsCodeAddress(callTarget); if (addr != null) { if (addr.ToLinear() == (dasm.Current.Address + dasm.Current.Length).ToLinear()) { // Calling the following address. Is the call followed by a // pop? var next = dasm.Peek(1); RegisterOperand reg = next.op1 as RegisterOperand; if (next.code == Opcode.pop && reg != null) { // call $+5,pop<reg> idiom dasm.MoveNext(); emitter.Assign( orw.AluRegister(reg), addr); ric.Length += 1; return; } } emitter.Call(addr, (byte)opsize.Size); ric.Class = RtlClass.Transfer; } else { var target = SrcOp(callTarget); if (target.DataType.Size == 2) { target = emitter.Seq(orw.AluRegister(Registers.cs), target); } emitter.Call(target, (byte)opsize.Size); ric.Class = RtlClass.Transfer; } }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { MemoryOperand operand = new MemoryOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX, new System.IntPtr(0)); context.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX), context.Operand1); context.AppendInstruction(CPUx86.Instruction.LgdtInstruction, null, operand); RegisterOperand ax = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), GeneralPurposeRegister.EAX); RegisterOperand ds = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.DS); RegisterOperand es = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.ES); RegisterOperand fs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.FS); RegisterOperand gs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.GS); RegisterOperand ss = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.SS); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ax, new ConstantOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), (int)0x00000010)); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ds, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, es, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, fs, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, gs, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ss, ax); context.AppendInstruction(CPUx86.Instruction.FarJmpInstruction); context.AppendInstruction(CPUx86.Instruction.NopInstruction); context.Previous.SetBranch(context.Offset); }
/// <summary> /// Expands the given invoke instruction to perform the method call. /// </summary> /// <param name="ctx">The context.</param> /// <returns> /// A single instruction or an array of instructions, which appropriately represent the method call. /// </returns> void ICallingConvention.Expand(Context ctx) { /* * Calling convention is right-to-left, pushed on the stack. Return value in EAX for integral * types 4 bytes or less, XMM0 for floating point and EAX:EDX for 64-bit. If this is a method * of a type, the this argument is moved to ECX right before the call. * */ Runtime.Vm.RuntimeMethod invokeTarget = ctx.InvokeTarget; Operand result = ctx.Result; Operand operand1 = ctx.Operand1; List <Operand> operands = new List <Operand> (); operands.AddRange(ctx.Operands); int resultCount = ctx.ResultCount; int operandCount = ctx.OperandCount; SigType I = new SigType(CilElementType.I); RegisterOperand esp = new RegisterOperand(I, GeneralPurposeRegister.ESP); int stackSize = CalculateStackSizeForParameters(operands, invokeTarget.Signature.HasThis); ctx.SetInstruction(CPUx86.Instruction.NopInstruction); if (stackSize != 0) { ctx.AppendInstruction(CPUx86.Instruction.SubInstruction, esp, new ConstantOperand(I, stackSize)); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(_architecture.NativeType, GeneralPurposeRegister.EDX), esp); Stack <Operand> operandStack = GetOperandStackFromInstruction(operands, operandCount, invokeTarget.Signature.HasThis); int space = stackSize; CalculateRemainingSpace(ctx, operandStack, ref space); } if (invokeTarget.Signature.HasThis) { RegisterOperand ecx = new RegisterOperand(I, GeneralPurposeRegister.ECX); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, operand1); } ctx.AppendInstruction(IR.Instruction.CallInstruction); ctx.InvokeTarget = invokeTarget; if (stackSize != 0) { ctx.AppendInstruction(CPUx86.Instruction.AddInstruction, esp, new ConstantOperand(I, stackSize)); } if (resultCount > 0) { if (result.StackType == StackTypeCode.Int64) { MoveReturnValueTo64Bit(result, ctx); } else { MoveReturnValueTo32Bit(result, ctx); } } //ctx.Remove(); }
private Pdp11Instruction DecodeOperands(ushort wOpcode, Opcode opcode, string fmt) { List <MachineOperand> ops = new List <MachineOperand>(2); int i = 0; dataWidth = PrimitiveType.Word16; if (fmt.Length == 0) { return(new Pdp11Instruction { Opcode = opcode, }); } switch (fmt[i]) { case 'b': dataWidth = PrimitiveType.Byte; i += 2; break; case 'w': dataWidth = PrimitiveType.Word16; i += 2; break; } while (i != fmt.Length) { if (fmt[i] == ',') { ++i; } MachineOperand op; switch (fmt[i++]) { case 'E': op = this.DecodeOperand(wOpcode); break; case 'e': op = this.DecodeOperand(wOpcode >> 6); break; case 'r': op = new RegisterOperand(arch.GetRegister((wOpcode >> 6) & 7)); break; case 'I': op = Imm6(wOpcode); break; case 'F': op = this.DecodeOperand(wOpcode, true); break; case 'f': op = FpuAccumulator(wOpcode); break; default: throw new NotImplementedException(); } if (op == null) { return new Pdp11Instruction { Opcode = Opcode.illegal } } ; ops.Add(op); } var instr = new Pdp11Instruction { Opcode = opcode, DataWidth = dataWidth, op1 = ops.Count > 0 ? ops[0] : null, op2 = ops.Count > 1 ? ops[1] : null, }; return(instr); }
private Tms7000Instruction Decode(Opcode opcode, string format) { int iOp = 0; var instr = new Tms7000Instruction { Opcode = opcode, }; for (int i = 0; i < format.Length; ++i) { MachineOperand op; byte b; ushort w; switch (format[i]) { case ',': continue; case 'A': op = new RegisterOperand(arch.a); break; case 'B': op = new RegisterOperand(arch.b); break; case 'R': if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = new RegisterOperand(arch.GpRegs[b]); break; case 'P': if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = new RegisterOperand(arch.Ports[b]); break; case 'S': ; op = new RegisterOperand(arch.st); break; case 'i': if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = ImmediateOperand.Byte(b); break; case 'I': if (!rdr.TryReadBeUInt16(out w)) { return(Invalid()); } op = ImmediateOperand.Word16(w); break; case 'j': // short PC-relative jump if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = AddressOperand.Create(rdr.Address + (sbyte)b); break; case 'D': // direct, absolute address if (!rdr.TryReadBeUInt16(out w)) { return(Invalid()); } if (i < format.Length - 1 && format[i + 1] == 'B') { ++i; op = MemoryOperand.Indexed(Address.Ptr16(w), arch.b); } else { op = MemoryOperand.Direct(Address.Ptr16(w)); } break; case '*': // indirect if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = MemoryOperand.Indirect(arch.GpRegs[b]); break; default: throw new NotImplementedException($"Addressing mode {format[i]}"); } switch (iOp++) { case 0: instr.op1 = op; break; case 1: instr.op2 = op; break; case 2: instr.op3 = op; break; } } return(instr); }
public void Stbu(RegisterOperand rS, short offset, RegisterOperand rA) { Add(new PowerPcInstruction(Opcode.stbu, rS, Mem(rA, offset), null, false)); }
public void Mtctr(RegisterOperand r) { Add(new PowerPcInstruction(Opcode.mtctr, r, null, null, false)); }
public void Oris(RegisterOperand rA, RegisterOperand rS, ushort val) { Add(new PowerPcInstruction(Opcode.oris, rA, rS, new ImmediateOperand(Constant.Word16(val)), false)); }
/// <summary> /// Floatings the point compare instruction. /// </summary> /// <param name="ctx">The context.</param> void IR.IIRVisitor.FloatingPointCompareInstruction(Context ctx) { Operand op0 = ctx.Result; Operand left = EmitConstant(ctx.Operand1); Operand right = EmitConstant(ctx.Operand2); //ctx.Remove(); ctx.Operand1 = left; ctx.Operand2 = right; // Swap the operands if necessary... if (left is MemoryOperand && right is RegisterOperand) { SwapComparisonOperands(ctx); left = ctx.Operand1; right = ctx.Operand2; } IR.ConditionCode setcc = IR.ConditionCode.Equal; IR.ConditionCode code = ctx.ConditionCode; ctx.SetInstruction(CPUx86.Instruction.NopInstruction); // x86 is messed up :( switch (code) { case IR.ConditionCode.Equal: break; case IR.ConditionCode.NotEqual: break; case IR.ConditionCode.UnsignedGreaterOrEqual: setcc = IR.ConditionCode.GreaterOrEqual; break; case IR.ConditionCode.UnsignedGreaterThan: setcc = IR.ConditionCode.GreaterThan; break; case IR.ConditionCode.UnsignedLessOrEqual: setcc = IR.ConditionCode.LessOrEqual; break; case IR.ConditionCode.UnsignedLessThan: setcc = IR.ConditionCode.LessThan; break; case IR.ConditionCode.GreaterOrEqual: setcc = IR.ConditionCode.UnsignedGreaterOrEqual; break; case IR.ConditionCode.GreaterThan: setcc = IR.ConditionCode.UnsignedGreaterThan; break; case IR.ConditionCode.LessOrEqual: setcc = IR.ConditionCode.UnsignedLessOrEqual; break; case IR.ConditionCode.LessThan: setcc = IR.ConditionCode.UnsignedLessThan; break; } if (!(left is RegisterOperand)) { RegisterOperand xmm2 = new RegisterOperand(left.Type, SSE2Register.XMM2); if (left.Type.Type == CilElementType.R4) { ctx.AppendInstruction(CPUx86.Instruction.MovssInstruction, xmm2, left); } else { ctx.AppendInstruction(CPUx86.Instruction.MovsdInstruction, xmm2, left); } left = xmm2; } // Compare using the smallest precision if (left.Type.Type == CilElementType.R4 && right.Type.Type == CilElementType.R8) { RegisterOperand rop = new RegisterOperand(new SigType(CilElementType.R4), SSE2Register.XMM4); ctx.AppendInstruction(CPUx86.Instruction.Cvtsd2ssInstruction, rop, right); right = rop; } if (left.Type.Type == CilElementType.R8 && right.Type.Type == CilElementType.R4) { RegisterOperand rop = new RegisterOperand(new SigType(CilElementType.R4), SSE2Register.XMM3); ctx.AppendInstruction(CPUx86.Instruction.Cvtsd2ssInstruction, rop, left); left = rop; } if (left.Type.Type == CilElementType.R4) { switch (code) { case IR.ConditionCode.Equal: ctx.AppendInstruction(CPUx86.Instruction.UcomissInstruction, left, right); break; case IR.ConditionCode.NotEqual: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedGreaterOrEqual: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedGreaterThan: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedLessOrEqual: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedLessThan: goto case IR.ConditionCode.Equal; case IR.ConditionCode.GreaterOrEqual: ctx.AppendInstruction(CPUx86.Instruction.ComissInstruction, left, right); break; case IR.ConditionCode.GreaterThan: goto case IR.ConditionCode.GreaterOrEqual; case IR.ConditionCode.LessOrEqual: goto case IR.ConditionCode.GreaterOrEqual; case IR.ConditionCode.LessThan: goto case IR.ConditionCode.GreaterOrEqual; } } else { switch (code) { case IR.ConditionCode.Equal: ctx.AppendInstruction(CPUx86.Instruction.UcomisdInstruction, left, right); break; case IR.ConditionCode.NotEqual: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedGreaterOrEqual: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedGreaterThan: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedLessOrEqual: goto case IR.ConditionCode.Equal; case IR.ConditionCode.UnsignedLessThan: goto case IR.ConditionCode.Equal; case IR.ConditionCode.GreaterOrEqual: ctx.AppendInstruction(CPUx86.Instruction.ComisdInstruction, left, right); break; case IR.ConditionCode.GreaterThan: goto case IR.ConditionCode.GreaterOrEqual; case IR.ConditionCode.LessOrEqual: goto case IR.ConditionCode.GreaterOrEqual; case IR.ConditionCode.LessThan: goto case IR.ConditionCode.GreaterOrEqual; } } // Determine the result ctx.AppendInstruction(CPUx86.Instruction.SetccInstruction, setcc, op0); // Extend this to the full register, if we're storing it in a register if (op0 is RegisterOperand) { RegisterOperand rop = new RegisterOperand(new SigType(CilElementType.U1), ((RegisterOperand)op0).Register); ctx.AppendInstruction(CPUx86.Instruction.MovzxInstruction, op0, rop); } }
public virtual string FormatOperand(RegisterOperand operand) { StringBuilder sb = new StringBuilder(10); FormatRegister(sb, operand.Register); return sb.ToString(); }
/// <summary> /// Writes an effective address operand. /// </summary> /// <returns>The number of characters written.</returns> private int WriteOperand(RegisterOperand operand, bool writeSize) { #region Contract if (operand == null) return 0; #endregion int length = 0; if (writeSize) { switch (operand.RequestedSize) { case DataSize.Bit8: Writer.Write("byte "); length += 5; break; case DataSize.Bit16: Writer.Write("word "); length += 5; break; case DataSize.Bit32: Writer.Write("dword "); length += 6; break; case DataSize.Bit64: Writer.Write("qword "); length += 6; break; case DataSize.None: break; default: throw new LanguageException(ExceptionStrings.UnknownRequestedSize); } } string str = Enum.GetName(typeof(Register), operand.Register); length += str.Length; Writer.Write(str); return length; }
public bool MatchesFstswSequence() { var nextInstr = dasm.Peek(1); if (nextInstr.Mnemonic == Mnemonic.sahf) { this.len += nextInstr.Length; dasm.Skip(1); m.Assign( orw.FlagGroup(FlagM.ZF | FlagM.CF | FlagM.SF | FlagM.OF), orw.AluRegister(Registers.FPUF)); return(true); } if (nextInstr.Mnemonic == Mnemonic.test) { RegisterOperand acc = nextInstr.Operands[0] as RegisterOperand; ImmediateOperand imm = nextInstr.Operands[1] as ImmediateOperand; if (imm == null || acc == null) { return(false); } int mask = imm.Value.ToInt32(); if (acc.Register == Registers.ax || acc.Register == Registers.eax) { mask >>= 8; } else if (acc.Register != Registers.ah) { return(false); } this.len += nextInstr.Length; m.Assign( orw.FlagGroup(FlagM.ZF | FlagM.CF | FlagM.SF | FlagM.OF), orw.AluRegister(Registers.FPUF)); // Advance past the 'test' instruction. dasm.Skip(1); while (dasm.MoveNext()) { instrCur = dasm.Current; this.len += instrCur.Length; /* fcom/fcomp/fcompp Results: * Condition C3 C2 C0 * ST(0) > SRC 0 0 0 * ST(0) < SRC 0 0 1 * ST(0) = SRC 1 0 0 * Unordered 1 1 1 * * Masks: * Mask Flags * 0x01 C0 * 0x04 C2 * 0x40 C3 * 0x05 C2 and C0 * 0x41 C3 and C0 * 0x44 C3 and C2 * * Masks && jump operations: * Mnem Mask Condition * jpe 0x05 >= * jpe 0x41 > * jpe 0x44 != * jpo 0x05 < * jpo 0x41 <= * jpo 0x44 = * jz 0x01 >= * jz 0x40 != * jz 0x41 > * jnz 0x01 < * jnz 0x40 = * jnz 0x41 <= */ switch (instrCur.Mnemonic) { //$TODO The following instructions are being added on an ad-hoc // basis, since they don't affect the x86 flags register. // The long term fix is to implement an architecture-specific // condition code elimination pass as described elsewhere. case Mnemonic.mov: RewriteMov(); break; case Mnemonic.fstp: RewriteFst(true); break; case Mnemonic.push: RewritePush(); break; case Mnemonic.lea: RewriteLea(); break; case Mnemonic.jpe: if (mask == 0x05) { Branch(ConditionCode.GE, instrCur.Operands[0]); return(true); } if (mask == 0x41) { Branch(ConditionCode.GT, instrCur.Operands[0]); return(true); } if (mask == 0x44) { Branch(ConditionCode.NE, instrCur.Operands[0]); return(true); } throw new AddressCorrelatedException(instrCur.Address, "Unexpected {0} fstsw mask for {1} mnemonic.", mask, instrCur.Mnemonic); case Mnemonic.jpo: if (mask == 0x44) { Branch(ConditionCode.EQ, instrCur.Operands[0]); return(true); } if (mask == 0x41) { Branch(ConditionCode.LE, instrCur.Operands[0]); return(true); } if (mask == 0x05) { Branch(ConditionCode.LT, instrCur.Operands[0]); return(true); } throw new AddressCorrelatedException(instrCur.Address, "Unexpected {0} fstsw mask for {1} mnemonic.", mask, instrCur.Mnemonic); case Mnemonic.jz: if (mask == 0x40) { Branch(ConditionCode.NE, instrCur.Operands[0]); return(true); } if (mask == 0x41) { Branch(ConditionCode.GT, instrCur.Operands[0]); return(true); } if (mask == 0x01) { Branch(ConditionCode.GE, instrCur.Operands[0]); return(true); } throw new AddressCorrelatedException(instrCur.Address, "Unexpected {0} fstsw mask for {1} mnemonic.", mask, instrCur.Mnemonic); case Mnemonic.jnz: if (mask == 0x40) { Branch(ConditionCode.EQ, instrCur.Operands[0]); return(true); } if (mask == 0x41) { Branch(ConditionCode.LE, instrCur.Operands[0]); return(true); } if (mask == 0x01) { Branch(ConditionCode.LT, instrCur.Operands[0]); return(true); } throw new AddressCorrelatedException(instrCur.Address, "Unexpected {0} fstsw mask for {1} mnemonic.", mask, instrCur.Mnemonic); default: throw new AddressCorrelatedException(instrCur.Address, "Unexpected instruction {0} after fstsw", instrCur); } } throw new AddressCorrelatedException(instrCur.Address, "Expected branch instruction after fstsw;test {0},{1}.", acc.Register, imm.Value); } return(false); }
public CallPtrInstruction(IOperand target, RegisterOperand returnAddressTarget) { operands = returnAddressTarget == null ? new[] { target } : new[] { target, returnAddressTarget }; }
public void Lis(RegisterOperand r, ushort uimm) { Add(new PowerPcInstruction(Opcode.oris, r, r, new ImmediateOperand(Constant.Word16(uimm)), false)); }
public void Add_(RegisterOperand rT, RegisterOperand rA, RegisterOperand rB) { Add(new PowerPcInstruction(Opcode.add, rT, rA, rB, true)); }
public Identifier AluRegister(RegisterOperand reg) { return(binder.EnsureRegister(reg.Register)); }
public void Lwz(RegisterOperand rD, short offset, RegisterOperand rA) { Add(new PowerPcInstruction(Opcode.lwz, rD, new MemoryOperand(rD.Register.DataType, rA.Register, Constant.Int16(offset)), null, false)); }
public bool MatchesFstswSequence() { var nextInstr = dasm.Peek(1); if (nextInstr.code == Opcode.sahf) { ric.Length += (byte)nextInstr.Length; dasm.Skip(1); emitter.Assign( orw.FlagGroup(FlagM.ZF | FlagM.CF | FlagM.SF | FlagM.OF), orw.FlagGroup(FlagM.FPUF)); return(true); } if (nextInstr.code == Opcode.test) { RegisterOperand acc = nextInstr.op1 as RegisterOperand; ImmediateOperand imm = nextInstr.op2 as ImmediateOperand; if (imm == null || acc == null) { return(false); } int mask = imm.Value.ToInt32(); if (acc.Register == Registers.ax || acc.Register == Registers.eax) { mask >>= 8; } else if (acc.Register != Registers.ah) { return(false); } ric.Length += (byte)nextInstr.Length; dasm.Skip(1); emitter.Assign( orw.FlagGroup(FlagM.ZF | FlagM.CF | FlagM.SF | FlagM.OF), orw.FlagGroup(FlagM.FPUF)); if (!dasm.MoveNext()) { throw new AddressCorrelatedException(nextInstr.Address, "Expected instruction after fstsw;test {0},{1}.", acc.Register, imm.Value); } nextInstr = dasm.Current; ric.Length += (byte)nextInstr.Length; //var r = new RtlInstructionCluster(nextInstr.Address, nextInstr.Length); //r.Instructions.AddRange(ric.Instructions); //emitter = new RtlEmitter(r.Instructions); //ric = r; switch (nextInstr.code) { case Opcode.jpe: if (mask == 0x05) { Branch(ConditionCode.LE, nextInstr.op1); return(true); } if (mask == 0x41) { Branch(ConditionCode.GE, nextInstr.op1); return(true); } if (mask == 0x44) { Branch(ConditionCode.NE, nextInstr.op1); return(true); } break; case Opcode.jpo: if (mask == 0x44) { Branch(ConditionCode.EQ, nextInstr.op1); return(true); } if (mask == 0x41) { Branch(ConditionCode.GE, nextInstr.op1); return(true); } if (mask == 0x05) { Branch(ConditionCode.LT, nextInstr.op1); return(true); } break; case Opcode.jz: if (mask == 0x40) { Branch(ConditionCode.NE, nextInstr.op1); return(true); } if (mask == 0x41) { Branch(ConditionCode.LT, nextInstr.op1); return(true); } break; case Opcode.jnz: if (mask == 0x40) { Branch(ConditionCode.EQ, nextInstr.op1); return(true); } if (mask == 0x41) { Branch(ConditionCode.GE, nextInstr.op1); return(true); } if (mask == 0x01) { Branch(ConditionCode.GT, nextInstr.op1); return(true); } break; } return(false); } return(false); }
public void Stbux(RegisterOperand rS, RegisterOperand rA, RegisterOperand rB) { Add(new PowerPcInstruction(Opcode.stbux, rS, rA, rB, false)); }
/// <summary> /// Calculates the value of the modR/M byte and SIB bytes. /// </summary> /// <param name="regField">The modR/M regfield value.</param> /// <param name="op1">The destination operand.</param> /// <param name="op2">The source operand.</param> /// <param name="sib">A potential SIB byte to emit.</param> /// <param name="displacement">An immediate displacement to emit.</param> /// <returns>The value of the modR/M byte.</returns> private static byte?CalculateModRM(byte?regField, Operand op1, Operand op2, out byte?sib, out Operand displacement) { byte?modRM = null; displacement = null; // FIXME: Handle the SIB byte sib = null; RegisterOperand rop1 = op1 as RegisterOperand, rop2 = op2 as RegisterOperand; MemoryOperand mop1 = op1 as MemoryOperand, mop2 = op2 as MemoryOperand; // Normalize the operand order if (rop1 == null && rop2 != null) { // Swap the memory operands rop1 = rop2; rop2 = null; mop2 = mop1; mop1 = null; } if (regField != null) { modRM = (byte)(regField.Value << 3); } if (rop1 != null && rop2 != null) { // mod = 11b, reg = rop1, r/m = rop2 modRM = (byte)((3 << 6) | (rop1.Register.RegisterCode << 3) | rop2.Register.RegisterCode); } // Check for register/memory combinations else if (mop2 != null && mop2.Base != null) { // mod = 10b, reg = rop1, r/m = mop2 modRM = (byte)(modRM.GetValueOrDefault() | (2 << 6) | (byte)mop2.Base.RegisterCode); if (rop1 != null) { modRM |= (byte)(rop1.Register.RegisterCode << 3); } displacement = mop2; if (mop2.Base.RegisterCode == 4) { sib = 0xA4; } } else if (mop2 != null) { // mod = 10b, r/m = mop1, reg = rop2 modRM = (byte)(modRM.GetValueOrDefault() | 5); if (rop1 != null) { modRM |= (byte)(rop1.Register.RegisterCode << 3); } displacement = mop2; } else if (mop1 != null && mop1.Base != null) { // mod = 10b, r/m = mop1, reg = rop2 modRM = (byte)(modRM.GetValueOrDefault() | (2 << 6) | mop1.Base.RegisterCode); if (rop2 != null) { modRM |= (byte)(rop2.Register.RegisterCode << 3); } displacement = mop1; if (mop1.Base.RegisterCode == 4) { sib = 0xA4; } } else if (mop1 != null) { // mod = 10b, r/m = mop1, reg = rop2 modRM = (byte)(modRM.GetValueOrDefault() | 5); if (rop2 != null) { modRM |= (byte)(rop2.Register.RegisterCode << 3); } displacement = mop1; } else if (rop1 != null) { modRM = (byte)(modRM.GetValueOrDefault() | (3 << 6) | rop1.Register.RegisterCode); //if (op2 is SymbolOperand) // displacement = op2; } return(modRM); }
private MemoryOperand Mem(RegisterOperand baseReg, short offset) { return(new MemoryOperand(baseReg.Register.DataType, baseReg.Register, Constant.Int16(offset))); }
private bool TryParseOperandInner(ushort uInstr, byte addressMode, byte operandBits, PrimitiveType dataWidth, EndianImageReader rdr, out MachineOperand op) { Constant offset; switch (addressMode) { case 0: // Data register direct. op = DataRegisterOperand(operandBits, 0); return(true); case 1: // Address register direct op = new RegisterOperand(AddressRegister(operandBits, 0)); return(true); case 2: // Address register indirect op = MemoryOperand.Indirect(dataWidth, AddressRegister(operandBits, 0)); return(true); case 3: // Address register indirect with postincrement. op = MemoryOperand.PostIncrement(dataWidth, AddressRegister(operandBits, 0)); return(true); case 4: // Address register indirect with predecrement. op = MemoryOperand.PreDecrement(dataWidth, AddressRegister(operandBits, 0)); return(true); case 5: // Address register indirect with displacement. if (!rdr.TryReadBe(PrimitiveType.Int16, out offset)) { op = null; return(false); } op = MemoryOperand.Indirect(dataWidth, AddressRegister(operandBits, 0), offset); return(true); case 6: // Address register indirect with index return(TryAddressRegisterIndirectWithIndex(uInstr, dataWidth, rdr, out op)); case 7: switch (operandBits) { case 0: // Absolute short address ushort usAddr; if (!rdr.TryReadBeUInt16(out usAddr)) { op = null; return(false); } op = new M68kAddressOperand(usAddr); return(true); case 1: // Absolute long address uint uAddr; if (!rdr.TryReadBeUInt32(out uAddr)) { op = null; return(false); } op = new M68kAddressOperand(uAddr); return(true); case 2: // Program counter with displacement var off = rdr.Address - dasm.instr.Address; short sOffset; if (!rdr.TryReadBeInt16(out sOffset)) { op = null; return(false); } off += sOffset; op = new MemoryOperand(dataWidth, Registers.pc, Constant.Int16((short)off)); return(true); case 3: // Program counter with index var addrExt = rdr.Address; ushort extension; if (!rdr.TryReadBeUInt16(out extension)) { op = null; return(false); } if (EXT_FULL(extension)) { if (EXT_EFFECTIVE_ZERO(extension)) { op = new M68kImmediateOperand(Constant.Word32(0)); return(true); } Constant @base = null; Constant outer = null; if (EXT_BASE_DISPLACEMENT_PRESENT(extension)) { @base = EXT_BASE_DISPLACEMENT_LONG(extension) ? rdr.ReadBe(PrimitiveType.Word32) : rdr.ReadBe(PrimitiveType.Int16); } if (EXT_OUTER_DISPLACEMENT_PRESENT(extension)) { outer = EXT_OUTER_DISPLACEMENT_LONG(extension) ? rdr.ReadBe(PrimitiveType.Word32) : rdr.ReadBe(PrimitiveType.Int16); } RegisterStorage base_reg = EXT_BASE_REGISTER_PRESENT(extension) ? Registers.pc : null; RegisterStorage index_reg = null; PrimitiveType index_width = null; int index_scale = 0; if (EXT_INDEX_REGISTER_PRESENT(extension)) { index_reg = EXT_INDEX_AR(extension) ? Registers.AddressRegister((int)EXT_INDEX_REGISTER(extension)) : Registers.DataRegister((int)EXT_INDEX_REGISTER(extension)); index_width = EXT_INDEX_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Int16; index_scale = (EXT_INDEX_SCALE(extension) != 0) ? 1 << EXT_INDEX_SCALE(extension) : 0; } op = new IndexedOperand(dataWidth, @base, outer, base_reg, index_reg, index_width, index_scale, (extension & 7) > 0 && (extension & 7) < 4, (extension & 7) > 4); return(true); } op = new IndirectIndexedOperand( dataWidth, EXT_8BIT_DISPLACEMENT(extension), Registers.pc, EXT_INDEX_AR(extension) ? Registers.AddressRegister((int)EXT_INDEX_REGISTER(extension)) : Registers.DataRegister((int)EXT_INDEX_REGISTER(extension)), EXT_INDEX_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Int16, 1 << EXT_INDEX_SCALE(extension)); return(true); case 4: // Immediate if (dataWidth.Size == 1) // don't want the instruction stream to get misaligned! { rdr.Offset += 1; } Constant coff; if (!rdr.TryReadBe(dataWidth, out coff)) { op = null; return(false); } op = new M68kImmediateOperand(coff); return(true); default: op = null; return(false); } default: throw new NotImplementedException(string.Format("Address mode {0:X1} not implemented.", addressMode)); } }
/// <summary> /// Converts the given instruction from three address format to a two address format. /// </summary> /// <param name="ctx">The conversion context.</param> private static void ThreeTwoAddressConversion(Context ctx) { Operand result = ctx.Result; Operand op1 = ctx.Operand1; Operand op2 = ctx.Operand2; if (ctx.Instruction is IR.IntegerCompareInstruction || ctx.Instruction is IR.FloatingPointCompareInstruction || ctx.Instruction is IR.LoadInstruction || ctx.Instruction is IR.StoreInstruction) { return; } if (ctx.Instruction is CIL.MulInstruction) { if (!(op1 is ConstantOperand) && (op2 is ConstantOperand)) { Operand temp = op1; op1 = op2; op2 = temp; } } // Create registers for different data types RegisterOperand eax = new RegisterOperand(op1.Type, op1.StackType == StackTypeCode.F ? (Register)SSE2Register.XMM0 : GeneralPurposeRegister.EAX); RegisterOperand storeOperand = new RegisterOperand(result.Type, result.StackType == StackTypeCode.F ? (Register)SSE2Register.XMM0 : GeneralPurposeRegister.EAX); // RegisterOperand eaxL = new RegisterOperand(op1.Type, GeneralPurposeRegister.EAX); ctx.Result = storeOperand; ctx.Operand1 = op2; ctx.Operand2 = null; ctx.OperandCount = 1; if (op1.StackType != StackTypeCode.F) { if (IsSigned(op1) && !(op1 is ConstantOperand)) { ctx.InsertBefore().SetInstruction(IR.Instruction.SignExtendedMoveInstruction, eax, op1); } else if (IsUnsigned(op1) && !(op1 is ConstantOperand)) { ctx.InsertBefore().SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, eax, op1); } else { ctx.InsertBefore().SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1); } } else { if (op1.Type.Type == CilElementType.R4) { if (op1 is ConstantOperand) { Context before = ctx.InsertBefore(); before.SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1); before.AppendInstruction(CPUx86.Instruction.Cvtss2sdInstruction, eax, eax); } else { ctx.InsertBefore().SetInstruction(CPUx86.Instruction.Cvtss2sdInstruction, eax, op1); } } else { ctx.InsertBefore().SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1); } } ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, result, eax); }
/// <summary> /// Moves the return value to 32 bit. /// </summary> /// <param name="resultOperand">The result operand.</param> /// <param name="ctx">The context.</param> private static void MoveReturnValueTo32Bit(Operand resultOperand, Context ctx) { RegisterOperand eax = new RegisterOperand(resultOperand.Type, GeneralPurposeRegister.EAX); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, resultOperand, eax); }
private bool TryDecodeOperand(PrimitiveType width, out MachineOperand op) { op = null; byte b; byte bSpecifier; ushort w; uint dw; if (!rdr.TryReadByte(out bSpecifier)) { return(false); } var reg = arch.GetRegister(bSpecifier & 0xF); switch (bSpecifier >> 4) { case 0: // Literal mode case 1: case 2: case 3: op = LiteralOperand(width, bSpecifier); break; case 4: // Index mode op = IndexOperand(width, reg); break; case 5: // Register mode op = new RegisterOperand(reg); break; case 6: // Register deferred op = new MemoryOperand(width) { Base = reg }; break; case 7: // Autodecrement mode op = new MemoryOperand(width) { Base = reg, AutoDecrement = true, }; break; case 8: // Autoincrement mode if (reg.Number == 0x0F) { op = ImmediateOperand(width); } else { op = new MemoryOperand(width) { Base = reg, AutoIncrement = true, }; } break; case 9: // Deferred Autoincrement mode op = new MemoryOperand(width) { Base = reg, AutoIncrement = true, Deferred = true, }; break; case 0xA: // Displacement mode case 0xD: if (!rdr.TryReadByte(out b)) { return(false); } op = DisplacementOperand(width, reg, Constant.SByte((sbyte)b), bSpecifier); break; case 0xB: case 0xE: if (!rdr.TryReadUInt16(out w)) { return(false); } op = DisplacementOperand(width, reg, Constant.Int16((short)w), bSpecifier); break; case 0xC: case 0xF: if (!rdr.TryReadUInt32(out dw)) { return(false); } op = DisplacementOperand(width, reg, Constant.Word32(dw), bSpecifier); break; default: throw new InvalidCastException("Impossiburu!"); } return(true); }
/// <summary> /// Pushes the specified instructions. /// </summary> /// <param name="ctx">The context.</param> /// <param name="op">The op.</param> /// <param name="stackSize">Size of the stack.</param> private void Push(Context ctx, Operand op, int stackSize) { if (op is MemoryOperand) { RegisterOperand rop; switch (op.StackType) { case StackTypeCode.O: goto case StackTypeCode.N; case StackTypeCode.Ptr: goto case StackTypeCode.N; case StackTypeCode.Int32: goto case StackTypeCode.N; case StackTypeCode.N: rop = new RegisterOperand(op.Type, GeneralPurposeRegister.EAX); break; case StackTypeCode.F: rop = new RegisterOperand(op.Type, SSE2Register.XMM0); break; case StackTypeCode.Int64: { SigType I4 = new SigType(CilElementType.I4); MemoryOperand mop = op as MemoryOperand; Debug.Assert(null != mop, "I8/U8 arg is not in a memory operand."); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); Operand opL, opH; LongOperandTransformationStage.SplitLongOperand(mop, out opL, out opH); //MemoryOperand opL = new MemoryOperand(I4, mop.Base, mop.Offset); //MemoryOperand opH = new MemoryOperand(I4, mop.Base, new IntPtr(mop.Offset.ToInt64() + 4)); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opL); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), eax); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opH); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize + 4)), eax); } return; default: throw new NotSupportedException(); } ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, rop, op); op = rop; } else if (op is ConstantOperand && op.StackType == StackTypeCode.Int64) { Operand opL, opH; SigType I4 = new SigType(CilElementType.I4); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); LongOperandTransformationStage.SplitLongOperand(op, out opL, out opH); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opL); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(I4, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), eax); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opH); ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(I4, GeneralPurposeRegister.EDX, new IntPtr(stackSize + 4)), eax); return; } ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), op); }