public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { XS.ClearInterruptFlag(); XS.Set(XSRegisters.EAX, "_NATIVE_GDT_Pointer"); XS.LoadGdt(XSRegisters.EAX, isIndirect: true); XS.Set(XSRegisters.EAX, XSRegisters.CR0); XS.Or(XSRegisters.AL, 1); XS.Set(XSRegisters.CR0, XSRegisters.EAX); XS.JumpToSegment(0x08, "PMode"); XS.Label("PMode"); }
public static void SSEInit() { XS.Comment("BEGIN - SSE Init"); // CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 XS.Set(EAX, CR4); XS.Or(EAX, 0x100); XS.Set(CR4, EAX); XS.Set(EAX, CR4); XS.Or(EAX, 0x200); XS.Set(CR4, EAX); XS.Set(EAX, CR0); XS.And(EAX, 0xfffffffd); XS.Set(CR0, EAX); XS.Set(EAX, CR0); XS.And(EAX, 1); XS.Set(CR0, EAX); XS.Comment("END - SSE Init"); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackContent = aOpCode.StackPopTypes[0]; var xStackContentSecond = aOpCode.StackPopTypes[1]; var xStackContentSize = SizeOfType(xStackContent); var xStackContentSecondSize = SizeOfType(xStackContentSecond); var xSize = Math.Max(xStackContentSize, xStackContentSecondSize); if (ILOp.Align(xStackContentSize, 4u) != ILOp.Align(xStackContentSecondSize, 4u)) { throw new NotSupportedException("Operands have different size!"); } if (xSize > 8) { throw new NotImplementedException("StackSize>8 not supported"); } if (xSize > 4) { // [ESP] is low part // [ESP + 4] is high part // [ESP + 8] is low part // [ESP + 12] is high part XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EDX); // [ESP] is low part // [ESP + 4] is high part XS.Or(XSRegisters.ESP, XSRegisters.EAX, destinationIsIndirect: true); XS.Or(XSRegisters.ESP, XSRegisters.EDX, destinationDisplacement: 4); } else { XS.Pop(XSRegisters.EAX); XS.Or(XSRegisters.ESP, XSRegisters.EAX, destinationIsIndirect: true); } }
public static void DoExecute(uint xStackContentSize, bool xStackContentIsFloat, string aBaseLabel) { if (xStackContentSize > 4) { if (xStackContentIsFloat) { XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.MulSD(XMM1, XMM0); XS.SSE2.MoveSD(ESP, XMM1, destinationIsIndirect: true); } else { // div of both == LEFT_LOW * RIGHT_LOW + ((LEFT_LOW * RIGHT_HIGH + RIGHT_LOW * LEFT_HIGH) << 32) string Simple32Multiply = aBaseLabel + "Simple32Multiply"; string MoveReturnValue = aBaseLabel + "MoveReturnValue"; // right value // low // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true // high // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 4 // left value // low // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 8 // high // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 12 // compair LEFT_HIGH, RIGHT_HIGH , on zero only simple multiply is used //mov RIGHT_HIGH to eax, is useable on Full 64 multiply XS.Set(EAX, ESP, sourceDisplacement: 4); XS.Or(EAX, ESP, sourceDisplacement: 12); XS.Jump(CPUx86.ConditionalTestEnum.Zero, Simple32Multiply); // Full 64 Multiply // copy again, or could change EAX //TODO is there an opcode that does OR without change EAX? XS.Set(EAX, ESP, sourceDisplacement: 4); // eax contains already RIGHT_HIGH // multiply with LEFT_LOW XS.Multiply(ESP, displacement: 8); // save result of LEFT_LOW * RIGHT_HIGH XS.Set(ECX, EAX); //mov RIGHT_LOW to eax XS.Set(EAX, ESP, sourceIsIndirect: true); // multiply with LEFT_HIGH XS.Multiply(ESP, displacement: 12); // add result of LEFT_LOW * RIGHT_HIGH + RIGHT_LOW + LEFT_HIGH XS.Add(ECX, EAX); //mov RIGHT_LOW to eax XS.Set(EAX, ESP, sourceIsIndirect: true); // multiply with LEFT_LOW XS.Multiply(ESP, displacement: 8); // add LEFT_LOW * RIGHT_HIGH + RIGHT_LOW + LEFT_HIGH to high dword of last result XS.Add(EDX, ECX); XS.Jump(MoveReturnValue); XS.Label(Simple32Multiply); //mov RIGHT_LOW to eax XS.Set(EAX, ESP, sourceIsIndirect: true); // multiply with LEFT_LOW XS.Multiply(ESP, displacement: 8); XS.Label(MoveReturnValue); // move high result to left high XS.Set(ESP, EDX, destinationDisplacement: 12); // move low result to left low XS.Set(ESP, EAX, destinationDisplacement: 8); // pop right 64 value XS.Add(ESP, 8); } } else { if (xStackContentIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.MulSS(XMM1, XMM0); XS.SSE.MoveSS(ESP, XMM1, destinationIsIndirect: true); } else { XS.Pop(EAX); XS.Multiply(ESP, isIndirect: true, size: RegisterSize.Int32); XS.Add(ESP, 4); XS.Push(EAX); } } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xSize = Math.Max(xStackItemSize, SizeOfType(aOpCode.StackPopTypes[1])); if (xSize > 4) { if (TypeIsFloat(xStackItem)) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 8); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.XorPS(XMM2, XMM2); XS.SSE.DivPS(XMM1, XMM0); XS.SSE.MoveSS(ESP, XMM2, destinationIsIndirect: true); } else { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor //low XS.Set(ESI, ESP, sourceIsIndirect: true); //high XS.Set(XSRegisters.EDI, XSRegisters.ESP, sourceDisplacement: 4); //dividend // low XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 8); //high XS.Set(XSRegisters.EDX, XSRegisters.ESP, sourceDisplacement: 12); // pop both 8 byte values XS.Add(XSRegisters.ESP, 16); // set flags XS.Or(XSRegisters.EDI, XSRegisters.EDI); // if high dword of divisor is already zero, we dont need the loop XS.Jump(CPUx86.ConditionalTestEnum.Zero, LabelNoLoop); // set ecx to zero for counting the shift operations XS.Xor(XSRegisters.ECX, XSRegisters.ECX); XS.Label(LabelShiftRight); // shift divisor 1 bit right XS.ShiftRightDouble(ESI, EDI, 1); XS.ShiftRight(XSRegisters.EDI, 1); // increment shift counter XS.Increment(XSRegisters.ECX); // set flags XS.Or(XSRegisters.EDI, XSRegisters.EDI); // loop while high dword of divisor till it is zero XS.Jump(CPUx86.ConditionalTestEnum.NotZero, LabelShiftRight); // shift the divident now in one step // shift divident CL bits right XS.ShiftRightDouble(EAX, EDX, CL); XS.ShiftRight(XSRegisters.EDX, CL); // so we shifted both, so we have near the same relation as original values // divide this XS.Divide(XSRegisters.ESI); // save remainder to stack XS.Push(0); XS.Push(XSRegisters.EDX); //TODO: implement proper derivation correction and overflow detection XS.Jump(LabelEnd); XS.Label(LabelNoLoop); //save high dividend XS.Set(XSRegisters.ECX, XSRegisters.EAX); XS.Set(XSRegisters.EAX, XSRegisters.EDX); // zero EDX, so that high part is zero -> reduce overflow case XS.Xor(XSRegisters.EDX, XSRegisters.EDX); // divide high part XS.Divide(XSRegisters.ESI); XS.Set(XSRegisters.EAX, XSRegisters.ECX); // divide low part XS.Divide(XSRegisters.ESI); // save remainder result XS.Push(0); XS.Push(XSRegisters.EDX); XS.Label(LabelEnd); } } else { if (TypeIsFloat(xStackItem)) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.XorPS(XMM2, XMM2); XS.SSE.DivPS(XMM1, XMM0); XS.Sub(XSRegisters.ESP, 4); XS.SSE.MoveSS(ESP, XMM2, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.ECX); XS.Pop(XSRegisters.EAX); // gets devised by ecx XS.Xor(XSRegisters.EDX, XSRegisters.EDX); XS.Divide(XSRegisters.ECX); // => EAX / ECX XS.Push(XSRegisters.EDX); } } }
public static void Assemble(Assembler aAssembler, _MethodInfo aMethod, OpMethod xMethod, string currentLabel, Type objectType, MethodBase constructor) { // call cctor: if (aMethod != null) { var xCctor = (objectType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? Array.Empty <ConstructorInfo>()).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } } if (objectType.IsValueType) { #region Valuetypes XS.Comment("ValueType"); XS.Comment("Type: " + objectType); /* * Current sitation on stack: * $ESP Arg * $ESP+.. other items * * What should happen: * + The stack should be increased to allow space to contain: * + .ctor arguments * + struct _pointer_ (ref to start of emptied space) * + empty space for struct * + arguments should be copied to the new place * + old place where arguments were should be cleared * + pointer should be set * + call .ctor */ // Size of return value - we need to make room for this on the stack. uint xStorageSize = Align(SizeOfType(objectType), 4); XS.Comment("StorageSize: " + xStorageSize); if (xStorageSize == 0) { throw new Exception("ValueType storage size cannot be 0."); } uint xArgSize = 0; var xParameterList = constructor.GetParameters(); foreach (var xParam in xParameterList) { xArgSize = xArgSize + Align(SizeOfType(xParam.ParameterType), 4); } XS.Comment("ArgSize: " + xArgSize); // set source of args copy XS.Set(ESI, ESP); // allocate space for struct XS.Sub(ESP, xStorageSize + 4); // set destination and count of args copy XS.Set(EDI, ESP); XS.Set(ECX, xArgSize / 4); // move the args to their new location new CPUx86.Movs { Size = 32, Prefixes = CPUx86.InstructionPrefixes.Repeat }; // set struct ptr XS.Set(EAX, ESP); XS.Add(EAX, xArgSize + 4); XS.Set(ESP, EAX, destinationDisplacement: (int)xArgSize); XS.Push(EAX); var xOpType = new OpType(xMethod.OpCode, xMethod.Position, xMethod.NextPosition, xMethod.Value.DeclaringType, xMethod.CurrentExceptionRegion); new Initobj(aAssembler).Execute(aMethod, xOpType); new Call(aAssembler).Execute(aMethod, xMethod); // Need to put these *after* the call because the Call pops the args from the stack // and we have mucked about on the stack, so this makes it right before the next // op. #endregion Valuetypes } else { // If not ValueType, then we need gc var xParams = constructor.GetParameters(); // array length + 8 bool xHasCalcSize = false; #region Special string handling // try calculating size: if (constructor.DeclaringType == typeof(string)) { if (xParams.Length == 1 && xParams[0].ParameterType == typeof(char[])) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceDisplacement: 4, sourceIsIndirect: true); // address XS.Set(EAX, EAX, sourceDisplacement: 8, sourceIsIndirect: true); // element count XS.Set(EDX, 2); // element size XS.Multiply(EDX); XS.Push(EAX); } else if (xParams.Length == 3 && (xParams[0].ParameterType == typeof(char[]) || xParams[0].ParameterType == typeof(char *)) && xParams[1].ParameterType == typeof(int) && xParams[2].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(EAX, 1); XS.Push(EAX); } else if (xParams.Length == 2 && xParams[0].ParameterType == typeof(char) && xParams[1].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(EAX, 1); XS.Push(EAX); } /* * TODO see if something is needed in stack / register to make them really work */ else if (xParams.Length == 3 && (xParams[0].ParameterType == typeof(sbyte *) && xParams[1].ParameterType == typeof(int) && xParams[2].ParameterType == typeof(int))) { xHasCalcSize = true; XS.Push(ESP, isIndirect: true); } else if (xParams.Length == 1 && xParams[0].ParameterType == typeof(sbyte *)) { xHasCalcSize = true; /* xParams[0] contains a C / ASCII Z string the following ASM is de facto the C strlen() function */ var xSByteCountLabel = currentLabel + ".SByteCount"; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.Or(ECX, 0xFFFFFFFF); XS.Label(xSByteCountLabel); XS.Increment(EAX); XS.Increment(ECX); XS.Compare(EAX, 0, destinationIsIndirect: true); XS.Jump(CPUx86.ConditionalTestEnum.NotEqual, xSByteCountLabel); XS.Push(ECX); } else { throw new NotImplementedException("In NewObj, a string ctor implementation is missing!"); } } #endregion Special string handling uint xMemSize = GetStorageSize(objectType); int xExtraSize = 12; // additional size for set values after alloc XS.Push((uint)(xMemSize + xExtraSize)); if (xHasCalcSize) { XS.Pop(EAX); XS.Add(ESP, EAX, destinationIsIndirect: true); } // todo: probably we want to check for exceptions after calling Alloc XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack now 3 times. Once from the Alloc return value, twice from the pushes // todo: use a cleaner approach here. this class shouldnt assemble the string string strTypeId = GetTypeIDLabel(constructor.DeclaringType); XS.Pop(EAX); XS.Set(EBX, strTypeId, sourceIsIndirect: true); XS.Set(EAX, EBX, destinationIsIndirect: true); XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.NormalObject, destinationDisplacement: 4, destinationIsIndirect: true, size: RegisterSize.Int32); XS.Set(EAX, xMemSize, destinationDisplacement: 8, destinationIsIndirect: true, size: RegisterSize.Int32); uint xSize = (uint)(from item in xParams let xQSize = Align(SizeOfType(item.ParameterType), 4) select(int) xQSize).Take(xParams.Length).Sum(); XS.Push(0); foreach (var xParam in xParams) { uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4); XS.Comment($"Arg {xParam.Name}: {xParamSize}"); for (int i = 0; i < xParamSize; i += 4) { XS.Push(ESP, isIndirect: true, displacement: (int)(xSize + 8)); } } XS.Call(LabelName.Get(constructor)); // should the complete error handling happen by ILOp.EmitExceptionLogic? if (aMethod != null) { // todo: only happening for real methods now, not for ctor's ? XS.Test(ECX, 2); string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString(); XS.Jump(CPUx86.ConditionalTestEnum.Equal, xNoErrorLabel); PushAlignedParameterSize(constructor); // an exception occurred, we need to cleanup the stack, and jump to the exit XS.Add(ESP, 4); new Comment(aAssembler, "[ Newobj.Execute cleanup end ]"); Jump_Exception(aMethod); XS.Label(xNoErrorLabel); } XS.Pop(EAX); PushAlignedParameterSize(constructor); XS.Push(EAX); XS.Push(0); } }
public override void AssembleNew(object aAssembler, object aMethodInfo) { XS.Mov(XSRegisters.BL, 0xa8); XS.Call("send_mouse_cmd"); XS.Call("mouse_read"); XS.Noop(); XS.Mov(XSRegisters.BL, 0x20); XS.Call("send_mouse_cmd"); XS.Call("mouse_read"); XS.Or(XSRegisters.AL, 3); XS.Mov(XSRegisters.BL, 0x60); XS.Push(XSRegisters.EAX); XS.Call("send_mouse_cmd"); XS.Pop(XSRegisters.EAX); XS.Call("mouse_write"); XS.Noop(); XS.Mov(XSRegisters.BL, 0xd4); XS.Call("send_mouse_cmd"); XS.Mov(XSRegisters.AL, 0xf4); XS.Call("mouse_write"); XS.Call("mouse_read"); #region mouse_read XS.Label("mouse_read"); { XS.Push(XSRegisters.ECX); XS.Push(XSRegisters.EDX); XS.Mov(XSRegisters.ECX, 0xffff); XS.Label("mouse_read_loop"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 1); XS.Jump(ConditionalTestEnum.NotZero, "mouse_read_ready"); new Loop { DestinationLabel = "mouse_read_loop" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_read_exit"); } XS.Label("mouse_read_ready"); { XS.Push(XSRegisters.ECX); XS.Mov(XSRegisters.ECX, 32); } XS.Label("mouse_read_delay"); { new Loop { DestinationLabel = "mouse_read_delay" }; XS.Pop(XSRegisters.ECX); new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x60, Size = 8 }; XS.Xor(XSRegisters.AH, XSRegisters.RegistersEnum.AH); } XS.Label("mouse_read_exit"); { XS.Pop(XSRegisters.EDX); XS.Pop(XSRegisters.ECX); XS.Return(); } } #endregion #region mouse_write XS.Label("mouse_write"); { XS.Push(XSRegisters.ECX); XS.Push(XSRegisters.EDX); XS.Mov(XSRegisters.BH, XSRegisters.RegistersEnum.AL); XS.Mov(XSRegisters.ECX, 0xffff); XS.Label("mouse_write_loop1"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 32); XS.Jump(ConditionalTestEnum.Zero, "mouse_write_ok1"); new Loop { DestinationLabel = "mouse_write_loop1" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_write_exit"); } XS.Label("mouse_write_ok1"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x60, Size = 8 }; XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_write_loop"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 2); XS.Jump(ConditionalTestEnum.Zero, "mouse_write_ok"); new Loop { DestinationLabel = "mouse_write_loop" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_write_exit"); } XS.Label("mouse_write_ok"); { XS.Mov(XSRegisters.AL, XSRegisters.RegistersEnum.BH); new Out2Port { DestinationValue = 0x60, SourceReg = RegistersEnum.AL, Size = 8 }; XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_write_loop3"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 2); XS.Jump(ConditionalTestEnum.Zero, "mouse_write_ok3"); new Loop { DestinationLabel = "mouse_write_loop3" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_write_exit"); } XS.Label("mouse_write_ok3"); { XS.Mov(XSRegisters.AH, 0x08); } XS.Label("mouse_write_loop4"); { XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_write_loop5"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 1); XS.Jump(ConditionalTestEnum.NotZero, "mouse_write_ok4"); new Loop { DestinationLabel = "mouse_write_loop5" }; XS.Dec(XSRegisters.AH); XS.Jump(ConditionalTestEnum.NotZero, "mouse_write_loop4"); } XS.Label("mouse_write_ok4"); { XS.Xor(XSRegisters.AH, XSRegisters.RegistersEnum.AH); } XS.Label("mouse_write_exit"); { XS.Pop(XSRegisters.EDX); XS.Pop(XSRegisters.ECX); XS.Return(); } } #endregion #region send_mouse_cmd XS.Label("send_mouse_cmd"); { XS.Mov(XSRegisters.ECX, 0xffff); XS.Label("mouse_cmd_wait"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 2); XS.Jump(ConditionalTestEnum.Zero, "mouse_cmd_send"); new Loop { DestinationLabel = "mouse_cmd_wait" }; XS.Jump("mouse_cmd_error"); } XS.Label("mouse_cmd_send"); { XS.Mov(XSRegisters.AL, XSRegisters.RegistersEnum.BL); new Out2Port { #if DebugMouse SourceValue = 0x64, DestinationReg = RegistersEnum.AL, #else DestinationValue = 0x64, SourceReg = RegistersEnum.AL, #endif Size = 8 }; XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_cmd_accept"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 0x02); XS.Jump(ConditionalTestEnum.Zero, "mouse_cmd_ok"); new Loop { DestinationLabel = "mouse_cmd_accept" }; } XS.Label("mouse_cmd_error"); { XS.Mov(XSRegisters.AH, 0x01); XS.Jump("mouse_cmd_exit"); } XS.Label("mouse_cmd_ok"); { XS.Xor(XSRegisters.AH, XSRegisters.RegistersEnum.AH); } XS.Label("mouse_cmd_exit"); { XS.Return(); } } #endregion }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItem2 = aOpCode.StackPopTypes[1]; var xStackItem2Size = SizeOfType(xStackItem2); if (xStackItemSize == 8) { // there seem to be an error in MS documentation, there is pushed an int32, but IL shows else if (xStackItem2Size != 8) { throw new Exception("Cosmos.IL2CPU.x86->IL->Div.cs->Error: Expected a size of 8 for Div!"); } if (TypeIsFloat(xStackItem)) { // TODO add 0/0 infinity/infinity X/infinity // value 1 new CPUx86.x87.FloatLoad { DestinationReg = CPUx86.RegistersEnum.ESP, Size = 64, DestinationIsIndirect = true, DestinationDisplacement = 8 }; // value 2 new CPUx86.x87.FloatDivide { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, Size = 64 }; // override value 1 new CPUx86.x87.FloatStoreAndPop { DestinationReg = CPUx86.RegistersEnum.ESP, Size = 64, DestinationIsIndirect = true, DestinationDisplacement = 8 }; // pop value 2 XS.Add(XSRegisters.ESP, 8); } else { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor //low XS.Set(ESI, ESP, sourceIsIndirect: true); //high XS.Set(XSRegisters.EDI, XSRegisters.ESP, sourceDisplacement: 4); //dividend // low XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 8); //high XS.Set(XSRegisters.EDX, XSRegisters.ESP, sourceDisplacement: 12); // pop both 8 byte values XS.Add(XSRegisters.ESP, 16); // set flags XS.Or(XSRegisters.EDI, XSRegisters.EDI); // if high dword of divisor is already zero, we dont need the loop XS.Jump(CPUx86.ConditionalTestEnum.Zero, LabelNoLoop); // set ecx to zero for counting the shift operations XS.Xor(XSRegisters.ECX, XSRegisters.ECX); XS.Label(LabelShiftRight); // shift divisor 1 bit right XS.ShiftRightDouble(ESI, EDI, 1); XS.ShiftRight(XSRegisters.EDI, 1); // increment shift counter XS.Increment(XSRegisters.ECX); // set flags XS.Or(XSRegisters.EDI, XSRegisters.EDI); // loop while high dword of divisor till it is zero XS.Jump(CPUx86.ConditionalTestEnum.NotZero, LabelShiftRight); // shift the divident now in one step // shift divident CL bits right XS.ShiftRightDouble(EAX, EDX, CL); XS.ShiftRight(XSRegisters.EDX, CL); // so we shifted both, so we have near the same relation as original values // divide this XS.Divide(XSRegisters.ESI); // save result to stack XS.Push(0); XS.Push(XSRegisters.EAX); //TODO: implement proper derivation correction and overflow detection XS.Jump(LabelEnd); XS.Label(LabelNoLoop); //save high dividend XS.Set(XSRegisters.ECX, XSRegisters.EAX); XS.Set(XSRegisters.EAX, XSRegisters.EDX); // zero EDX, so that high part is zero -> reduce overflow case XS.Xor(XSRegisters.EDX, XSRegisters.EDX); // divide high part XS.Divide(XSRegisters.ESI); // save high result XS.Push(XSRegisters.EAX); XS.Set(XSRegisters.EAX, XSRegisters.ECX); // divide low part XS.Divide(XSRegisters.ESI); // save low result XS.Push(XSRegisters.EAX); XS.Label(LabelEnd); } } else { if (TypeIsFloat(xStackItem)) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.MulSS(XMM0, XMM1); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); } else { XS.Xor(XSRegisters.EDX, XSRegisters.EDX); XS.Pop(XSRegisters.ECX); XS.Pop(XSRegisters.EAX); XS.Divide(XSRegisters.ECX); XS.Push(XSRegisters.EAX); } } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItem2 = aOpCode.StackPopTypes[0]; var xStackItem2Size = SizeOfType(xStackItem2); if (xStackItemSize == 8) { // there seem to be an error in MS documentation, there is pushed an int32, but IL shows else if (xStackItem2Size != 8) { throw new Exception("Cosmos.IL2CPU.x86->IL->Div.cs->Error: Expected a size of 8 for Div!"); } if (TypeIsFloat(xStackItem)) { XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.DivSD(XMM1, XMM0); XS.SSE2.MoveSD(ESP, XMM1, destinationIsIndirect: true); } else { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor //low XS.Set(ESI, ESP, sourceIsIndirect: true); //high XS.Set(EDI, ESP, sourceDisplacement: 4); // pop both 8 byte values XS.Add(ESP, 8); //dividend // low XS.Set(EAX, ESP, sourceIsIndirect: true); //high XS.Set(EDX, ESP, sourceDisplacement: 4); XS.Add(ESP, 8); // set flags XS.Or(EDI, EDI); // if high dword of divisor is already zero, we dont need the loop XS.Jump(CPUx86.ConditionalTestEnum.Zero, LabelNoLoop); // set ecx to zero for counting the shift operations XS.Xor(ECX, ECX); XS.Label(LabelShiftRight); // shift divisor 1 bit right XS.ShiftRightDouble(ESI, EDI, 1); XS.ShiftRight(EDI, 1); // increment shift counter XS.Increment(ECX); // set flags XS.Or(EDI, EDI); // loop while high dword of divisor till it is zero XS.Jump(CPUx86.ConditionalTestEnum.NotZero, LabelShiftRight); // shift the divident now in one step // shift divident CL bits right XS.ShiftRightDouble(EAX, EDX, CL); XS.ShiftRight(EDX, CL); // so we shifted both, so we have near the same relation as original values // divide this XS.IntegerDivide(ESI); // sign extend XS.SignExtendAX(RegisterSize.Int32); // save result to stack XS.Push(EDX); XS.Push(EAX); //TODO: implement proper derivation correction and overflow detection XS.Jump(LabelEnd); XS.Label(LabelNoLoop); //save high dividend XS.Set(ECX, EAX); XS.Set(EAX, EDX); // extend that sign is in edx XS.SignExtendAX(RegisterSize.Int32); // divide high part XS.IntegerDivide(ESI); // save high result XS.Push(EAX); XS.Set(EAX, ECX); // divide low part XS.Divide(ESI); // save low result XS.Push(EAX); XS.Label(LabelEnd); } } else { if (TypeIsFloat(xStackItem)) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.DivSS(XMM1, XMM0); XS.SSE.MoveSS(ESP, XMM1, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.ECX); XS.Pop(XSRegisters.EAX); XS.SignExtendAX(RegisterSize.Int32); XS.IntegerDivide(XSRegisters.ECX); XS.Push(XSRegisters.EAX); } } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xSize = Math.Max(SizeOfType(xStackItem), SizeOfType(aOpCode.StackPopTypes[1])); var xIsFloat = TypeIsFloat(xStackItem); var xBaseLabel = GetLabel(aMethod, aOpCode); var xNoDivideByZeroExceptionLabel = xBaseLabel + "_NoDivideByZeroException"; if (xSize > 8) { throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Div.cs->Error: StackSize > 8 not supported"); } else if (xSize > 4) { if (xIsFloat) { XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.DivSD(XMM1, XMM0); XS.SSE2.MoveSD(ESP, XMM1, destinationIsIndirect: true); } else { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor // low XS.Pop(ESI); // high XS.Pop(EDI); XS.Xor(EAX, EAX); XS.Or(EAX, ESI); XS.Or(EAX, EDI); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); // dividend // low XS.Pop(EAX); // high XS.Pop(EDX); // set flags XS.Or(EDI, EDI); // if high dword of divisor is already zero, we dont need the loop XS.Jump(ConditionalTestEnum.Zero, LabelNoLoop); // set ecx to zero for counting the shift operations XS.Xor(ECX, ECX); // push most significant bit of result XS.Set(EBX, EDI); XS.Xor(EBX, EDX); XS.Push(EBX); XS.Compare(EDI, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "divisor_no_neg"); XS.Negate(ESI); XS.AddWithCarry(EDI, 0); XS.Negate(EDI); XS.Label(BaseLabel + "divisor_no_neg"); XS.Compare(EDX, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "dividend_no_neg"); XS.Negate(EAX); XS.AddWithCarry(EDX, 0); XS.Negate(EDX); XS.Label(BaseLabel + "dividend_no_neg"); XS.Label(LabelShiftRight); // shift divisor 1 bit right XS.ShiftRightDouble(ESI, EDI, 1); XS.ShiftRight(EDI, 1); // increment shift counter XS.Increment(ECX); // set flags //XS.Or(EDI, EDI); XS.Set(EBX, ESI); XS.And(EBX, 0x80000000); XS.Or(EBX, EDI); // loop while high dword of divisor is not zero or most significant bit of low dword of divisor is set XS.Jump(ConditionalTestEnum.NotZero, LabelShiftRight); // shift the dividend now in one step XS.ShiftRightDouble(EAX, EDX, CL); // shift dividend CL bits right XS.ShiftRight(EDX, CL); // so we shifted both, so we have near the same relation as original values // divide this XS.IntegerDivide(ESI); // pop most significant bit of result XS.Pop(EBX); XS.Compare(EBX, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "_result_no_neg"); XS.Negate(EAX); XS.Label(BaseLabel + "_result_no_neg"); // sign extend XS.SignExtendAX(RegisterSize.Int32); // save result to stack XS.Push(EDX); XS.Push(EAX); //TODO: implement proper derivation correction and overflow detection XS.Jump(LabelEnd); XS.Label(LabelNoLoop); // save high dividend XS.Set(ECX, EAX); XS.Set(EAX, EDX); // extend that sign is in edx XS.SignExtendAX(RegisterSize.Int32); // divide high part XS.IntegerDivide(ESI); // save high result XS.Push(EAX); XS.Set(EAX, ECX); // divide low part XS.Divide(ESI); // save low result XS.Push(EAX); XS.Label(LabelEnd); } } else { if (xIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.DivSS(XMM1, XMM0); XS.SSE.MoveSS(ESP, XMM1, destinationIsIndirect: true); } else { XS.Pop(ECX); XS.Test(ECX, ECX); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); XS.Pop(EAX); XS.SignExtendAX(RegisterSize.Int32); XS.IntegerDivide(ECX); XS.Push(EAX); } } }
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { XS.Mov(XSRegisters.EAX, XSRegisters.CPUx86.Registers.CR0); XS.Or(XSRegisters.EAX, 0x80000000); XS.Mov(XSRegisters.CR0, XSRegisters.CPUx86.Registers.EAX); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xSize = Math.Max(SizeOfType(xStackItem), SizeOfType(aOpCode.StackPopTypes[1])); var xBaseLabel = GetLabel(aMethod, aOpCode); var xNoDivideByZeroExceptionLabel = xBaseLabel + "_NoDivideByZeroException"; if (TypeIsFloat(xStackItem)) { throw new Exception("Cosmos.IL2CPU.x86->IL->Div_Un.cs->Error: Expected unsigned integer operands but got float!"); } if (xSize > 8) { throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Div_Un.cs->Error: StackSize > 8 not supported"); } else if (xSize > 4) { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor // low XS.Pop(ESI); // high XS.Pop(EDI); XS.Xor(EAX, EAX); XS.Or(EAX, ESI); XS.Or(EAX, EDI); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); // dividend // low XS.Pop(EAX); // high XS.Pop(EDX); // set flags XS.Or(EDI, EDI); // if high dword of divisor is already zero, we dont need the loop XS.Jump(ConditionalTestEnum.Zero, LabelNoLoop); // set ecx to zero for counting the shift operations XS.Xor(ECX, ECX); XS.Label(LabelShiftRight); // shift divisor 1 bit right XS.ShiftRightDouble(ESI, EDI, 1); XS.ShiftRight(EDI, 1); // increment shift counter XS.Increment(ECX); // set flags XS.Or(EDI, EDI); // loop while high dword of divisor till it is zero XS.Jump(ConditionalTestEnum.NotZero, LabelShiftRight); // shift the dividend now in one step // shift dividend CL bits right XS.ShiftRightDouble(EAX, EDX, CL); XS.ShiftRight(EDX, CL); // so we shifted both, so we have near the same relation as original values // divide this XS.Divide(ESI); // save result to stack XS.Push(0); XS.Push(EAX); //TODO: implement proper derivation correction and overflow detection XS.Jump(LabelEnd); XS.Label(LabelNoLoop); //save high dividend XS.Set(ECX, EAX); XS.Set(EAX, EDX); // zero EDX, so that high part is zero -> reduce overflow case XS.Xor(EDX, EDX); // divide high part XS.Divide(ESI); // save high result XS.Push(EAX); XS.Set(EAX, ECX); // divide low part XS.Divide(ESI); // save low result XS.Push(EAX); XS.Label(LabelEnd); } else { XS.Pop(ECX); XS.Test(ECX, ECX); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); XS.Pop(EAX); XS.Xor(EDX, EDX); XS.Divide(ECX); XS.Push(EAX); } }