private U Link <T, U>(IEnumerable <StaticLibrary <T> > staticLibraries, Func <byte[], U> UConstructor, Config.OutputType outputType) where T : ObjectFile, new() where U : IPortableExecutable, new() { 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()) { File.Copy(GoLinkResourcePath, "GoLink.exe"); File.WriteAllText("input.txt", ""); var inputFiles = new List <string>(); foreach (var staticLibrary in staticLibraries) { foreach (var objectFile in staticLibrary.ObjectFiles) { var inputFilename = Utils.RandomString(5) + ".obj"; inputFiles.Add(inputFilename); File.WriteAllBytes(inputFilename, objectFile.Bytes); File.AppendAllText("input.txt", inputFilename + "\r\n"); } } var outputfilename = "OUTPUT" + outputExtension; var linkerOptions = CConfig.ToString(); if (linkerOptions.Length > 0) { linkerOptions = " " + linkerOptions; } var linkCommand = ""; linkCommand += " /fo " + outputfilename; linkCommand += linkerOptions; linkCommand += " " + "@input.txt"; // Attempt to link // If there are any mising symbols, then try to locate them in ImportStaticLibraryObjects // & add them to the linker input list if found and try again until there are no more missing symbols var missingSymbols = new List <string>(); switch (CConfig.ENTRY) { case "mainCRTStartup": case "wmainCRTStartup": case "WinMainCRTStartup": case "wWinMainCRTStartup": case "_DllMainCRTStartup": missingSymbols.Add(CConfig.ENTRY); break; } for (var i = 0; i < 10; i++) { // Find the object file(s) that contain the symbols that are missing foreach (var symbol in missingSymbols) { foreach (var slObject in ImportStaticLibraryObjects) { if (slObject.ExternalSymbols.Contains(symbol)) { using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) { string hash = BitConverter.ToString(sha1.ComputeHash(slObject.Bytes)).Replace("-", ""); File.WriteAllBytes($"{hash}.obj", slObject.Bytes); File.AppendAllText("input.txt", $"{hash}.obj\r\n"); } break; } } } missingSymbols.Clear(); Process process = new Process(); process.StartInfo.FileName = "GoLink.exe"; process.StartInfo.Arguments = linkCommand; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.Start(); bool isMissingSymbols = false; while (!process.StandardOutput.EndOfStream) { string line = process.StandardOutput.ReadLine().Trim(); if (isMissingSymbols) { if (line != "") { missingSymbols.Add(line); } } if (line.Contains("symbols were not defined")) { isMissingSymbols = true; } } if (!isMissingSymbols) { break; } if (ImportStaticLibraryObjects.Count() == 0) { break; } } var pe = UConstructor(File.ReadAllBytes(outputfilename)); return(pe); } }
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); } }