private IEnumerable <T> Assmeble <T>(AssemblySource <MASM> assemblySource, TargetArch targetArch, Func <byte[], T> TConstructor) where T : ObjectFile, new() { List <T> objectFiles = new List <T>(); using (new TemporaryContext()) { foreach (var sourceFile in assemblySource.SourceFiles) { System.IO.File.WriteAllBytes(sourceFile.Filename, sourceFile.Bytes); } foreach (var sourceFile in assemblySource.SourceFiles.Where(sf => sf.Type == AssemblySourceFileType.Asm)) { var program = targetArch == TargetArch.x64 ? "ml64.exe" : "ml.exe"; var arguments = String.Format("/nologo /Fo object.obj /c /Cx {0}", sourceFile.Filename); var assembleCommand = program + " " + arguments; var msvcVersion = version.ToString().Replace("v", "").Replace("_", "."); var assembleBatFile = @"call ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\VCVARSALL.bat"" {0} -vcvars_ver=" + msvcVersion + "\r\n" + assembleCommand; assembleBatFile = String.Format(assembleBatFile, targetArch.ToString()); File.WriteAllText("assemble.bat", assembleBatFile); var proc = Process.Start("cmd.exe", "/c " + "assemble.bat"); proc.WaitForExit(); if (!System.IO.File.Exists("object.obj")) { throw new Exception("Masm error. Object file not found."); } var objectFileBytes = System.IO.File.ReadAllBytes("object.obj"); objectFiles.Add(TConstructor(objectFileBytes)); } } return(objectFiles); }
// TODO: Support compiling source files recursively private StaticLibrary <T> Compile <T>(ICCxxSource source, TargetArch targetArch, Func <byte[], T> TConstructor) where T : ObjectFile, new() { switch (targetArch) { case TargetArch.x86: CConfig.MACHINE = Config.Machine.X86; break; case TargetArch.x64: CConfig.MACHINE = Config.Machine.X64; break; case TargetArch.arm: case TargetArch.arm64: CConfig.MACHINE = Config.Machine.ARM; break; } using (new TemporaryContext()) { var exts = new HashSet <string>(); foreach (var sourceFile in source.SourceFiles) { File.WriteAllText(sourceFile.Filename, sourceFile.Source); if (sourceFile.Type == CCxxSourceFileType.C || sourceFile.Type == CCxxSourceFileType.Cxx) { exts.Add(Path.GetExtension(sourceFile.Filename)); } } var sourceFilenames = exts.Select(ext => "*" + ext); var compilerOptions = CConfig.ToString(); var compileCommand = $"cl.exe /c /nologo /diagnostics:column {compilerOptions} {string.Join(" ", sourceFilenames)}"; var msvcVersion = version.ToString().Replace("v", "").Replace("_", "."); var compileBatFile = @"call ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\VCVARSALL.bat"" {0} -vcvars_ver=" + msvcVersion + "\r\n" + compileCommand; compileBatFile = String.Format(compileBatFile, targetArch.ToString()); File.WriteAllText("compile.bat", compileBatFile); var proc = Process.Start("cmd.exe", "/c " + "compile.bat"); proc.WaitForExit(); string[] objectFilePaths = Directory.GetFiles(".", "*.obj", SearchOption.AllDirectories); var objectFiles = objectFilePaths.ToList().Select((file) => TConstructor(File.ReadAllBytes(file))).ToList(); return(new StaticLibrary <T>(objectFiles)); } }
private U Link <T, U>(IEnumerable <StaticLibrary <T> > staticLibraries, TargetArch targetArch, Func <byte[], U> UConstructor, Config.OutputType outputType) where T : ObjectFile, new() where U : IPortableExecutable, new() { switch (targetArch) { case TargetArch.x86: CConfig.MACHINE = Config.Machine.X86; break; case TargetArch.x64: CConfig.MACHINE = Config.Machine.X64; break; case TargetArch.arm: case TargetArch.arm64: CConfig.MACHINE = Config.Machine.ARM; break; } var outputExtension = ".exe"; switch (outputType) { case Config.OutputType.EXE: CConfig.outputType = Config.OutputType.EXE; outputExtension = ".exe"; break; case Config.OutputType.DLL: CConfig.outputType = Config.OutputType.DLL; outputExtension = ".dll"; break; case Config.OutputType.DRIVER: CConfig.outputType = Config.OutputType.DRIVER; outputExtension = ".sys"; break; } using (new TemporaryContext()) { foreach (var staticLibrary in staticLibraries) { foreach (var objectFile in staticLibrary.ObjectFiles) { File.WriteAllBytes(Core.Utils.RandomString(10) + ".obj", objectFile.Bytes); } } var outputfilename = "OUTPUT" + outputExtension; var linkerOptions = CConfig.ToString(); if (linkerOptions.Length > 0) { linkerOptions = " " + linkerOptions; } var linkCommand = "link.exe"; linkCommand += " /out:" + outputfilename; linkCommand += " /NOLOGO"; linkCommand += linkerOptions; linkCommand += " *.obj"; var msvcVersion = version.ToString().Replace("v", "").Replace("_", "."); var linkBatFile = @"call ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\VCVARSALL.bat"" {0} -vcvars_ver=" + msvcVersion + "\r\n" + linkCommand; linkBatFile = String.Format(linkBatFile, targetArch.ToString()); File.WriteAllText("link.bat", linkBatFile); var proc = Process.Start("cmd.exe", "/c " + "link.bat"); proc.WaitForExit(); var pe = UConstructor(File.ReadAllBytes(outputfilename)); if (CConfig.MAP) { pe.Map = File.ReadAllText("OUTPUT.map"); } return(pe); } }
internal static StaticLibrary <T> LibFileToStaticLibrary <T>(string libFile, Func <byte[], T> TConstructor, TargetArch targetArch, Version version = Version.v14_16, IEnumerable <string> includeFilter = null) where T : ObjectFile, new() { var objectPaths = new List <string>(); using (new TemporaryContext()) { var command = $"lib.exe /nologo /list {libFile}"; var msvcVersion = version.ToString().Replace("v", "").Replace("_", "."); var listBatFile = @"call ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\VCVARSALL.bat"" {0} -vcvars_ver=" + msvcVersion + "\r\n" + command; listBatFile = String.Format(listBatFile, targetArch.ToString()); File.WriteAllText("list.bat", listBatFile); Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.Arguments = "/c list.bat"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.Start(); while (!process.StandardOutput.EndOfStream) { string line = process.StandardOutput.ReadLine(); if (line.Contains("**")) { continue; } if (line.ToLower().Contains("vcvars")) { continue; } if (line != "") { objectPaths.Add(line); } } process.WaitForExit(); } objectPaths = objectPaths.Where(x => includeFilter == null || includeFilter.Any(y => x.Contains(y))).ToList(); using (new TemporaryContext()) { var msvcVersion = version.ToString().Replace("v", "").Replace("_", "."); var extractBatFile = @"call ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\VCVARSALL.bat"" {0} -vcvars_ver=" + msvcVersion + "\r\n"; extractBatFile = String.Format(extractBatFile, targetArch.ToString()); File.WriteAllText("extract.bat", extractBatFile); foreach (var objectPath in objectPaths) { var command = $"lib.exe /nologo {libFile} /EXTRACT:{objectPath}"; File.AppendAllText("extract.bat", $"\r\n{command}"); } Process.Start("cmd.exe", "/c extract.bat").WaitForExit(); // Parse the object files for their Symbol names string[] objectFilePaths = Directory.GetFiles(".", "*.obj", SearchOption.AllDirectories); var symbolsBatFile = @"call ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\VCVARSALL.bat"" {0} -vcvars_ver=" + msvcVersion + "\r\n"; symbolsBatFile = String.Format(symbolsBatFile, targetArch.ToString()); File.WriteAllText("symbols.bat", symbolsBatFile); foreach (var objectFilePath in objectFilePaths) { var command = $"dumpbin /symbols {objectFilePath} | findstr External | findstr -v UNDEF > {objectFilePath}.txt"; File.AppendAllText("symbols.bat", $"\r\n{command}"); } Process.Start("cmd.exe", "/c symbols.bat").WaitForExit(); var objectFiles = new List <T>(); foreach (var objectFilePath in objectFilePaths) { var symbols = new List <string>(); var objectFile = TConstructor(File.ReadAllBytes(objectFilePath)); var lines = File.ReadLines($"{objectFilePath}.txt"); foreach (var line in lines) { var line2 = line.Trim(); if (line2 == "") { continue; } var symbol = line.Split("| ")[1]; symbols.Add(symbol); } objectFile.ExternalSymbols = symbols; objectFiles.Add(objectFile); } return(new StaticLibrary <T>(objectFiles)); } }