protected void SetIdtDescriptor(int aNo, string aLabel, bool aDisableInts) { int xOffset = aNo * 8; XS.Set(XSRegisters.EAX, aLabel); var xIDT = ElementReference.New("_NATIVE_IDT_Contents"); new Mov { DestinationRef = xIDT, DestinationIsIndirect = true, DestinationDisplacement = xOffset, SourceReg = RegistersEnum.AL }; new Mov { DestinationRef = xIDT, DestinationIsIndirect = true, DestinationDisplacement = xOffset + 1, SourceReg = RegistersEnum.AH }; XS.ShiftRight(XSRegisters.EAX, 16); new Mov { DestinationRef = xIDT, DestinationIsIndirect = true, DestinationDisplacement = xOffset + 6, SourceReg = RegistersEnum.AL }; new Mov { DestinationRef = xIDT, DestinationIsIndirect = true, DestinationDisplacement = xOffset + 7, SourceReg = RegistersEnum.AH }; // Code Segment new Mov { DestinationRef = xIDT, DestinationIsIndirect = true, DestinationDisplacement = xOffset + 2, SourceValue = mGdCode, Size = 16 }; // Reserved new Mov { DestinationRef = xIDT, DestinationIsIndirect = true, DestinationDisplacement = xOffset + 4, SourceValue = 0x00, Size = 8 }; // Type new Mov { DestinationRef = xIDT, DestinationIsIndirect = true, DestinationDisplacement = xOffset + 5, SourceValue = (byte)(aDisableInts ? 0x8E : 0x8F), Size = 8 }; }
public void CreateIDT() { new Comment(this, "BEGIN - Create IDT"); // Create IDT UInt16 xIdtSize = 8 * 256; DataMembers.Add(new DataMember("_NATIVE_IDT_Contents", new byte[xIdtSize])); // if (mComPort > 0) { SetIdtDescriptor(1, "DebugStub_TracerEntry", false); SetIdtDescriptor(3, "DebugStub_TracerEntry", false); //for (int i = 0; i < 256; i++) //{ // if (i == 1 || i == 3) // { // continue; // } // SetIdtDescriptor(i, "DebugStub_Interrupt_" + i.ToString(), true); //} } //SetIdtDescriptor(1, "DebugStub_INT0"); - Change to GPF // Set IDT DataMembers.Add(new DataMember("_NATIVE_IDT_Pointer", new UInt16[] { xIdtSize, 0, 0 })); new Mov { DestinationRef = Cosmos.Assembler.ElementReference.New("_NATIVE_IDT_Pointer"), DestinationIsIndirect = true, DestinationDisplacement = 2, SourceRef = Cosmos.Assembler.ElementReference.New("_NATIVE_IDT_Contents") }; new Mov { DestinationReg = Registers.EAX, SourceRef = Cosmos.Assembler.ElementReference.New("_NATIVE_IDT_Pointer") }; if (mComPort > 0) { new Mov { DestinationRef = ElementReference.New("static_field__Cosmos_Core_CPU_mInterruptsEnabled"), DestinationIsIndirect = true, SourceValue = 1 }; new Lidt { DestinationReg = Registers.EAX, DestinationIsIndirect = true }; } new Label("AfterCreateIDT"); new Comment(this, "END - Create IDT"); }
private static void Do <T>(string destination, UInt32 value, bool destinationIsIndirect = false, int?destinationDisplacement = null, bool sourceIsIndirect = false, int?sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) where T : InstructionWithDestinationAndSourceAndSize, new() { if (destinationDisplacement != null) { destinationIsIndirect = true; if (destinationDisplacement == 0) { destinationDisplacement = null; } } if (sourceDisplacement != null) { sourceIsIndirect = true; if (sourceDisplacement == 0) { sourceDisplacement = null; } } if (destinationIsIndirect && sourceIsIndirect) { throw new Exception("Both destination and source cannot be indirect!"); } new T { Size = (byte)size, DestinationRef = ElementReference.New(destination), DestinationIsIndirect = destinationIsIndirect, DestinationDisplacement = destinationDisplacement, SourceValue = value, SourceIsIndirect = sourceIsIndirect, SourceDisplacement = sourceDisplacement, }; }
public static void DoNullReferenceCheck(Assembler.Assembler assembler, bool debugEnabled, uint stackOffsetToCheck) { if (stackOffsetToCheck != Align(stackOffsetToCheck, 4)) { throw new Exception("Stack offset not aligned!"); } if (debugEnabled) { new CPU.Compare { DestinationReg = CPU.RegistersEnum.ESP, DestinationDisplacement = (int)stackOffsetToCheck, DestinationIsIndirect = true, SourceValue = 0 }; new CPU.ConditionalJump { DestinationLabel = ".AfterNullCheck", Condition = CPU.ConditionalTestEnum.NotEqual }; new CPU.ClrInterruptFlag(); // don't remove the call. It seems pointless, but we need it to retrieve the EIP value new CPU.Call { DestinationLabel = ".NullCheck_GetCurrAddress" }; new Assembler.Label(".NullCheck_GetCurrAddress"); new CPU.Pop { DestinationReg = CPU.RegistersEnum.EAX }; new CPU.Mov { DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.EAX }; new CPU.Call { DestinationLabel = "DebugStub_SendNullReferenceOccurred" }; new CPU.Halt(); new Label(".AfterNullCheck"); } }
protected static void DoNullReferenceCheck(Assembler.Assembler assembler, bool debugEnabled, int stackOffsetToCheck) { if (stackOffsetToCheck != SignedAlign(stackOffsetToCheck, 4)) { throw new Exception("Stack offset not aligned!"); } if (debugEnabled) { if (!CompilerEngine.UseGen3Kernel) { XS.Compare(XSRegisters.ESP, 0, destinationDisplacement: (int)stackOffsetToCheck); XS.Jump(CPU.ConditionalTestEnum.NotEqual, ".AfterNullCheck"); XS.ClearInterruptFlag(); // don't remove the call. It seems pointless, but we need it to retrieve the EIP value XS.Call(".NullCheck_GetCurrAddress"); XS.Label(".NullCheck_GetCurrAddress"); XS.Pop(XSRegisters.EAX); new CPU.Mov { DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.EAX }; XS.Call("DebugStub_SendNullReferenceOccurred"); } XS.Halt(); XS.Label(".AfterNullCheck"); } }
public static string GetFakeHandleForLiteralArray(string labelArray) { var xAsm = CPU.Assembler.CurrentInstance; var xResult = labelArray + "__Handle"; xAsm.DataMembers.Add(new DataMember(xResult, ElementReference.New(labelArray))); return(xResult); }
public static void Test(Register destination, string sourceRef, bool sourceIsIndirect = false) { new Test { DestinationReg = destination.RegEnum, SourceRef = ElementReference.New(sourceRef), SourceIsIndirect = sourceIsIndirect }; }
public void CreateIDT() { new Comment(this, "BEGIN - Create IDT"); // Create IDT UInt16 xIdtSize = 8 * 256; DataMembers.Add(new DataMember("_NATIVE_IDT_Contents", new byte[xIdtSize])); // if (mComPort > 0) { if (!CompilerEngine.UseGen3Kernel) { SetIdtDescriptor(1, "DebugStub_TracerEntry", false); SetIdtDescriptor(3, "DebugStub_TracerEntry", false); } //for (int i = 0; i < 256; i++) //{ // if (i == 1 || i == 3) // { // continue; // } // SetIdtDescriptor(i, "DebugStub_Interrupt_" + i.ToString(), true); //} } //SetIdtDescriptor(1, "DebugStub_INT0"); - Change to GPF // Set IDT DataMembers.Add(new DataMember("_NATIVE_IDT_Pointer", new UInt16[] { xIdtSize, 0, 0 })); new Mov { DestinationRef = ElementReference.New("_NATIVE_IDT_Pointer"), DestinationIsIndirect = true, DestinationDisplacement = 2, SourceRef = ElementReference.New("_NATIVE_IDT_Contents") }; XS.Set(XSRegisters.EAX, "_NATIVE_IDT_Pointer"); if (mComPort > 0) { if (!CompilerEngine.UseGen3Kernel) { XS.Set("static_field__Cosmos_Core_CPU_mInterruptsEnabled", 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.LoadIdt(XSRegisters.EAX, isIndirect: true); } } XS.Label("AfterCreateIDT"); new Comment(this, "END - Create IDT"); }
private static void Do <T>(string label, bool isIndirect = false, RegisterSize size = RegisterSize.Int32) where T : InstructionWithDestinationAndSize, new() { new T { DestinationRef = ElementReference.New(label), DestinationIsIndirect = isIndirect, Size = (byte)size }; }
public void CreateGDT() { new Comment(this, "BEGIN - Create GDT"); var xGDT = new List <byte>(); // Null Segment - Selector 0x00 // Not used, but required by many emulators. xGDT.AddRange(new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); // Code Segment mGdCode = (byte)xGDT.Count; xGDT.AddRange(GdtDescriptor(0x00000000, 0xFFFFFFFF, true)); // Data Segment - Selector mGdData = (byte)xGDT.Count; xGDT.AddRange(GdtDescriptor(0x00000000, 0xFFFFFFFF, false)); DataMembers.Add(new DataMember("_NATIVE_GDT_Contents", xGDT.ToArray())); XS.Comment("Tell CPU about GDT"); var xGdtPtr = new UInt16[3]; // Size of GDT Table - 1 xGdtPtr[0] = (UInt16)(xGDT.Count - 1); DataMembers.Add(new DataMember("_NATIVE_GDT_Pointer", xGdtPtr)); new Mov { DestinationRef = ElementReference.New("_NATIVE_GDT_Pointer"), DestinationIsIndirect = true, DestinationDisplacement = 2, SourceRef = ElementReference.New("_NATIVE_GDT_Contents") }; XS.Set(XSRegisters.EAX, "_NATIVE_GDT_Pointer"); XS.LoadGdt(XSRegisters.EAX, isIndirect: true); XS.Comment("Set data segments"); XS.Set(XSRegisters.EAX, mGdData); XS.Set(XSRegisters.DS, XSRegisters.AX); XS.Set(XSRegisters.ES, XSRegisters.AX); XS.Set(XSRegisters.FS, XSRegisters.AX); XS.Set(XSRegisters.GS, XSRegisters.AX); XS.Set(XSRegisters.SS, XSRegisters.AX); XS.Comment("Force reload of code segment"); new JumpToSegment { Segment = mGdCode, DestinationLabel = "Boot_FlushCsGDT" }; XS.Label("Boot_FlushCsGDT"); new Comment(this, "END - Create GDT"); }
public void CreateIDT() { new Comment(this, "BEGIN - Create IDT"); // Create IDT ushort xIdtSize = 8 * 256; DataMembers.Add(new DataMember("_NATIVE_IDT_Contents", new byte[xIdtSize])); // if (mComPort > 0) { SetIdtDescriptor(1, AsmMarker.Labels[AsmMarker.Type.DebugStub_TracerEntry], false); SetIdtDescriptor(3, AsmMarker.Labels[AsmMarker.Type.DebugStub_TracerEntry], false); //for (int i = 0; i < 256; i++) //{ // if (i == 1 || i == 3) // { // continue; // } // SetIdtDescriptor(i, "DebugStub_Interrupt_" + i.ToString(), true); //} } //SetIdtDescriptor(1, "DebugStub_INT0"); - Change to GPF // Set IDT DataMembers.Add(new DataMember("_NATIVE_IDT_Pointer", new ushort[] { xIdtSize, 0, 0 })); new Mov { DestinationRef = ElementReference.New("_NATIVE_IDT_Pointer"), DestinationIsIndirect = true, DestinationDisplacement = 2, SourceRef = ElementReference.New("_NATIVE_IDT_Contents") }; XS.Set(EAX, "_NATIVE_IDT_Pointer"); if (mComPort > 0) { XS.Set(AsmMarker.Labels[AsmMarker.Type.Processor_IntsEnabled], 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.LoadIdt(EAX, isIndirect: true); } XS.Label("AfterCreateIDT"); new Comment(this, "END - Create IDT"); }
public void EmitData(DataMember dm, MemberSpec v, bool constant = false) { if (!Variables.ContainsKey(v.Signature.ToString())) { v.Reference = ElementReference.New(v.Signature.ToString()); if (constant) { ag.DefineConstantData(dm); } else { ag.DefineData(dm); } } }
private static void Do <T>(Register destination, string sourceLabel, bool destinationIsIndirect = false, int?destinationDisplacement = null, bool sourceIsIndirect = false, int?sourceDisplacement = null, RegisterSize?size = null) where T : InstructionWithDestinationAndSourceAndSize, new() { if (destinationDisplacement != null) { destinationIsIndirect = true; if (destinationDisplacement == 0) { destinationDisplacement = null; } } if (sourceDisplacement != null) { sourceIsIndirect = true; if (sourceDisplacement == 0) { sourceDisplacement = null; } } if (size == null) { if (destinationIsIndirect) { throw new Exception("No size specified!"); } size = destination.Size; } new T { Size = (byte)size.Value, DestinationReg = destination.RegEnum, DestinationIsIndirect = destinationIsIndirect, DestinationDisplacement = destinationDisplacement, SourceRef = ElementReference.New(sourceLabel), SourceIsIndirect = sourceIsIndirect, SourceDisplacement = sourceDisplacement }; }
public override bool EmitToStack(EmitContext ec) { if (ReferenceType == ReferenceKind.Field) { ec.EmitComment("Push Field @" + Signature.ToString() + " " + Offset); ec.EmitInstruction(new Push() { DestinationRef = ElementReference.New(Signature.ToString()), DestinationDisplacement = Offset, DestinationIsIndirect = true, Size = 16 }); } else if (ReferenceType == ReferenceKind.LocalVariable) { ec.EmitComment("Push Var @BP" + Offset); ec.EmitInstruction(new Push() { DestinationReg = EmitContext.BP, DestinationDisplacement = Offset, DestinationIsIndirect = true, Size = 16 }); } else if (ReferenceType == ReferenceKind.Register) { ec.EmitComment("Push Var @" + Register.ToString() + Offset); ec.EmitInstruction(new Push() { DestinationReg = Register, DestinationDisplacement = Offset, DestinationIsIndirect = true, Size = 16 }); } else { ec.EmitComment("Push Parameter @BP " + Offset); ec.EmitInstruction(new Push() { DestinationReg = EmitContext.BP, Size = 16, DestinationDisplacement = Offset, DestinationIsIndirect = true }); } return(true); }
public void Initialize() { uint xSig = 0x1BADB002; DataMembers.Add(new DataIfNotDefined("ELF_COMPILATION")); DataMembers.Add(new DataMember("MultibootSignature", new uint[] { xSig })); uint xFlags = 0x10007; DataMembers.Add(new DataMember("MultibootFlags", xFlags)); DataMembers.Add(new DataMember("MultibootChecksum", (int)(0 - (xFlags + xSig)))); DataMembers.Add(new DataMember("MultibootHeaderAddr", ElementReference.New("MultibootSignature"))); DataMembers.Add(new DataMember("MultibootLoadAddr", ElementReference.New("MultibootSignature"))); DataMembers.Add(new DataMember("MultibootLoadEndAddr", ElementReference.New("_end_code"))); DataMembers.Add(new DataMember("MultibootBSSEndAddr", ElementReference.New("_end_code"))); DataMembers.Add(new DataMember("MultibootEntryAddr", ElementReference.New("Kernel_Start"))); DataMembers.Add(new DataMember("", 0)); DataMembers.Add(new DataMember("", 800, 600, 32)); DataMembers.Add(new DataEndIfDefined()); DataMembers.Add(new DataIfDefined("ELF_COMPILATION")); xFlags = 0x00007; DataMembers.Add(new DataMember("MultibootSignature", new uint[] { xSig })); DataMembers.Add(new DataMember("MultibootFlags", xFlags)); DataMembers.Add(new DataMember("MultibootChecksum", (int)(0 - (xFlags + xSig)))); DataMembers.Add(new DataMember("", 0, 0, 0, 0, 0)); DataMembers.Add(new DataMember("", 0)); DataMembers.Add(new DataMember("", 800, 600, 32)); DataMembers.Add(new DataEndIfDefined()); //graphics info fields DataMembers.Add(new DataMember("MultibootGraphicsRuntime_VbeModeInfoAddr", 1 << 2)); DataMembers.Add(new DataMember("MultibootGraphicsRuntime_VbeControlInfoAddr", 1 << 0)); DataMembers.Add(new DataMember("MultibootGraphicsRuntime_VbeMode", 0)); // memory DataMembers.Add(new DataMember("MultiBootInfo_Memory_High", 0)); DataMembers.Add(new DataMember("MultiBootInfo_Memory_Low", 0)); DataMembers.Add(new DataMember("Before_Kernel_Stack", new byte[0x50000])); DataMembers.Add(new DataMember("Kernel_Stack", new byte[0])); DataMembers.Add(new DataMember("MultiBootInfo_Structure", new uint[1])); // constants DataMembers.Add(new DataMember(@"__uint2double_const", new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x41 })); DataMembers.Add(new DataMember(@"__ulong2double_const", 0x5F800000)); DataMembers.Add(new DataMember(@"__doublesignbit", 0x8000000000000000)); DataMembers.Add(new DataMember(@"__floatsignbit", 0x80000000)); if (mComPort > 0) { new Define("DEBUGSTUB"); } // This is our first entry point. Multiboot uses this as Cosmos entry point. new Label("Kernel_Start", isGlobal: true); XS.Set(XSRegisters.ESP, "Kernel_Stack"); // Displays "Cosmos" in top left. Used to make sure Cosmos is booted in case of hang. // ie bootloader debugging. This must be the FIRST code, even before setup so we know // we are being called properly by the bootloader and that if there are problems its // somwhere in our code, not the bootloader. WriteDebugVideo("Cosmos pre boot"); // For when using Bochs, causes a break ASAP on entry after initial Cosmos display. //new LiteralAssemblerCode("xchg bx, bx"); // CLI ASAP WriteDebugVideo("Clearing interrupts."); XS.ClearInterruptFlag(); WriteDebugVideo("Begin multiboot info."); new LiteralAssemblerCode("%ifndef EXCLUDE_MULTIBOOT_MAGIC"); new Comment(this, "MultiBoot compliant loader provides info in registers: "); new Comment(this, "EBX=multiboot_info "); new Comment(this, "EAX=0x2BADB002 - check if it's really Multiboot-compliant loader "); new Comment(this, " ;- copy mb info - some stuff for you "); new Comment(this, "BEGIN - Multiboot Info"); new Mov { DestinationRef = ElementReference.New("MultiBootInfo_Structure"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EBX }; XS.Add(XSRegisters.EBX, 4); XS.Set(XSRegisters.EAX, XSRegisters.EBX, sourceIsIndirect: true); new Mov { DestinationRef = ElementReference.New("MultiBootInfo_Memory_Low"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX }; XS.Add(XSRegisters.EBX, 4); XS.Set(XSRegisters.EAX, XSRegisters.EBX, sourceIsIndirect: true); new Mov { DestinationRef = ElementReference.New("MultiBootInfo_Memory_High"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX }; new Comment(this, "END - Multiboot Info"); new LiteralAssemblerCode("%endif"); WriteDebugVideo("Creating GDT."); CreateGDT(); WriteDebugVideo("Configuring PIC"); ConfigurePIC(); WriteDebugVideo("Creating IDT."); CreateIDT(); new Comment("Set graphics fields"); new Mov { DestinationReg = XSRegisters.EBX, SourceRef = ElementReference.New("MultiBootInfo_Structure"), SourceIsIndirect = true }; new Mov { DestinationReg = XSRegisters.EAX, SourceReg = XSRegisters.EBX, SourceIsIndirect = true, SourceDisplacement = 72 }; new Mov { DestinationRef = ElementReference.New("MultibootGraphicsRuntime_VbeControlInfoAddr"), DestinationIsIndirect = true, SourceReg = XSRegisters.EAX }; new Mov { DestinationReg = XSRegisters.EAX, SourceReg = XSRegisters.EBX, SourceIsIndirect = true, SourceDisplacement = 76 }; new Mov { DestinationRef = ElementReference.New("MultibootGraphicsRuntime_VbeModeInfoAddr"), DestinationIsIndirect = true, SourceReg = XSRegisters.EAX }; new Mov { DestinationReg = XSRegisters.EAX, SourceReg = XSRegisters.EBX, SourceIsIndirect = true, SourceDisplacement = 80 }; new Mov { DestinationRef = ElementReference.New("MultibootGraphicsRuntime_VbeMode"), DestinationIsIndirect = true, SourceReg = XSRegisters.EAX }; //WriteDebugVideo("Initializing SSE."); //new Comment(this, "BEGIN - SSE Init"); //// CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR4); //XS.Or(XSRegisters.EAX, 0x100); //XS.Mov(XSRegisters.CR4, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR4); //XS.Or(XSRegisters.EAX, 0x200); //XS.Mov(XSRegisters.CR4, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR0); //XS.And(XSRegisters.EAX, 0xfffffffd); //XS.Mov(XSRegisters.CR0, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR0); //XS.And(XSRegisters.EAX, 1); //XS.Mov(XSRegisters.CR0, XSRegisters.Registers.EAX); //new Comment(this, "END - SSE Init"); if (mComPort > 0) { WriteDebugVideo("Initializing DebugStub."); XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_Init]); } // Jump to Kernel entry point WriteDebugVideo("Jumping to kernel."); XS.Call(EntryPointName); new Comment(this, "Kernel done - loop till next IRQ"); XS.Label(".loop"); XS.ClearInterruptFlag(); XS.Halt(); XS.Jump(".loop"); if (mComPort > 0) { var xGen = new AsmGenerator(); var xGenerateAssembler = new Action <object>(i => { if (i is StreamReader) { var xAsm = xGen.Generate((StreamReader)i); CurrentInstance.Instructions.AddRange(xAsm.Instructions); CurrentInstance.DataMembers.AddRange(xAsm.DataMembers); } else if (i is string) { var xAsm = xGen.Generate((string)i); CurrentInstance.Instructions.AddRange(xAsm.Instructions); CurrentInstance.DataMembers.AddRange(xAsm.DataMembers); } else { throw new Exception("Object type '" + i.ToString() + "' not supported!"); } }); if (ReadDebugStubFromDisk) { foreach (var xFile in Directory.GetFiles(CosmosPaths.DebugStubSrc, "*.xs")) { xGenerateAssembler(xFile); } } else { foreach (var xManifestName in typeof(ReferenceHelper).Assembly.GetManifestResourceNames()) { if (!xManifestName.EndsWith(".xs", StringComparison.OrdinalIgnoreCase)) { continue; } using (var xStream = typeof(ReferenceHelper).Assembly.GetManifestResourceStream(xManifestName)) { using (var xReader = new StreamReader(xStream)) { xGenerateAssembler(xReader); } } } } OnAfterEmitDebugStub(); } else { XS.Label(AsmMarker.Labels[AsmMarker.Type.DebugStub_Step]); XS.Return(); } // Start emitting assembly labels CurrentInstance.EmitAsmLabels = true; }
public static void Set(string destinationLabel, string sourceLabel) { new Mov { DestinationRef = ElementReference.New(destinationLabel), DestinationIsIndirect = true, SourceRef = ElementReference.New(sourceLabel) }; }
public void Initialize(bool enableVBE, string VBEResolution) { uint xSig = 0xe85250d6; //Multiboot header DataMembers.Add(new DataMember("align", "8", true)); DataMembers.Add(new DataMember("MultibootHeader", Array.Empty <byte>())); DataMembers.Add(new DataMember("MultibootSignature", new uint[] { xSig })); DataMembers.Add(new DataMember("MultibootArchitecture", 0)); DataMembers.Add(new DataMember("MultibootLenght", "MultibootHeaderEnd - MultibootHeader", typeof(uint))); DataMembers.Add(new DataMember("MultibootChecksum", "0x100000000 - (0xe85250d6 + 0 + (MultibootHeaderEnd - MultibootHeader))", typeof(uint))); if (enableVBE) { try { string[] res = VBEResolution.Split('x'); //Framebuffer Tag DataMembers.Add(new DataMember("align", "8", true)); DataMembers.Add(new DataMember("MultibootFramebufferTag", Array.Empty <byte>())); DataMembers.Add(new DataMember("MultibootFramebufferType", (ushort)5)); DataMembers.Add(new DataMember("MultibootFramebufferOptional", (ushort)1)); DataMembers.Add(new DataMember("MultibootFramebufferLenght", "MultibootFramebufferTagEnd - MultibootFramebufferTag", typeof(uint))); DataMembers.Add(new DataMember("", int.Parse(res[0]))); DataMembers.Add(new DataMember("", int.Parse(res[1]))); DataMembers.Add(new DataMember("", int.Parse(res[2]))); DataMembers.Add(new DataMember("MultibootFramebufferTagEnd", Array.Empty <byte>())); } catch { Console.WriteLine("VBE Resolution must be this format: 1920x1080x32"); } } // memory DataMembers.Add(new DataMember("align", "8", true)); DataMembers.Add(new DataMember("MultibootMemoryTag", Array.Empty <byte>())); DataMembers.Add(new DataMember("MultibootMemoryTagType", (ushort)2)); DataMembers.Add(new DataMember("MultibootMemoryTagOptional", (ushort)1)); DataMembers.Add(new DataMember("MultibootMemoryTagLenght", "MultibootMemoryTagEnd - MultibootMemoryTag", typeof(uint))); DataMembers.Add(new DataMember("MultibootHeaderAddr", ElementReference.New("MultibootSignature"))); DataMembers.Add(new DataMember("MultibootLoadAddr", ElementReference.New("MultibootSignature"))); DataMembers.Add(new DataMember("MultibootLoadEndAddr", ElementReference.New("_end_code"))); DataMembers.Add(new DataMember("MultibootBSSEndAddr", ElementReference.New("_end_code"))); DataMembers.Add(new DataMember("MultibootMemoryTagEnd", Array.Empty <byte>())); //Entry Address DataMembers.Add(new DataMember("align", "8", true)); DataMembers.Add(new DataMember("MultibootEntryTag", Array.Empty <byte>())); DataMembers.Add(new DataMember("MultibootEntryTagType", (ushort)3)); DataMembers.Add(new DataMember("MultibootEntryTagOptional", (ushort)1)); DataMembers.Add(new DataMember("MultibootEntryTagLenght", "MultibootEntryTagEnd - MultibootEntryTag", typeof(uint))); DataMembers.Add(new DataMember("MultibootEntryAddr", ElementReference.New("Kernel_Start"))); DataMembers.Add(new DataMember("MultibootEntryTagEnd", Array.Empty <byte>())); //End Tag DataMembers.Add(new DataMember("align", "8", true)); DataMembers.Add(new DataMember("MultibootEndTag", Array.Empty <byte>())); DataMembers.Add(new DataMember("MultibootEndTagType", (ushort)0)); DataMembers.Add(new DataMember("MultibootEndTagOptional", (ushort)0)); DataMembers.Add(new DataMember("MultibootEndTagEnd", Array.Empty <byte>())); DataMembers.Add(new DataMember("MultibootHeaderEnd", Array.Empty <byte>())); //memory DataMembers.Add(new DataMember("align", "16", true)); DataMembers.Add(new DataMember("Before_Kernel_Stack", new byte[0x50000])); DataMembers.Add(new DataMember("align", "16", true)); DataMembers.Add(new DataMember("Kernel_Stack", Array.Empty <byte>())); DataMembers.Add(new DataMember("MultiBootInfo_Structure", new uint[1])); // constants DataMembers.Add(new DataMember("align", "16", true)); DataMembers.Add(new DataMember(@"__uint2double_const", new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x41 })); DataMembers.Add(new DataMember("align", "16", true)); DataMembers.Add(new DataMember(@"__ulong2double_const", 0x5F800000)); DataMembers.Add(new DataMember("align", "16", true)); DataMembers.Add(new DataMember(@"__doublesignbit", 0x8000000000000000)); DataMembers.Add(new DataMember("align", "16", true)); DataMembers.Add(new DataMember(@"__floatsignbit", 0x80000000)); if (mComPort > 0) { new Define("DEBUGSTUB"); } // This is our first entry point. Multiboot uses this as Cosmos entry point. new Label("Kernel_Start", isGlobal: true); XS.Set(ESP, "Kernel_Stack"); // Displays "Cosmos" in top left. Used to make sure Cosmos is booted in case of hang. // ie bootloader debugging. This must be the FIRST code, even before setup so we know // we are being called properly by the bootloader and that if there are problems its // somwhere in our code, not the bootloader. WriteDebugVideo("Cosmos pre boot"); // For when using Bochs, causes a break ASAP on entry after initial Cosmos display. //new LiteralAssemblerCode("xchg bx, bx"); // CLI ASAP WriteDebugVideo("Clearing interrupts."); XS.ClearInterruptFlag(); WriteDebugVideo("Begin multiboot info."); new LiteralAssemblerCode("%ifndef EXCLUDE_MULTIBOOT_MAGIC"); new Comment(this, "MultiBoot compliant loader provides info in registers: "); new Comment(this, "EBX=multiboot_info "); new Comment(this, "EAX=0x36d76289 - check if it's really Multiboot2-compliant loader "); new Comment(this, " ;- copy mb info - some stuff for you "); new Comment(this, "BEGIN - Multiboot Info"); new Mov { DestinationRef = ElementReference.New("MultiBootInfo_Structure"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EBX }; XS.Call("SystemVoidCosmosCoreMultiboot2Init"); new Comment(this, "END - Multiboot Info"); new LiteralAssemblerCode("%endif"); WriteDebugVideo("Creating GDT."); CreateGDT(); WriteDebugVideo("Configuring PIC"); ConfigurePIC(); WriteDebugVideo("Creating IDT."); CreateIDT(); //WriteDebugVideo("Initializing SSE."); //new Comment(this, "BEGIN - SSE Init"); //// CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR4); //XS.Or(XSRegisters.EAX, 0x100); //XS.Mov(XSRegisters.CR4, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR4); //XS.Or(XSRegisters.EAX, 0x200); //XS.Mov(XSRegisters.CR4, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR0); //XS.And(XSRegisters.EAX, 0xfffffffd); //XS.Mov(XSRegisters.CR0, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR0); //XS.And(XSRegisters.EAX, 1); //XS.Mov(XSRegisters.CR0, XSRegisters.Registers.EAX); //new Comment(this, "END - SSE Init"); if (mComPort > 0) { WriteDebugVideo("Initializing DebugStub."); XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_Init]); } //Initiate Memory WriteDebugVideo("Initiating Memory"); XS.Call(LabelName.Get(GCImplementationRefs.InitRef)); // Jump to Kernel entry point WriteDebugVideo("Jumping to kernel."); XS.Call(EntryPointName); new Comment(this, "Kernel done - loop till next IRQ"); XS.Label(".loop"); XS.ClearInterruptFlag(); XS.Halt(); XS.Jump(".loop"); if (mComPort > 0) { var xGen = new AsmGenerator(); void GenerateAssembler(Assembler assembler) { CurrentInstance.Instructions.AddRange(assembler.Instructions); CurrentInstance.DataMembers.AddRange(assembler.DataMembers); } if (ReadDebugStubFromDisk) { foreach (var xFile in Directory.GetFiles(CosmosPaths.DebugStubSrc, "*.xs")) { GenerateAssembler(xGen.Generate(xFile)); } } else { foreach (var xManifestName in typeof(ReferenceHelper).Assembly.GetManifestResourceNames()) { if (!xManifestName.EndsWith(".xs", StringComparison.OrdinalIgnoreCase)) { continue; } using (var xStream = typeof(ReferenceHelper).Assembly.GetManifestResourceStream(xManifestName)) { using (var xReader = new StreamReader(xStream)) { GenerateAssembler(xGen.Generate(xReader)); } } } } OnAfterEmitDebugStub(); } else { XS.Label(AsmMarker.Labels[AsmMarker.Type.DebugStub_Step]); XS.Return(); } // Start emitting assembly labels CurrentInstance.EmitAsmLabels = true; }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (ILOpCodes.OpField)aOpCode; SysReflection.FieldInfo xField = xOpCode.Value; var xIsReferenceType = TypeIsReferenceType(xField.FieldType); // call cctor: var xCctor = (xField.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); if (xCctor != null && xCctor.DeclaringType != aMethod.MethodBase.DeclaringType) { XS.Call(LabelName.Get(xCctor)); ILOp.EmitExceptionLogic(Assembler, aMethod, aOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } //int aExtraOffset;// = 0; //bool xNeedsGC = xField.FieldType.IsClass && !xField.FieldType.IsValueType; uint xSize = SizeOfType(xField.FieldType); //if( xNeedsGC ) //{ // aExtraOffset = 12; //} new Comment(Assembler, "Type = '" + xField.FieldType.FullName /*+ "', NeedsGC = " + xNeedsGC*/); uint xOffset = 0; var xFields = xField.DeclaringType.GetFields(); foreach (SysReflection.FieldInfo xInfo in xFields) { if (xInfo == xField) { break; } xOffset += SizeOfType(xInfo.FieldType); } string xDataName = DataMember.GetStaticFieldName(xField); if (xIsReferenceType) { XS.Add(XSRegisters.ESP, 4); XS.Pop(XSRegisters.EAX); XS.Set(ElementReference.New(xDataName).Name, XSRegisters.EAX, destinationIsIndirect: true, destinationDisplacement: 4); return; } for (int i = 0; i < (xSize / 4); i++) { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = ElementReference.New(xDataName, i * 4), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.EAX }; } switch (xSize % 4) { case 1: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.AL }; break; } case 2: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = Cosmos.Assembler.ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.AX }; break; } case 0: { break; } default: //EmitNotImplementedException(Assembler, GetServiceProvider(), "Ldsfld: Remainder size " + (xSize % 4) + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel); throw new NotImplementedException(); //break; } }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { new CPUx86.Push { DestinationRef = ElementReference.New("MultiBootInfo_Structure"), DestinationIsIndirect = true }; }
public static void DoExecute(Cosmos.Assembler.Assembler Assembler, MethodInfo aMethod, MethodBase aTargetMethod, uint aTargetMethodUID, ILOpCode aOp, bool debugEnabled) { string xCurrentMethodLabel = GetLabel(aMethod, aOp.Position); // mTargetMethodInfo = GetService<IMetaDataInfoService>().GetMethodInfo(mMethod // , mMethod, mMethodDescription, null, mCurrentMethodInfo.DebugMode); string xNormalAddress = ""; if (aTargetMethod.IsStatic || !aTargetMethod.IsVirtual || aTargetMethod.IsFinal) { xNormalAddress = LabelName.Get(aTargetMethod); } // mMethodIdentifier = GetService<IMetaDataInfoService>().GetMethodIdLabel(mMethod); int xArgCount = aTargetMethod.GetParameters().Length; uint xReturnSize = 0; var xMethodInfo = aTargetMethod as SysReflection.MethodInfo; if (xMethodInfo != null) { xReturnSize = Align(SizeOfType(xMethodInfo.ReturnType), 4); } // Extracted from MethodInformation: Calculated offset // var xRoundedSize = ReturnSize; //if (xRoundedSize % 4 > 0) { // xRoundedSize += (4 - (ReturnSize % 4)); //} //ExtraStackSize = (int)xRoundedSize; uint xExtraStackSize = Call.GetStackSizeToReservate(aTargetMethod); uint xThisOffset = 0; var xParameters = aTargetMethod.GetParameters(); foreach (var xItem in xParameters) { xThisOffset += Align(SizeOfType(xItem.ParameterType), 4); } // This is finding offset to self? It looks like we dont need offsets of other // arguments, but only self. If so can calculate without calculating all fields // Might have to go to old data structure for the offset... // Can we add this method info somehow to the data passed in? // mThisOffset = mTargetMethodInfo.Arguments[0].Offset; new Comment(Assembler, "ThisOffset = " + xThisOffset); Call.DoNullReferenceCheck(Assembler, debugEnabled, xThisOffset); if (!String.IsNullOrEmpty(xNormalAddress)) { if (xExtraStackSize > 0) { new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xExtraStackSize }; } new CPUx86.Call { DestinationLabel = xNormalAddress }; } else { /* * On the stack now: * $esp Params * $esp + mThisOffset This */ Type xPopType = aOp.StackPopTypes.Last(); if ((xPopType.IsPointer) || (xPopType.IsByRef)) { xPopType = xPopType.GetElementType(); string xTypeId = GetTypeIDLabel(xPopType); new CPUx86.Push { DestinationRef = ElementReference.New(xTypeId), DestinationIsIndirect = true }; } else { new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xThisOffset }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true }; } new CPUx86.Push { DestinationValue = aTargetMethodUID }; new CPUx86.Call { DestinationLabel = LabelName.Get(VTablesImplRefs.GetMethodAddressForTypeRef) }; if (xExtraStackSize > 0) { xThisOffset -= xExtraStackSize; } /* * On the stack now: * $esp Params * $esp + mThisOffset This */ //Call.EmitExceptionLogic( Assembler, // mCurrentILOffset, // mCurrentMethodInfo, // mLabelName + "_AfterAddressCheck", // true, // xEmitCleanup ); new CPUx86.Pop { DestinationReg = CPU.RegistersEnum.ECX }; new Label(xCurrentMethodLabel + ".AfterAddressCheck"); if (xMethodInfo.DeclaringType == typeof(object)) { /* * On the stack now: * $esp + 0 Params * $esp + mThisOffset This */ // we need to see if $this is a boxed object, and if so, we need to box it new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xThisOffset }; //new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = ( ( uint )InstanceTypeEnum.BoxedValueType ), Size = 32 }; // EAX contains the handle now, lets dereference it new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = (int)InstanceTypeEnum.BoxedValueType, Size = 32 }; /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call * EAX contains the type pointer (not the handle!!) */ new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.NotEqual, DestinationLabel = xCurrentMethodLabel + ".NotBoxedThis" }; /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call * EAX contains the type pointer (not the handle!!) */ new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = (uint)ObjectImpl.FieldDataOffset }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)xThisOffset, SourceReg = CPUx86.Registers.EAX }; /* * On the stack now: * $esp Params * $esp + mThisOffset Pointer to address inside box * * ECX contains the method to call */ } new Label(xCurrentMethodLabel + ".NotBoxedThis"); if (xExtraStackSize > 0) { new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = xExtraStackSize }; } new CPUx86.Call { DestinationReg = CPUx86.Registers.ECX }; new Label(xCurrentMethodLabel + ".AfterNotBoxedThis"); } ILOp.EmitExceptionLogic(Assembler, aMethod, aOp, true, delegate() { var xStackOffsetBefore = aOp.StackOffsetBeforeExecution.Value; uint xPopSize = 0; foreach (var type in aOp.StackPopTypes) { xPopSize += Align(SizeOfType(type), 4); } var xResultSize = xReturnSize; if (xResultSize % 4 != 0) { xResultSize += 4 - (xResultSize % 4); } ILOp.EmitExceptionCleanupAfterCall(Assembler, xResultSize, xStackOffsetBefore, xPopSize); }); new Label(xCurrentMethodLabel + ".NoExceptionAfterCall"); new Comment(Assembler, "Argument Count = " + xParameters.Length.ToString()); }
public override bool LoadEffectiveAddress(EmitContext ec) { if (ReferenceType == ReferenceKind.Field) { ec.EmitComment("AddressOf Field "); ec.EmitInstruction(new Lea() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, SourceDisplacement = Offset, Size = 16, SourceRef = ElementReference.New(Signature.ToString()) }); ec.EmitPush(EmitContext.SI); } else if (ReferenceType == ReferenceKind.LocalVariable) { ec.EmitComment("AddressOf @BP" + Offset); ec.EmitInstruction(new Lea() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, Size = 16, SourceReg = EmitContext.BP, SourceDisplacement = Offset }); ec.EmitPush(EmitContext.SI); } else if (ReferenceType == ReferenceKind.Register) { ec.EmitComment("AddressOf @" + Register.ToString() + Offset); ec.EmitInstruction(new Lea() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, Size = 16, SourceReg = Register, SourceDisplacement = Offset }); ec.EmitPush(EmitContext.SI); } else { ec.EmitComment("AddressOf @BP+" + Offset); ec.EmitInstruction(new Lea() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, Size = 16, SourceReg = EmitContext.BP, SourceDisplacement = Offset }); ec.EmitPush(EmitContext.SI); } return(true); }
public override bool ValueOfStackAccess(EmitContext ec, int off) { if (ReferenceType == ReferenceKind.Field) { ec.EmitComment("ValueOf Access Field "); ec.EmitInstruction(new Mov() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, Size = 16, SourceRef = ElementReference.New(Signature.ToString()) }); ec.EmitPop(EmitContext.SI, 16, true, off); } else if (ReferenceType == ReferenceKind.LocalVariable) { ec.EmitComment("ValueOf Stack Access @BP" + Offset); ec.EmitInstruction(new Mov() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, Size = 16, SourceReg = EmitContext.BP, SourceDisplacement = Offset }); ec.EmitPop(EmitContext.SI, 16, true, off); } else if (ReferenceType == ReferenceKind.Register) { ec.EmitComment("ValueOf Stack Access @" + Register.ToString() + Offset); ec.EmitInstruction(new Mov() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, Size = 16, SourceReg = Register, SourceDisplacement = Offset }); ec.EmitPop(EmitContext.SI, 16, true, off); } else { ec.EmitComment("ValueOf Access Stack @BP+" + Offset); ec.EmitInstruction(new Mov() { DestinationReg = EmitContext.SI, SourceIsIndirect = true, Size = 16, SourceReg = EmitContext.BP, SourceDisplacement = Offset }); ec.EmitPop(EmitContext.SI, 16, true, off); } return(true); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (ILOpCodes.OpField)aOpCode; FieldInfo xField = xOpCode.Value; var xIsReferenceType = IsReferenceType(xField.FieldType); // call cctor: var xCctor = (xField.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); EmitExceptionLogic(Assembler, aMethod, aOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } uint xSize = SizeOfType(xField.FieldType); XS.Comment("Type = '" + xField.FieldType.FullName + "'"); uint xOffset = 0; var xFields = xField.DeclaringType.GetFields(); foreach (FieldInfo xInfo in xFields) { if (xInfo == xField) { break; } xOffset += SizeOfType(xInfo.FieldType); } string xDataName = LabelName.GetStaticFieldName(xField); if (xIsReferenceType) { var name = ElementReference.New(xDataName).Name; XS.Add(ESP, 4); // GC clean up old object XS.Compare(name, 0, destinationIsIndirect: true, destinationDisplacement: 4); XS.Jump(CPU.ConditionalTestEnum.Equal, ".AfterGC"); XS.Push(name, isIndirect: true, displacement: 4); // push object as pointer to send to DecRootCount XS.Call(LabelName.Get(GCImplementationRefs.DecRootCountRef)); XS.Label(".AfterGC"); XS.Pop(EAX); XS.Set(name, EAX, destinationIsIndirect: true, destinationDisplacement: 4); // Update GC for new object XS.Compare(name, 0, destinationIsIndirect: true, destinationDisplacement: 4); XS.Jump(CPU.ConditionalTestEnum.Equal, ".SecondAfterGC"); XS.Push(name, isIndirect: true, displacement: 4); // push object as pointer/uint to send to IncRootCount XS.Call(LabelName.Get(GCImplementationRefs.IncRootCountRef)); XS.Label(".SecondAfterGC"); return; } // value types if (!xField.FieldType.IsPointer && !xField.FieldType.IsPrimitive && !xField.FieldType.IsEnum) { // let clean up object deal with it XS.Push(xDataName, isIndirect: true, displacement: 4); XS.Push(GetTypeIDLabel(xField.FieldType), isIndirect: true); XS.Call(LabelName.Get(GCImplementationRefs.DecRootCountsInStructRef)); } for (int i = 0; i < (xSize / 4); i++) { XS.Pop(EAX); new CPU.Mov { DestinationRef = ElementReference.New(xDataName, i * 4), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.EAX }; } switch (xSize % 4) { case 1: { XS.Pop(EAX); new CPU.Mov { DestinationRef = ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.AL }; break; } case 2: { XS.Pop(EAX); new CPU.Mov { DestinationRef = ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.AX }; break; } case 0: { break; } default: throw new NotImplementedException(); } if (!xField.FieldType.IsPointer && !xField.FieldType.IsPrimitive && !xField.FieldType.IsEnum) { // let clean up object deal with it XS.Push(xDataName, isIndirect: true, displacement: 4); XS.Push(GetTypeIDLabel(xField.FieldType), isIndirect: true); XS.Call(LabelName.Get(GCImplementationRefs.IncRootCountsInStructRef)); } }