using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Indy.IL2CPU.Assembler { public class Assembler: IDisposable { public enum OutputTypeEnum { DLL, Console, GUI } public const string EntryPointLabelName = "___ENTRYPOINT___"; private List mInstructions = new List(); private List mDataMembers = new List(); private OutputTypeEnum mOutputType = OutputTypeEnum.DLL; private StreamWriter mOutputWriter; private List mIncludes = new List(); private List mImportMembers = new List(); private readonly bool mInMetalMode = false; private uint mDataMemberCounter = 0; public string GetIdentifier(string aPrefix) { return aPrefix + mDataMemberCounter++.ToString("X8").ToUpper(); } public Assembler(StreamWriter aOutputWriter) : this(aOutputWriter, false) { } public Assembler(StreamWriter aOutputWriter, bool aInMetalMode) { mOutputWriter = aOutputWriter; mInMetalMode = aInMetalMode; } public OutputTypeEnum OutputType { get { return mOutputType; } set { mOutputType = value; } } public List Includes { get { return mIncludes; } } public List DataMembers { get { return mDataMembers; } } public List ImportMembers { get { return mImportMembers; } } public bool InMetalMode { get { return mInMetalMode; } } public void Dispose() { // MtW: I know, IDisposable usage for this isn't really nice, but for now this should be fine. mInstructions.Clear(); mDataMembers.Clear(); } public void Add(params Instruction[] aInstructions) { foreach (Instruction xInstruction in aInstructions) { mInstructions.Add(xInstruction); } } public void Flush() { // write .asm header switch (mOutputType) { case OutputTypeEnum.Console: mOutputWriter.WriteLine("format PE console"); break; case OutputTypeEnum.GUI: mOutputWriter.WriteLine("format PE GUI 4.0"); break; default: mOutputWriter.WriteLine("format PE dll"); break; } if (mOutputType != OutputTypeEnum.DLL) { mOutputWriter.WriteLine("entry " + EntryPointLabelName); } mOutputWriter.WriteLine(); foreach (string xInclude in mIncludes) { mOutputWriter.WriteLine("include '{0}'", xInclude); } mOutputWriter.WriteLine(); if (mDataMembers.Count > 0) { mOutputWriter.WriteLine("section '.data' data readable writeable"); mOutputWriter.WriteLine(); foreach (DataMember xMember in mDataMembers) { mOutputWriter.WriteLine("\t" + xMember); } mOutputWriter.WriteLine(); } if (mInstructions.Count > 0) { mOutputWriter.WriteLine("section '.code' code readable executable"); mOutputWriter.WriteLine(); mOutputWriter.WriteLine("\t" + EntryPointLabelName + ":"); foreach (Instruction x in mInstructions) { string prefix = "\t\t\t"; if (x is Label) { mOutputWriter.WriteLine(); if (x.ToString()[0] == '.') { prefix = "\t\t"; } else { prefix = "\t"; } } mOutputWriter.WriteLine(prefix + x); } mOutputWriter.WriteLine(); } if (mImportMembers.Count > 0) { mOutputWriter.WriteLine("section '.idata' import data readable writeable"); mOutputWriter.WriteLine(); foreach (ImportMember xImportMember in mImportMembers) { mOutputWriter.WriteLine("\tdd 0,0,0,rva {0}_name,rva {0}_table", xImportMember.Name); } mOutputWriter.WriteLine("\tdd 0,0,0,0,0"); mOutputWriter.WriteLine(); foreach (ImportMember xImportMember in mImportMembers) { mOutputWriter.WriteLine("\t{0}_table:", xImportMember.Name); foreach (ImportMethodMember xImportMethod in xImportMember.Methods) { mOutputWriter.WriteLine("\t\t{0} dd rva _{0}", xImportMethod.Name); } mOutputWriter.WriteLine("\t\tdd 0"); mOutputWriter.WriteLine(); } foreach (ImportMember xImportMember in mImportMembers) { mOutputWriter.WriteLine("\t{0}_name db '{1}',0", xImportMember.Name, xImportMember.FileName); } mOutputWriter.WriteLine(); foreach (ImportMember xImportMember in mImportMembers) { foreach (ImportMethodMember xImportMethod in xImportMember.Methods) { mOutputWriter.WriteLine("\t_{0} dw 0", xImportMethod.Name); mOutputWriter.WriteLine("\tdb '{0}',0", xImportMethod.Name); } } } } } }