Skip to content

[WIP] x64 support #211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 58 additions & 53 deletions source/Cosmos.IL2CPU/AppAssembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ internal sealed class AppAssembler : IDisposable
public bool StackCorruptionDetection = false;
public StackCorruptionDetectionLevel StackCorruptionDetectionLevel;
public DebugMode DebugMode;
public bool IgnoreDebugStubAttribute;
public bool IgnoreDebugStubAttribute;
public string TargetArchitecture;
private List<MethodIlOp> mSymbols = new List<MethodIlOp>();
private List<INT3Label> mINT3Labels = new List<INT3Label>();
private int incBinCounter = 0;
Expand Down Expand Up @@ -141,16 +142,16 @@ private void MethodBegin(Il2cpuMethodInfo aMethod)
if (DebugEnabled && StackCorruptionDetection)
{
// if StackCorruption detection is active, we're also going to emit a stack overflow detection
XS.Set(EAX, "Before_Kernel_Stack");
XS.Compare(EAX, ESP);
XS.Set(RAX, "Before_Kernel_Stack");
XS.Compare(RAX, RSP);
XS.Jump(ConditionalTestEnum.LessThan, ".StackOverflowCheck_End");
XS.ClearInterruptFlag();
// don't remove the call. It seems pointless, but we need it to retrieve the EIP value
XS.Call(".StackOverflowCheck_GetAddress");
XS.Label(".StackOverflowCheck_GetAddress");
XS.Exchange(BX, BX);
XS.Pop(EAX);
XS.Set(AsmMarker.Labels[AsmMarker.Type.DebugStub_CallerEIP], EAX, destinationIsIndirect: true);
XS.Pop(RAX);
XS.Set(AsmMarker.Labels[AsmMarker.Type.DebugStub_CallerEIP], RAX, destinationIsIndirect: true);
XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendStackOverflowEvent]);
XS.Halt();
XS.Label(".StackOverflowCheck_End");
Expand All @@ -168,13 +169,13 @@ private void MethodBegin(Il2cpuMethodInfo aMethod)
XS.Set(xName, 1, destinationIsIndirect: true, size: RegisterSize.Byte8);
XS.Jump(".AfterCCTorAlreadyCalledCheck");
XS.Label(".BeforeQuickReturn");
XS.Set(ECX, 0);
XS.Set(RCX, 0);
XS.Return();
XS.Label(".AfterCCTorAlreadyCalledCheck");
}

XS.Push(EBP);
XS.Set(EBP, ESP);
XS.Push(RBP);
XS.Set(RBP, RSP);

if (aMethod.MethodAssembler == null && aMethod.PlugMethod == null && !aMethod.IsInlineAssembler)
{
Expand Down Expand Up @@ -286,9 +287,10 @@ private void MethodEnd(Il2cpuMethodInfo aMethod)
var xMethodLabel = ILOp.GetLabel(aMethod);
XS.Label(xMethodLabel + EndOfMethodLabelNameNormal);
XS.Comment("Following code is for debugging. Adjust accordingly!");
XS.Set(AsmMarker.Labels[AsmMarker.Type.Int_LastKnownAddress], xMethodLabel + EndOfMethodLabelNameNormal, destinationIsIndirect: true);
XS.Set(R10, xMethodLabel + EndOfMethodLabelNameNormal, size: RegisterSize.Long64);
XS.Set(AsmMarker.Labels[AsmMarker.Type.Int_LastKnownAddress], R10, true);

XS.Set(ECX, 0);
XS.Set(RCX, 0);

// Determine size of return value
uint xReturnSize = 0;
Expand Down Expand Up @@ -340,8 +342,8 @@ private void MethodEnd(Il2cpuMethodInfo aMethod)
// move return value
for (int i = 0; i < (int)(xReturnSize / 4); i++)
{
XS.Pop(EAX);
XS.Set(EBP, EAX, destinationDisplacement: (int)(xOffset + (i + 0) * 4));
XS.Pop(RAX);
XS.Set(RBP, RAX, destinationDisplacement: (int)(xOffset + (i + 0) * 4));
}
}
// extra stack space is the space reserved for example when a "public static int TestMethod();" method is called, 4 bytes is pushed, to make room for result;
Expand All @@ -359,42 +361,42 @@ private void MethodEnd(Il2cpuMethodInfo aMethod)

if (xLocalsSize >= 256)
{
XS.Add(ESP, 255);
XS.Add(RSP, 255);
xLocalsSize -= 255;
}
}
if (xLocalsSize > 0)
{
XS.Add(ESP, xLocalsSize);
XS.Add(RSP, xLocalsSize);
}
}

if (DebugEnabled && StackCorruptionDetection)
{
// if debugstub is active, emit a stack corruption detection. at this point EBP and ESP should have the same value.
// if not, we should somehow break here.
XS.Set(EAX, ESP);
XS.Set(EBX, EBP);
XS.Compare(EAX, EBX);
XS.Set(RAX, RSP);
XS.Set(RBX, RBP);
XS.Compare(RAX, RBX);
XS.Jump(ConditionalTestEnum.Equal, xLabelExc + "__2");
XS.ClearInterruptFlag();
// don't remove the call. It seems pointless, but we need it to retrieve the EIP value
XS.Call(".MethodFooterStackCorruptionCheck_Break_on_location");
XS.Label(xLabelExc + ".MethodFooterStackCorruptionCheck_Break_on_location");
XS.Exchange(BX, BX);
XS.Pop(ECX);
XS.Push(EAX);
XS.Push(EBX);
XS.Set(AsmMarker.Labels[AsmMarker.Type.DebugStub_CallerEIP], ECX, destinationIsIndirect: true);
XS.Pop(RCX);
XS.Push(RAX);
XS.Push(RBX);
XS.Set(AsmMarker.Labels[AsmMarker.Type.DebugStub_CallerEIP], RCX, destinationIsIndirect: true);
XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendSimpleNumber]);
XS.Add(ESP, 4);
XS.Add(RSP, 4);
XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendSimpleNumber]);
XS.Add(ESP, 4);
XS.Add(RSP, 4);
XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendStackCorruptedEvent]);
XS.Halt();
}
XS.Label(xLabelExc + "__2");
XS.Pop(EBP);
XS.Pop(RBP);
var xRetSize = xTotalArgsSize - (int)xReturnSize;
if (xRetSize < 0)
{
Expand Down Expand Up @@ -675,7 +677,7 @@ private void Call(Il2cpuMethodInfo aMethod, Il2cpuMethodInfo aTargetMethod, stri
}
if (xSize > 0)
{
XS.Sub(ESP, xSize);
XS.Sub(RSP, xSize);
}
XS.Call(ILOp.GetLabel(aTargetMethod));
var xMethodInfo = aMethod.MethodBase as MethodInfo;
Expand All @@ -696,7 +698,7 @@ private void Call(Il2cpuMethodInfo aMethod, Il2cpuMethodInfo aTargetMethod, stri
}
for (int i = 0; i < xResultSize / 4; i++)
{
XS.Add(ESP, 4);
XS.Add(RSP, 4);
}
}, aNextLabel);
}
Expand Down Expand Up @@ -733,8 +735,8 @@ public unsafe void GenerateVMTCode(HashSet<Type> aTypesSet, HashSet<MethodBase>
{
XS.Comment("---------------------------------------------------------");
XS.Label(InitVMTCodeLabel);
XS.Push(EBP);
XS.Set(EBP, ESP);
XS.Push(RBP);
XS.Set(RBP, RSP);

var xTypesFieldRef = VTablesImplRefs.VTablesImplDef.GetField("mTypes", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
string xTheName = LabelName.GetStaticFieldName(xTypesFieldRef);
Expand Down Expand Up @@ -775,12 +777,14 @@ public unsafe void GenerateVMTCode(HashSet<Type> aTypesSet, HashSet<MethodBase>

byte[] xData = AllocateEmptyArray(aTypesSet.Count, (int)ILOp.SizeOfType(VTableType), xArrayTypeID);
XS.DataMemberBytes(xTheName + "_Contents", xData);
XS.DataMember(xTheName, 1, "db", "0, 0, 0, 0, 0, 0, 0, 0");
XS.Set(xTheName, xTheName + "_Contents", destinationIsIndirect: true, destinationDisplacement: 4);
XS.DataMember(xTheName, 1, "db", "0, 0, 0, 0, 0, 0, 0, 0");
XS.Set(R10, xTheName + "_Contents", sourceIsIndirect: true);
XS.Set(xTheName, R10, destinationIsIndirect: true, destinationDisplacement: 4);
xData = AllocateEmptyArray(aTypesSet.Count, (int)ILOp.SizeOfType(GCTableType), xArrayTypeID);
XS.DataMemberBytes(xGCArrayName + "_Contents", xData);
XS.DataMember(xGCArrayName, 1, "db", "0, 0, 0, 0, 0, 0, 0, 0");
XS.Set(xGCArrayName, xGCArrayName + "_Contents", destinationIsIndirect: true, destinationDisplacement: 4);
XS.DataMember(xGCArrayName, 1, "db", "0, 0, 0, 0, 0, 0, 0, 0");
XS.Set(R10, xGCArrayName + "_Contents", sourceIsIndirect: true);
XS.Set(xGCArrayName, R10, destinationIsIndirect: true, destinationDisplacement: 4);
#if VMT_DEBUG
using (var xVmtDebugOutput = XmlWriter.Create(
File.Create(Path.Combine(mLogDir, @"vmt_debug.xml")), new XmlWriterSettings() { Indent = true }))
Expand Down Expand Up @@ -833,7 +837,7 @@ public unsafe void GenerateVMTCode(HashSet<Type> aTypesSet, HashSet<MethodBase>
// Type ID
string xDataName = $"VMT__TYPE_ID_HOLDER__{xTypeName}";
XS.Comment(xType.FullName);
XS.Set(xDataName, (uint)xTypeID, destinationIsIndirect: true, size: RegisterSize.Int32);
XS.Set(xDataName, (uint)xTypeID, destinationIsIndirect: true, size: RegisterSize.Long64);
XS.DataMember(xDataName, xTypeID);
XS.Push(xTypeID);

Expand Down Expand Up @@ -1021,7 +1025,7 @@ public unsafe void GenerateVMTCode(HashSet<Type> aTypesSet, HashSet<MethodBase>
#endif

XS.Label("_END_OF_" + InitVMTCodeLabel);
XS.Pop(EBP);
XS.Pop(RBP);
XS.Return();
}

Expand Down Expand Up @@ -1219,7 +1223,7 @@ internal void GenerateMethodForward(Il2cpuMethodInfo aFrom, Il2cpuMethodInfo aTo
if (xObjectPointerAccessAttrib != null)
{
XS.Comment("Skipping the reference to the next object reference.");
XS.Add(ESP, 4);
XS.Add(RSP, 4);
xExtraSpaceToSkipDueToObjectPointerAccess += 4;
}
else
Expand Down Expand Up @@ -1259,7 +1263,7 @@ internal void GenerateMethodForward(Il2cpuMethodInfo aFrom, Il2cpuMethodInfo aTo
{
xOriginalParamsIdx++;
Ldarg(aFrom, xCurParamIdx + xCurParamOffset);
XS.Add(ESP, 4);
XS.Add(RSP, 4);
xExtraSpaceToSkipDueToObjectPointerAccess += 4;
xCurParamIdx++;
}
Expand Down Expand Up @@ -1303,11 +1307,12 @@ public void EmitEntrypoint(MethodBase aEntrypoint, MethodBase[] aBootEntries = n
// at the time the datamembers for literal strings are created, the type id for string is not yet determined.
// for now, we fix this at runtime.
XS.Label(InitStringIDsLabel);
XS.Push(EBP);
XS.Set(EBP, ESP);
XS.Set(EAX, ILOp.GetTypeIDLabel(typeof(string)), sourceIsIndirect: true);
XS.Push(RBP);
XS.Set(RBP, RSP);
XS.Set(RAX, ILOp.GetTypeIDLabel(typeof(string)), sourceIsIndirect: true);
XS.Set(R10, LdStr.GetContentsArrayName(Assembler, ""));
XS.Set(LabelName.GetStaticFieldName(typeof(string).GetField("Empty", BindingFlags.Static | BindingFlags.Public)),
LdStr.GetContentsArrayName(Assembler, ""), destinationDisplacement: 4);
R10, destinationDisplacement: 4);

var xMemberId = 0;

Expand All @@ -1329,12 +1334,12 @@ public void EmitEntrypoint(MethodBase aEntrypoint, MethodBase[] aBootEntries = n
new Mov { DestinationRef = ElementReference.New(xDataMember.Name), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX };
}
Assembler.WriteDebugVideo("Done");
XS.Pop(EBP);
XS.Pop(RBP);
XS.Return();

XS.Label(CosmosAssembler.EntryPointName);
XS.Push(EBP);
XS.Set(EBP, ESP);
XS.Push(RBP);
XS.Set(RBP, RSP);
Assembler.WriteDebugVideo("Initializing VMT.");
XS.Call(InitVMTCodeLabel);
Assembler.WriteDebugVideo("Initializing string IDs.");
Expand All @@ -1350,7 +1355,7 @@ public void EmitEntrypoint(MethodBase aEntrypoint, MethodBase[] aBootEntries = n
XS.Label(xCurLabel);
X86.IL.Call.DoExecute(Assembler, null, aEntrypoint.DeclaringType.GetMethod("Start"), null, xCurLabel, CosmosAssembler.EntryPointName + ".AfterStart", DebugEnabled);
XS.Label(CosmosAssembler.EntryPointName + ".AfterStart");
XS.Pop(EBP);
XS.Pop(RBP);
XS.Return();

if (ShouldOptimize)
Expand Down Expand Up @@ -1434,27 +1439,27 @@ private void BeforeOp(Il2cpuMethodInfo aMethod, ILOpCode aOpCode, bool emitInt3N

// if debugstub is active, emit a stack corruption detection. at this point EBP and ESP should have the same value.
// if not, we should somehow break here.
XS.Set(EAX, ESP);
XS.Set(EBX, EBP);
XS.Set(RAX, RSP);
XS.Set(RBX, RBP);
if (xStackDifference != 0)
{
XS.Add(EAX, xStackDifference.Value);
XS.Add(RAX, xStackDifference.Value);
}
XS.Compare(EAX, EBX);
XS.Compare(RAX, RBX);
XS.Jump(ConditionalTestEnum.Equal, xLabel + ".StackCorruptionCheck_End");
XS.Push(EAX);
XS.Push(EBX);
XS.Push(RAX);
XS.Push(RBX);
XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendSimpleNumber]);
XS.Add(ESP, 4);
XS.Add(RSP, 4);
XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendSimpleNumber]);

XS.ClearInterruptFlag();
// don't remove the call. It seems pointless, but we need it to retrieve the EIP value
XS.Call(xLabel + ".StackCorruptionCheck_GetAddress");
XS.Label(xLabel + ".StackCorruptionCheck_GetAddress");
XS.Exchange(BX, BX);
XS.Pop(EAX);
XS.Set(AsmMarker.Labels[AsmMarker.Type.DebugStub_CallerEIP], EAX, destinationIsIndirect: true);
XS.Pop(RAX);
XS.Set(AsmMarker.Labels[AsmMarker.Type.DebugStub_CallerEIP], RAX, destinationIsIndirect: true);
XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendStackCorruptedEvent]);
XS.Halt();
XS.Label(xLabel + ".StackCorruptionCheck_End");
Expand Down
6 changes: 4 additions & 2 deletions source/Cosmos.IL2CPU/CompilerEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ public bool Execute()
xAsm.StackCorruptionDetectionLevel = mSettings.StackCorruptionDetectionLevel;
xAsm.DebugMode = mSettings.DebugMode;
xAsm.TraceAssemblies = mSettings.TraceAssemblies;
xAsm.IgnoreDebugStubAttribute = mSettings.IgnoreDebugStubAttribute;
xAsm.IgnoreDebugStubAttribute = mSettings.IgnoreDebugStubAttribute;
xAsm.TargetArchitecture = mSettings.TargetArchitecture;
if (!mSettings.EnableDebug)
{
xAsm.ShouldOptimize = true;
Expand All @@ -158,7 +159,8 @@ public bool Execute()
bool VBEMultiboot = mSettings.CompileVBEMultiboot;
string VBEResolution = string.IsNullOrEmpty(mSettings.VBEResolution) ? "800x600x32" : mSettings.VBEResolution;

xAsm.Assembler.RemoveBootDebugOutput = mSettings.RemoveBootDebugOutput;
xAsm.Assembler.RemoveBootDebugOutput = mSettings.RemoveBootDebugOutput;
xAsm.Assembler.TargetArchitecture = mSettings.TargetArchitecture;
xAsm.Assembler.Initialize(VBEMultiboot, VBEResolution);

if (mSettings.DebugMode != DebugMode.IL)
Expand Down
4 changes: 2 additions & 2 deletions source/Cosmos.IL2CPU/ConsoleCompilerEngineSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ internal class ConsoleCompilerEngineSettings : ICompilerEngineSettings
public bool RemoveBootDebugOutput => GetOption<bool>(nameof(RemoveBootDebugOutput));
public bool CompileVBEMultiboot => GetOption<bool>(nameof(CompileVBEMultiboot));
public string VBEResolution => GetOption<string>(nameof(VBEResolution));

public bool AllowComments => GetOption<bool>(nameof(AllowComments));
public bool AllowComments => GetOption<bool>(nameof(AllowComments));
public string TargetArchitecture => GetOption<string>(nameof(TargetArchitecture));

public ConsoleCompilerEngineSettings(string[] aArgs, Action<string> aLogMessage, Action<string> aLogError)
{
Expand Down
Loading