Path: blob/main/contrib/llvm-project/lld/COFF/Driver.cpp
34870 views
//===- Driver.cpp ---------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Driver.h"9#include "COFFLinkerContext.h"10#include "Config.h"11#include "DebugTypes.h"12#include "ICF.h"13#include "InputFiles.h"14#include "MarkLive.h"15#include "MinGW.h"16#include "SymbolTable.h"17#include "Symbols.h"18#include "Writer.h"19#include "lld/Common/Args.h"20#include "lld/Common/CommonLinkerContext.h"21#include "lld/Common/Driver.h"22#include "lld/Common/Filesystem.h"23#include "lld/Common/Timer.h"24#include "lld/Common/Version.h"25#include "llvm/ADT/IntrusiveRefCntPtr.h"26#include "llvm/ADT/StringSwitch.h"27#include "llvm/BinaryFormat/Magic.h"28#include "llvm/Config/llvm-config.h"29#include "llvm/LTO/LTO.h"30#include "llvm/Object/ArchiveWriter.h"31#include "llvm/Object/COFFImportFile.h"32#include "llvm/Object/COFFModuleDefinition.h"33#include "llvm/Option/Arg.h"34#include "llvm/Option/ArgList.h"35#include "llvm/Option/Option.h"36#include "llvm/Support/BinaryStreamReader.h"37#include "llvm/Support/CommandLine.h"38#include "llvm/Support/Debug.h"39#include "llvm/Support/LEB128.h"40#include "llvm/Support/MathExtras.h"41#include "llvm/Support/Parallel.h"42#include "llvm/Support/Path.h"43#include "llvm/Support/Process.h"44#include "llvm/Support/TarWriter.h"45#include "llvm/Support/TargetSelect.h"46#include "llvm/Support/TimeProfiler.h"47#include "llvm/Support/VirtualFileSystem.h"48#include "llvm/Support/raw_ostream.h"49#include "llvm/TargetParser/Triple.h"50#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"51#include <algorithm>52#include <future>53#include <memory>54#include <optional>55#include <tuple>5657using namespace llvm;58using namespace llvm::object;59using namespace llvm::COFF;60using namespace llvm::sys;6162namespace lld::coff {6364bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,65llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {66// This driver-specific context will be freed later by unsafeLldMain().67auto *ctx = new COFFLinkerContext;6869ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);70ctx->e.logName = args::getFilenameWithoutExe(args[0]);71ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now"72" (use /errorlimit:0 to see all errors)";7374ctx->driver.linkerMain(args);7576return errorCount() == 0;77}7879// Parse options of the form "old;new".80static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,81unsigned id) {82auto *arg = args.getLastArg(id);83if (!arg)84return {"", ""};8586StringRef s = arg->getValue();87std::pair<StringRef, StringRef> ret = s.split(';');88if (ret.second.empty())89error(arg->getSpelling() + " expects 'old;new' format, but got " + s);90return ret;91}9293// Parse options of the form "old;new[;extra]".94static std::tuple<StringRef, StringRef, StringRef>95getOldNewOptionsExtra(opt::InputArgList &args, unsigned id) {96auto [oldDir, second] = getOldNewOptions(args, id);97auto [newDir, extraDir] = second.split(';');98return {oldDir, newDir, extraDir};99}100101// Drop directory components and replace extension with102// ".exe", ".dll" or ".sys".103static std::string getOutputPath(StringRef path, bool isDll, bool isDriver) {104StringRef ext = ".exe";105if (isDll)106ext = ".dll";107else if (isDriver)108ext = ".sys";109110return (sys::path::stem(path) + ext).str();111}112113// Returns true if S matches /crtend.?\.o$/.114static bool isCrtend(StringRef s) {115if (!s.ends_with(".o"))116return false;117s = s.drop_back(2);118if (s.ends_with("crtend"))119return true;120return !s.empty() && s.drop_back().ends_with("crtend");121}122123// ErrorOr is not default constructible, so it cannot be used as the type124// parameter of a future.125// FIXME: We could open the file in createFutureForFile and avoid needing to126// return an error here, but for the moment that would cost us a file descriptor127// (a limited resource on Windows) for the duration that the future is pending.128using MBErrPair = std::pair<std::unique_ptr<MemoryBuffer>, std::error_code>;129130// Create a std::future that opens and maps a file using the best strategy for131// the host platform.132static std::future<MBErrPair> createFutureForFile(std::string path) {133#if _WIN64134// On Windows, file I/O is relatively slow so it is best to do this135// asynchronously. But 32-bit has issues with potentially launching tons136// of threads137auto strategy = std::launch::async;138#else139auto strategy = std::launch::deferred;140#endif141return std::async(strategy, [=]() {142auto mbOrErr = MemoryBuffer::getFile(path, /*IsText=*/false,143/*RequiresNullTerminator=*/false);144if (!mbOrErr)145return MBErrPair{nullptr, mbOrErr.getError()};146return MBErrPair{std::move(*mbOrErr), std::error_code()};147});148}149150// Symbol names are mangled by prepending "_" on x86.151StringRef LinkerDriver::mangle(StringRef sym) {152assert(ctx.config.machine != IMAGE_FILE_MACHINE_UNKNOWN);153if (ctx.config.machine == I386)154return saver().save("_" + sym);155return sym;156}157158llvm::Triple::ArchType LinkerDriver::getArch() {159return getMachineArchType(ctx.config.machine);160}161162bool LinkerDriver::findUnderscoreMangle(StringRef sym) {163Symbol *s = ctx.symtab.findMangle(mangle(sym));164return s && !isa<Undefined>(s);165}166167MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {168MemoryBufferRef mbref = *mb;169make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take ownership170171if (ctx.driver.tar)172ctx.driver.tar->append(relativeToRoot(mbref.getBufferIdentifier()),173mbref.getBuffer());174return mbref;175}176177void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,178bool wholeArchive, bool lazy) {179StringRef filename = mb->getBufferIdentifier();180181MemoryBufferRef mbref = takeBuffer(std::move(mb));182filePaths.push_back(filename);183184// File type is detected by contents, not by file extension.185switch (identify_magic(mbref.getBuffer())) {186case file_magic::windows_resource:187resources.push_back(mbref);188break;189case file_magic::archive:190if (wholeArchive) {191std::unique_ptr<Archive> file =192CHECK(Archive::create(mbref), filename + ": failed to parse archive");193Archive *archive = file.get();194make<std::unique_ptr<Archive>>(std::move(file)); // take ownership195196int memberIndex = 0;197for (MemoryBufferRef m : getArchiveMembers(archive))198addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++);199return;200}201ctx.symtab.addFile(make<ArchiveFile>(ctx, mbref));202break;203case file_magic::bitcode:204ctx.symtab.addFile(make<BitcodeFile>(ctx, mbref, "", 0, lazy));205break;206case file_magic::coff_object:207case file_magic::coff_import_library:208ctx.symtab.addFile(make<ObjFile>(ctx, mbref, lazy));209break;210case file_magic::pdb:211ctx.symtab.addFile(make<PDBInputFile>(ctx, mbref));212break;213case file_magic::coff_cl_gl_object:214error(filename + ": is not a native COFF file. Recompile without /GL");215break;216case file_magic::pecoff_executable:217if (ctx.config.mingw) {218ctx.symtab.addFile(make<DLLFile>(ctx, mbref));219break;220}221if (filename.ends_with_insensitive(".dll")) {222error(filename + ": bad file type. Did you specify a DLL instead of an "223"import library?");224break;225}226[[fallthrough]];227default:228error(mbref.getBufferIdentifier() + ": unknown file type");229break;230}231}232233void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {234auto future = std::make_shared<std::future<MBErrPair>>(235createFutureForFile(std::string(path)));236std::string pathStr = std::string(path);237enqueueTask([=]() {238llvm::TimeTraceScope timeScope("File: ", path);239auto [mb, ec] = future->get();240if (ec) {241// Retry reading the file (synchronously) now that we may have added242// winsysroot search paths from SymbolTable::addFile().243// Retrying synchronously is important for keeping the order of inputs244// consistent.245// This makes it so that if the user passes something in the winsysroot246// before something we can find with an architecture, we won't find the247// winsysroot file.248if (std::optional<StringRef> retryPath = findFileIfNew(pathStr)) {249auto retryMb = MemoryBuffer::getFile(*retryPath, /*IsText=*/false,250/*RequiresNullTerminator=*/false);251ec = retryMb.getError();252if (!ec)253mb = std::move(*retryMb);254} else {255// We've already handled this file.256return;257}258}259if (ec) {260std::string msg = "could not open '" + pathStr + "': " + ec.message();261// Check if the filename is a typo for an option flag. OptTable thinks262// that all args that are not known options and that start with / are263// filenames, but e.g. `/nodefaultlibs` is more likely a typo for264// the option `/nodefaultlib` than a reference to a file in the root265// directory.266std::string nearest;267if (ctx.optTable.findNearest(pathStr, nearest) > 1)268error(msg);269else270error(msg + "; did you mean '" + nearest + "'");271} else272ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy);273});274}275276void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,277StringRef parentName,278uint64_t offsetInArchive) {279file_magic magic = identify_magic(mb.getBuffer());280if (magic == file_magic::coff_import_library) {281InputFile *imp = make<ImportFile>(ctx, mb);282imp->parentName = parentName;283ctx.symtab.addFile(imp);284return;285}286287InputFile *obj;288if (magic == file_magic::coff_object) {289obj = make<ObjFile>(ctx, mb);290} else if (magic == file_magic::bitcode) {291obj =292make<BitcodeFile>(ctx, mb, parentName, offsetInArchive, /*lazy=*/false);293} else if (magic == file_magic::coff_cl_gl_object) {294error(mb.getBufferIdentifier() +295": is not a native COFF file. Recompile without /GL?");296return;297} else {298error("unknown file type: " + mb.getBufferIdentifier());299return;300}301302obj->parentName = parentName;303ctx.symtab.addFile(obj);304log("Loaded " + toString(obj) + " for " + symName);305}306307void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,308const Archive::Symbol &sym,309StringRef parentName) {310311auto reportBufferError = [=](Error &&e, StringRef childName) {312fatal("could not get the buffer for the member defining symbol " +313toCOFFString(ctx, sym) + ": " + parentName + "(" + childName +314"): " + toString(std::move(e)));315};316317if (!c.getParent()->isThin()) {318uint64_t offsetInArchive = c.getChildOffset();319Expected<MemoryBufferRef> mbOrErr = c.getMemoryBufferRef();320if (!mbOrErr)321reportBufferError(mbOrErr.takeError(), check(c.getFullName()));322MemoryBufferRef mb = mbOrErr.get();323enqueueTask([=]() {324llvm::TimeTraceScope timeScope("Archive: ", mb.getBufferIdentifier());325ctx.driver.addArchiveBuffer(mb, toCOFFString(ctx, sym), parentName,326offsetInArchive);327});328return;329}330331std::string childName =332CHECK(c.getFullName(),333"could not get the filename for the member defining symbol " +334toCOFFString(ctx, sym));335auto future =336std::make_shared<std::future<MBErrPair>>(createFutureForFile(childName));337enqueueTask([=]() {338auto mbOrErr = future->get();339if (mbOrErr.second)340reportBufferError(errorCodeToError(mbOrErr.second), childName);341llvm::TimeTraceScope timeScope("Archive: ",342mbOrErr.first->getBufferIdentifier());343// Pass empty string as archive name so that the original filename is344// used as the buffer identifier.345ctx.driver.addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)),346toCOFFString(ctx, sym), "",347/*OffsetInArchive=*/0);348});349}350351bool LinkerDriver::isDecorated(StringRef sym) {352return sym.starts_with("@") || sym.contains("@@") || sym.starts_with("?") ||353(!ctx.config.mingw && sym.contains('@'));354}355356// Parses .drectve section contents and returns a list of files357// specified by /defaultlib.358void LinkerDriver::parseDirectives(InputFile *file) {359StringRef s = file->getDirectives();360if (s.empty())361return;362363log("Directives: " + toString(file) + ": " + s);364365ArgParser parser(ctx);366// .drectve is always tokenized using Windows shell rules.367// /EXPORT: option can appear too many times, processing in fastpath.368ParsedDirectives directives = parser.parseDirectives(s);369370for (StringRef e : directives.exports) {371// If a common header file contains dllexported function372// declarations, many object files may end up with having the373// same /EXPORT options. In order to save cost of parsing them,374// we dedup them first.375if (!directivesExports.insert(e).second)376continue;377378Export exp = parseExport(e);379if (ctx.config.machine == I386 && ctx.config.mingw) {380if (!isDecorated(exp.name))381exp.name = saver().save("_" + exp.name);382if (!exp.extName.empty() && !isDecorated(exp.extName))383exp.extName = saver().save("_" + exp.extName);384}385exp.source = ExportSource::Directives;386ctx.config.exports.push_back(exp);387}388389// Handle /include: in bulk.390for (StringRef inc : directives.includes)391addUndefined(inc);392393// Handle /exclude-symbols: in bulk.394for (StringRef e : directives.excludes) {395SmallVector<StringRef, 2> vec;396e.split(vec, ',');397for (StringRef sym : vec)398excludedSymbols.insert(mangle(sym));399}400401// https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160402for (auto *arg : directives.args) {403switch (arg->getOption().getID()) {404case OPT_aligncomm:405parseAligncomm(arg->getValue());406break;407case OPT_alternatename:408parseAlternateName(arg->getValue());409break;410case OPT_defaultlib:411if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))412enqueuePath(*path, false, false);413break;414case OPT_entry:415if (!arg->getValue()[0])416fatal("missing entry point symbol name");417ctx.config.entry = addUndefined(mangle(arg->getValue()));418break;419case OPT_failifmismatch:420checkFailIfMismatch(arg->getValue(), file);421break;422case OPT_incl:423addUndefined(arg->getValue());424break;425case OPT_manifestdependency:426ctx.config.manifestDependencies.insert(arg->getValue());427break;428case OPT_merge:429parseMerge(arg->getValue());430break;431case OPT_nodefaultlib:432ctx.config.noDefaultLibs.insert(findLib(arg->getValue()).lower());433break;434case OPT_release:435ctx.config.writeCheckSum = true;436break;437case OPT_section:438parseSection(arg->getValue());439break;440case OPT_stack:441parseNumbers(arg->getValue(), &ctx.config.stackReserve,442&ctx.config.stackCommit);443break;444case OPT_subsystem: {445bool gotVersion = false;446parseSubsystem(arg->getValue(), &ctx.config.subsystem,447&ctx.config.majorSubsystemVersion,448&ctx.config.minorSubsystemVersion, &gotVersion);449if (gotVersion) {450ctx.config.majorOSVersion = ctx.config.majorSubsystemVersion;451ctx.config.minorOSVersion = ctx.config.minorSubsystemVersion;452}453break;454}455// Only add flags here that link.exe accepts in456// `#pragma comment(linker, "/flag")`-generated sections.457case OPT_editandcontinue:458case OPT_guardsym:459case OPT_throwingnew:460case OPT_inferasanlibs:461case OPT_inferasanlibs_no:462break;463default:464error(arg->getSpelling() + " is not allowed in .drectve (" +465toString(file) + ")");466}467}468}469470// Find file from search paths. You can omit ".obj", this function takes471// care of that. Note that the returned path is not guaranteed to exist.472StringRef LinkerDriver::findFile(StringRef filename) {473auto getFilename = [this](StringRef filename) -> StringRef {474if (ctx.config.vfs)475if (auto statOrErr = ctx.config.vfs->status(filename))476return saver().save(statOrErr->getName());477return filename;478};479480if (sys::path::is_absolute(filename))481return getFilename(filename);482bool hasExt = filename.contains('.');483for (StringRef dir : searchPaths) {484SmallString<128> path = dir;485sys::path::append(path, filename);486path = SmallString<128>{getFilename(path.str())};487if (sys::fs::exists(path.str()))488return saver().save(path.str());489if (!hasExt) {490path.append(".obj");491path = SmallString<128>{getFilename(path.str())};492if (sys::fs::exists(path.str()))493return saver().save(path.str());494}495}496return filename;497}498499static std::optional<sys::fs::UniqueID> getUniqueID(StringRef path) {500sys::fs::UniqueID ret;501if (sys::fs::getUniqueID(path, ret))502return std::nullopt;503return ret;504}505506// Resolves a file path. This never returns the same path507// (in that case, it returns std::nullopt).508std::optional<StringRef> LinkerDriver::findFileIfNew(StringRef filename) {509StringRef path = findFile(filename);510511if (std::optional<sys::fs::UniqueID> id = getUniqueID(path)) {512bool seen = !visitedFiles.insert(*id).second;513if (seen)514return std::nullopt;515}516517if (path.ends_with_insensitive(".lib"))518visitedLibs.insert(std::string(sys::path::filename(path).lower()));519return path;520}521522// MinGW specific. If an embedded directive specified to link to523// foo.lib, but it isn't found, try libfoo.a instead.524StringRef LinkerDriver::findLibMinGW(StringRef filename) {525if (filename.contains('/') || filename.contains('\\'))526return filename;527528SmallString<128> s = filename;529sys::path::replace_extension(s, ".a");530StringRef libName = saver().save("lib" + s.str());531return findFile(libName);532}533534// Find library file from search path.535StringRef LinkerDriver::findLib(StringRef filename) {536// Add ".lib" to Filename if that has no file extension.537bool hasExt = filename.contains('.');538if (!hasExt)539filename = saver().save(filename + ".lib");540StringRef ret = findFile(filename);541// For MinGW, if the find above didn't turn up anything, try542// looking for a MinGW formatted library name.543if (ctx.config.mingw && ret == filename)544return findLibMinGW(filename);545return ret;546}547548// Resolves a library path. /nodefaultlib options are taken into549// consideration. This never returns the same path (in that case,550// it returns std::nullopt).551std::optional<StringRef> LinkerDriver::findLibIfNew(StringRef filename) {552if (ctx.config.noDefaultLibAll)553return std::nullopt;554if (!visitedLibs.insert(filename.lower()).second)555return std::nullopt;556557StringRef path = findLib(filename);558if (ctx.config.noDefaultLibs.count(path.lower()))559return std::nullopt;560561if (std::optional<sys::fs::UniqueID> id = getUniqueID(path))562if (!visitedFiles.insert(*id).second)563return std::nullopt;564return path;565}566567void LinkerDriver::detectWinSysRoot(const opt::InputArgList &Args) {568IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();569570// Check the command line first, that's the user explicitly telling us what to571// use. Check the environment next, in case we're being invoked from a VS572// command prompt. Failing that, just try to find the newest Visual Studio573// version we can and use its default VC toolchain.574std::optional<StringRef> VCToolsDir, VCToolsVersion, WinSysRoot;575if (auto *A = Args.getLastArg(OPT_vctoolsdir))576VCToolsDir = A->getValue();577if (auto *A = Args.getLastArg(OPT_vctoolsversion))578VCToolsVersion = A->getValue();579if (auto *A = Args.getLastArg(OPT_winsysroot))580WinSysRoot = A->getValue();581if (!findVCToolChainViaCommandLine(*VFS, VCToolsDir, VCToolsVersion,582WinSysRoot, vcToolChainPath, vsLayout) &&583(Args.hasArg(OPT_lldignoreenv) ||584!findVCToolChainViaEnvironment(*VFS, vcToolChainPath, vsLayout)) &&585!findVCToolChainViaSetupConfig(*VFS, {}, vcToolChainPath, vsLayout) &&586!findVCToolChainViaRegistry(vcToolChainPath, vsLayout))587return;588589// If the VC environment hasn't been configured (perhaps because the user did590// not run vcvarsall), try to build a consistent link environment. If the591// environment variable is set however, assume the user knows what they're592// doing. If the user passes /vctoolsdir or /winsdkdir, trust that over env593// vars.594if (const auto *A = Args.getLastArg(OPT_diasdkdir, OPT_winsysroot)) {595diaPath = A->getValue();596if (A->getOption().getID() == OPT_winsysroot)597path::append(diaPath, "DIA SDK");598}599useWinSysRootLibPath = Args.hasArg(OPT_lldignoreenv) ||600!Process::GetEnv("LIB") ||601Args.getLastArg(OPT_vctoolsdir, OPT_winsysroot);602if (Args.hasArg(OPT_lldignoreenv) || !Process::GetEnv("LIB") ||603Args.getLastArg(OPT_winsdkdir, OPT_winsysroot)) {604std::optional<StringRef> WinSdkDir, WinSdkVersion;605if (auto *A = Args.getLastArg(OPT_winsdkdir))606WinSdkDir = A->getValue();607if (auto *A = Args.getLastArg(OPT_winsdkversion))608WinSdkVersion = A->getValue();609610if (useUniversalCRT(vsLayout, vcToolChainPath, getArch(), *VFS)) {611std::string UniversalCRTSdkPath;612std::string UCRTVersion;613if (getUniversalCRTSdkDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot,614UniversalCRTSdkPath, UCRTVersion)) {615universalCRTLibPath = UniversalCRTSdkPath;616path::append(universalCRTLibPath, "Lib", UCRTVersion, "ucrt");617}618}619620std::string sdkPath;621std::string windowsSDKIncludeVersion;622std::string windowsSDKLibVersion;623if (getWindowsSDKDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot, sdkPath,624sdkMajor, windowsSDKIncludeVersion,625windowsSDKLibVersion)) {626windowsSdkLibPath = sdkPath;627path::append(windowsSdkLibPath, "Lib");628if (sdkMajor >= 8)629path::append(windowsSdkLibPath, windowsSDKLibVersion, "um");630}631}632}633634void LinkerDriver::addClangLibSearchPaths(const std::string &argv0) {635std::string lldBinary = sys::fs::getMainExecutable(argv0.c_str(), nullptr);636SmallString<128> binDir(lldBinary);637sys::path::remove_filename(binDir); // remove lld-link.exe638StringRef rootDir = sys::path::parent_path(binDir); // remove 'bin'639640SmallString<128> libDir(rootDir);641sys::path::append(libDir, "lib");642643// Add the resource dir library path644SmallString<128> runtimeLibDir(rootDir);645sys::path::append(runtimeLibDir, "lib", "clang",646std::to_string(LLVM_VERSION_MAJOR), "lib");647// Resource dir + osname, which is hardcoded to windows since we are in the648// COFF driver.649SmallString<128> runtimeLibDirWithOS(runtimeLibDir);650sys::path::append(runtimeLibDirWithOS, "windows");651652searchPaths.push_back(saver().save(runtimeLibDirWithOS.str()));653searchPaths.push_back(saver().save(runtimeLibDir.str()));654searchPaths.push_back(saver().save(libDir.str()));655}656657void LinkerDriver::addWinSysRootLibSearchPaths() {658if (!diaPath.empty()) {659// The DIA SDK always uses the legacy vc arch, even in new MSVC versions.660path::append(diaPath, "lib", archToLegacyVCArch(getArch()));661searchPaths.push_back(saver().save(diaPath.str()));662}663if (useWinSysRootLibPath) {664searchPaths.push_back(saver().save(getSubDirectoryPath(665SubDirectoryType::Lib, vsLayout, vcToolChainPath, getArch())));666searchPaths.push_back(saver().save(667getSubDirectoryPath(SubDirectoryType::Lib, vsLayout, vcToolChainPath,668getArch(), "atlmfc")));669}670if (!universalCRTLibPath.empty()) {671StringRef ArchName = archToWindowsSDKArch(getArch());672if (!ArchName.empty()) {673path::append(universalCRTLibPath, ArchName);674searchPaths.push_back(saver().save(universalCRTLibPath.str()));675}676}677if (!windowsSdkLibPath.empty()) {678std::string path;679if (appendArchToWindowsSDKLibPath(sdkMajor, windowsSdkLibPath, getArch(),680path))681searchPaths.push_back(saver().save(path));682}683}684685// Parses LIB environment which contains a list of search paths.686void LinkerDriver::addLibSearchPaths() {687std::optional<std::string> envOpt = Process::GetEnv("LIB");688if (!envOpt)689return;690StringRef env = saver().save(*envOpt);691while (!env.empty()) {692StringRef path;693std::tie(path, env) = env.split(';');694searchPaths.push_back(path);695}696}697698Symbol *LinkerDriver::addUndefined(StringRef name) {699Symbol *b = ctx.symtab.addUndefined(name);700if (!b->isGCRoot) {701b->isGCRoot = true;702ctx.config.gcroot.push_back(b);703}704return b;705}706707StringRef LinkerDriver::mangleMaybe(Symbol *s) {708// If the plain symbol name has already been resolved, do nothing.709Undefined *unmangled = dyn_cast<Undefined>(s);710if (!unmangled)711return "";712713// Otherwise, see if a similar, mangled symbol exists in the symbol table.714Symbol *mangled = ctx.symtab.findMangle(unmangled->getName());715if (!mangled)716return "";717718// If we find a similar mangled symbol, make this an alias to it and return719// its name.720log(unmangled->getName() + " aliased to " + mangled->getName());721unmangled->weakAlias = ctx.symtab.addUndefined(mangled->getName());722return mangled->getName();723}724725// Windows specific -- find default entry point name.726//727// There are four different entry point functions for Windows executables,728// each of which corresponds to a user-defined "main" function. This function729// infers an entry point from a user-defined "main" function.730StringRef LinkerDriver::findDefaultEntry() {731assert(ctx.config.subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&732"must handle /subsystem before calling this");733734if (ctx.config.mingw)735return mangle(ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI736? "WinMainCRTStartup"737: "mainCRTStartup");738739if (ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {740if (findUnderscoreMangle("wWinMain")) {741if (!findUnderscoreMangle("WinMain"))742return mangle("wWinMainCRTStartup");743warn("found both wWinMain and WinMain; using latter");744}745return mangle("WinMainCRTStartup");746}747if (findUnderscoreMangle("wmain")) {748if (!findUnderscoreMangle("main"))749return mangle("wmainCRTStartup");750warn("found both wmain and main; using latter");751}752return mangle("mainCRTStartup");753}754755WindowsSubsystem LinkerDriver::inferSubsystem() {756if (ctx.config.dll)757return IMAGE_SUBSYSTEM_WINDOWS_GUI;758if (ctx.config.mingw)759return IMAGE_SUBSYSTEM_WINDOWS_CUI;760// Note that link.exe infers the subsystem from the presence of these761// functions even if /entry: or /nodefaultlib are passed which causes them762// to not be called.763bool haveMain = findUnderscoreMangle("main");764bool haveWMain = findUnderscoreMangle("wmain");765bool haveWinMain = findUnderscoreMangle("WinMain");766bool haveWWinMain = findUnderscoreMangle("wWinMain");767if (haveMain || haveWMain) {768if (haveWinMain || haveWWinMain) {769warn(std::string("found ") + (haveMain ? "main" : "wmain") + " and " +770(haveWinMain ? "WinMain" : "wWinMain") +771"; defaulting to /subsystem:console");772}773return IMAGE_SUBSYSTEM_WINDOWS_CUI;774}775if (haveWinMain || haveWWinMain)776return IMAGE_SUBSYSTEM_WINDOWS_GUI;777return IMAGE_SUBSYSTEM_UNKNOWN;778}779780uint64_t LinkerDriver::getDefaultImageBase() {781if (ctx.config.is64())782return ctx.config.dll ? 0x180000000 : 0x140000000;783return ctx.config.dll ? 0x10000000 : 0x400000;784}785786static std::string rewritePath(StringRef s) {787if (fs::exists(s))788return relativeToRoot(s);789return std::string(s);790}791792// Reconstructs command line arguments so that so that you can re-run793// the same command with the same inputs. This is for --reproduce.794static std::string createResponseFile(const opt::InputArgList &args,795ArrayRef<StringRef> filePaths,796ArrayRef<StringRef> searchPaths) {797SmallString<0> data;798raw_svector_ostream os(data);799800for (auto *arg : args) {801switch (arg->getOption().getID()) {802case OPT_linkrepro:803case OPT_reproduce:804case OPT_INPUT:805case OPT_defaultlib:806case OPT_libpath:807case OPT_winsysroot:808break;809case OPT_call_graph_ordering_file:810case OPT_deffile:811case OPT_manifestinput:812case OPT_natvis:813os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << '\n';814break;815case OPT_order: {816StringRef orderFile = arg->getValue();817orderFile.consume_front("@");818os << arg->getSpelling() << '@' << quote(rewritePath(orderFile)) << '\n';819break;820}821case OPT_pdbstream: {822const std::pair<StringRef, StringRef> nameFile =823StringRef(arg->getValue()).split("=");824os << arg->getSpelling() << nameFile.first << '='825<< quote(rewritePath(nameFile.second)) << '\n';826break;827}828case OPT_implib:829case OPT_manifestfile:830case OPT_pdb:831case OPT_pdbstripped:832case OPT_out:833os << arg->getSpelling() << sys::path::filename(arg->getValue()) << "\n";834break;835default:836os << toString(*arg) << "\n";837}838}839840for (StringRef path : searchPaths) {841std::string relPath = relativeToRoot(path);842os << "/libpath:" << quote(relPath) << "\n";843}844845for (StringRef path : filePaths)846os << quote(relativeToRoot(path)) << "\n";847848return std::string(data);849}850851static unsigned parseDebugTypes(const opt::InputArgList &args) {852unsigned debugTypes = static_cast<unsigned>(DebugType::None);853854if (auto *a = args.getLastArg(OPT_debugtype)) {855SmallVector<StringRef, 3> types;856StringRef(a->getValue())857.split(types, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);858859for (StringRef type : types) {860unsigned v = StringSwitch<unsigned>(type.lower())861.Case("cv", static_cast<unsigned>(DebugType::CV))862.Case("pdata", static_cast<unsigned>(DebugType::PData))863.Case("fixup", static_cast<unsigned>(DebugType::Fixup))864.Default(0);865if (v == 0) {866warn("/debugtype: unknown option '" + type + "'");867continue;868}869debugTypes |= v;870}871return debugTypes;872}873874// Default debug types875debugTypes = static_cast<unsigned>(DebugType::CV);876if (args.hasArg(OPT_driver))877debugTypes |= static_cast<unsigned>(DebugType::PData);878if (args.hasArg(OPT_profile))879debugTypes |= static_cast<unsigned>(DebugType::Fixup);880881return debugTypes;882}883884std::string LinkerDriver::getMapFile(const opt::InputArgList &args,885opt::OptSpecifier os,886opt::OptSpecifier osFile) {887auto *arg = args.getLastArg(os, osFile);888if (!arg)889return "";890if (arg->getOption().getID() == osFile.getID())891return arg->getValue();892893assert(arg->getOption().getID() == os.getID());894StringRef outFile = ctx.config.outputFile;895return (outFile.substr(0, outFile.rfind('.')) + ".map").str();896}897898std::string LinkerDriver::getImplibPath() {899if (!ctx.config.implib.empty())900return std::string(ctx.config.implib);901SmallString<128> out = StringRef(ctx.config.outputFile);902sys::path::replace_extension(out, ".lib");903return std::string(out);904}905906// The import name is calculated as follows:907//908// | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY909// -----+----------------+---------------------+------------------910// LINK | {value} | {value}.{.dll/.exe} | {output name}911// LIB | {value} | {value}.dll | {output name}.dll912//913std::string LinkerDriver::getImportName(bool asLib) {914SmallString<128> out;915916if (ctx.config.importName.empty()) {917out.assign(sys::path::filename(ctx.config.outputFile));918if (asLib)919sys::path::replace_extension(out, ".dll");920} else {921out.assign(ctx.config.importName);922if (!sys::path::has_extension(out))923sys::path::replace_extension(out,924(ctx.config.dll || asLib) ? ".dll" : ".exe");925}926927return std::string(out);928}929930void LinkerDriver::createImportLibrary(bool asLib) {931llvm::TimeTraceScope timeScope("Create import library");932std::vector<COFFShortExport> exports;933for (Export &e1 : ctx.config.exports) {934COFFShortExport e2;935e2.Name = std::string(e1.name);936e2.SymbolName = std::string(e1.symbolName);937e2.ExtName = std::string(e1.extName);938e2.ExportAs = std::string(e1.exportAs);939e2.ImportName = std::string(e1.importName);940e2.Ordinal = e1.ordinal;941e2.Noname = e1.noname;942e2.Data = e1.data;943e2.Private = e1.isPrivate;944e2.Constant = e1.constant;945exports.push_back(e2);946}947948std::string libName = getImportName(asLib);949std::string path = getImplibPath();950951if (!ctx.config.incremental) {952checkError(writeImportLibrary(libName, path, exports, ctx.config.machine,953ctx.config.mingw));954return;955}956957// If the import library already exists, replace it only if the contents958// have changed.959ErrorOr<std::unique_ptr<MemoryBuffer>> oldBuf = MemoryBuffer::getFile(960path, /*IsText=*/false, /*RequiresNullTerminator=*/false);961if (!oldBuf) {962checkError(writeImportLibrary(libName, path, exports, ctx.config.machine,963ctx.config.mingw));964return;965}966967SmallString<128> tmpName;968if (std::error_code ec =969sys::fs::createUniqueFile(path + ".tmp-%%%%%%%%.lib", tmpName))970fatal("cannot create temporary file for import library " + path + ": " +971ec.message());972973if (Error e = writeImportLibrary(libName, tmpName, exports,974ctx.config.machine, ctx.config.mingw)) {975checkError(std::move(e));976return;977}978979std::unique_ptr<MemoryBuffer> newBuf = check(MemoryBuffer::getFile(980tmpName, /*IsText=*/false, /*RequiresNullTerminator=*/false));981if ((*oldBuf)->getBuffer() != newBuf->getBuffer()) {982oldBuf->reset();983checkError(errorCodeToError(sys::fs::rename(tmpName, path)));984} else {985sys::fs::remove(tmpName);986}987}988989void LinkerDriver::parseModuleDefs(StringRef path) {990llvm::TimeTraceScope timeScope("Parse def file");991std::unique_ptr<MemoryBuffer> mb =992CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,993/*RequiresNullTerminator=*/false,994/*IsVolatile=*/true),995"could not open " + path);996COFFModuleDefinition m = check(parseCOFFModuleDefinition(997mb->getMemBufferRef(), ctx.config.machine, ctx.config.mingw));998999// Include in /reproduce: output if applicable.1000ctx.driver.takeBuffer(std::move(mb));10011002if (ctx.config.outputFile.empty())1003ctx.config.outputFile = std::string(saver().save(m.OutputFile));1004ctx.config.importName = std::string(saver().save(m.ImportName));1005if (m.ImageBase)1006ctx.config.imageBase = m.ImageBase;1007if (m.StackReserve)1008ctx.config.stackReserve = m.StackReserve;1009if (m.StackCommit)1010ctx.config.stackCommit = m.StackCommit;1011if (m.HeapReserve)1012ctx.config.heapReserve = m.HeapReserve;1013if (m.HeapCommit)1014ctx.config.heapCommit = m.HeapCommit;1015if (m.MajorImageVersion)1016ctx.config.majorImageVersion = m.MajorImageVersion;1017if (m.MinorImageVersion)1018ctx.config.minorImageVersion = m.MinorImageVersion;1019if (m.MajorOSVersion)1020ctx.config.majorOSVersion = m.MajorOSVersion;1021if (m.MinorOSVersion)1022ctx.config.minorOSVersion = m.MinorOSVersion;10231024for (COFFShortExport e1 : m.Exports) {1025Export e2;1026// Renamed exports are parsed and set as "ExtName = Name". If Name has1027// the form "OtherDll.Func", it shouldn't be a normal exported1028// function but a forward to another DLL instead. This is supported1029// by both MS and GNU linkers.1030if (!e1.ExtName.empty() && e1.ExtName != e1.Name &&1031StringRef(e1.Name).contains('.')) {1032e2.name = saver().save(e1.ExtName);1033e2.forwardTo = saver().save(e1.Name);1034} else {1035e2.name = saver().save(e1.Name);1036e2.extName = saver().save(e1.ExtName);1037}1038e2.exportAs = saver().save(e1.ExportAs);1039e2.importName = saver().save(e1.ImportName);1040e2.ordinal = e1.Ordinal;1041e2.noname = e1.Noname;1042e2.data = e1.Data;1043e2.isPrivate = e1.Private;1044e2.constant = e1.Constant;1045e2.source = ExportSource::ModuleDefinition;1046ctx.config.exports.push_back(e2);1047}1048}10491050void LinkerDriver::enqueueTask(std::function<void()> task) {1051taskQueue.push_back(std::move(task));1052}10531054bool LinkerDriver::run() {1055llvm::TimeTraceScope timeScope("Read input files");1056ScopedTimer t(ctx.inputFileTimer);10571058bool didWork = !taskQueue.empty();1059while (!taskQueue.empty()) {1060taskQueue.front()();1061taskQueue.pop_front();1062}1063return didWork;1064}10651066// Parse an /order file. If an option is given, the linker places1067// COMDAT sections in the same order as their names appear in the1068// given file.1069void LinkerDriver::parseOrderFile(StringRef arg) {1070// For some reason, the MSVC linker requires a filename to be1071// preceded by "@".1072if (!arg.starts_with("@")) {1073error("malformed /order option: '@' missing");1074return;1075}10761077// Get a list of all comdat sections for error checking.1078DenseSet<StringRef> set;1079for (Chunk *c : ctx.symtab.getChunks())1080if (auto *sec = dyn_cast<SectionChunk>(c))1081if (sec->sym)1082set.insert(sec->sym->getName());10831084// Open a file.1085StringRef path = arg.substr(1);1086std::unique_ptr<MemoryBuffer> mb =1087CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,1088/*RequiresNullTerminator=*/false,1089/*IsVolatile=*/true),1090"could not open " + path);10911092// Parse a file. An order file contains one symbol per line.1093// All symbols that were not present in a given order file are1094// considered to have the lowest priority 0 and are placed at1095// end of an output section.1096for (StringRef arg : args::getLines(mb->getMemBufferRef())) {1097std::string s(arg);1098if (ctx.config.machine == I386 && !isDecorated(s))1099s = "_" + s;11001101if (set.count(s) == 0) {1102if (ctx.config.warnMissingOrderSymbol)1103warn("/order:" + arg + ": missing symbol: " + s + " [LNK4037]");1104} else1105ctx.config.order[s] = INT_MIN + ctx.config.order.size();1106}11071108// Include in /reproduce: output if applicable.1109ctx.driver.takeBuffer(std::move(mb));1110}11111112void LinkerDriver::parseCallGraphFile(StringRef path) {1113std::unique_ptr<MemoryBuffer> mb =1114CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,1115/*RequiresNullTerminator=*/false,1116/*IsVolatile=*/true),1117"could not open " + path);11181119// Build a map from symbol name to section.1120DenseMap<StringRef, Symbol *> map;1121for (ObjFile *file : ctx.objFileInstances)1122for (Symbol *sym : file->getSymbols())1123if (sym)1124map[sym->getName()] = sym;11251126auto findSection = [&](StringRef name) -> SectionChunk * {1127Symbol *sym = map.lookup(name);1128if (!sym) {1129if (ctx.config.warnMissingOrderSymbol)1130warn(path + ": no such symbol: " + name);1131return nullptr;1132}11331134if (DefinedCOFF *dr = dyn_cast_or_null<DefinedCOFF>(sym))1135return dyn_cast_or_null<SectionChunk>(dr->getChunk());1136return nullptr;1137};11381139for (StringRef line : args::getLines(*mb)) {1140SmallVector<StringRef, 3> fields;1141line.split(fields, ' ');1142uint64_t count;11431144if (fields.size() != 3 || !to_integer(fields[2], count)) {1145error(path + ": parse error");1146return;1147}11481149if (SectionChunk *from = findSection(fields[0]))1150if (SectionChunk *to = findSection(fields[1]))1151ctx.config.callGraphProfile[{from, to}] += count;1152}11531154// Include in /reproduce: output if applicable.1155ctx.driver.takeBuffer(std::move(mb));1156}11571158static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) {1159for (ObjFile *obj : ctx.objFileInstances) {1160if (obj->callgraphSec) {1161ArrayRef<uint8_t> contents;1162cantFail(1163obj->getCOFFObj()->getSectionContents(obj->callgraphSec, contents));1164BinaryStreamReader reader(contents, llvm::endianness::little);1165while (!reader.empty()) {1166uint32_t fromIndex, toIndex;1167uint64_t count;1168if (Error err = reader.readInteger(fromIndex))1169fatal(toString(obj) + ": Expected 32-bit integer");1170if (Error err = reader.readInteger(toIndex))1171fatal(toString(obj) + ": Expected 32-bit integer");1172if (Error err = reader.readInteger(count))1173fatal(toString(obj) + ": Expected 64-bit integer");1174auto *fromSym = dyn_cast_or_null<Defined>(obj->getSymbol(fromIndex));1175auto *toSym = dyn_cast_or_null<Defined>(obj->getSymbol(toIndex));1176if (!fromSym || !toSym)1177continue;1178auto *from = dyn_cast_or_null<SectionChunk>(fromSym->getChunk());1179auto *to = dyn_cast_or_null<SectionChunk>(toSym->getChunk());1180if (from && to)1181ctx.config.callGraphProfile[{from, to}] += count;1182}1183}1184}1185}11861187static void markAddrsig(Symbol *s) {1188if (auto *d = dyn_cast_or_null<Defined>(s))1189if (SectionChunk *c = dyn_cast_or_null<SectionChunk>(d->getChunk()))1190c->keepUnique = true;1191}11921193static void findKeepUniqueSections(COFFLinkerContext &ctx) {1194llvm::TimeTraceScope timeScope("Find keep unique sections");11951196// Exported symbols could be address-significant in other executables or DSOs,1197// so we conservatively mark them as address-significant.1198for (Export &r : ctx.config.exports)1199markAddrsig(r.sym);12001201// Visit the address-significance table in each object file and mark each1202// referenced symbol as address-significant.1203for (ObjFile *obj : ctx.objFileInstances) {1204ArrayRef<Symbol *> syms = obj->getSymbols();1205if (obj->addrsigSec) {1206ArrayRef<uint8_t> contents;1207cantFail(1208obj->getCOFFObj()->getSectionContents(obj->addrsigSec, contents));1209const uint8_t *cur = contents.begin();1210while (cur != contents.end()) {1211unsigned size;1212const char *err = nullptr;1213uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err);1214if (err)1215fatal(toString(obj) + ": could not decode addrsig section: " + err);1216if (symIndex >= syms.size())1217fatal(toString(obj) + ": invalid symbol index in addrsig section");1218markAddrsig(syms[symIndex]);1219cur += size;1220}1221} else {1222// If an object file does not have an address-significance table,1223// conservatively mark all of its symbols as address-significant.1224for (Symbol *s : syms)1225markAddrsig(s);1226}1227}1228}12291230// link.exe replaces each %foo% in altPath with the contents of environment1231// variable foo, and adds the two magic env vars _PDB (expands to the basename1232// of pdb's output path) and _EXT (expands to the extension of the output1233// binary).1234// lld only supports %_PDB% and %_EXT% and warns on references to all other env1235// vars.1236void LinkerDriver::parsePDBAltPath() {1237SmallString<128> buf;1238StringRef pdbBasename =1239sys::path::filename(ctx.config.pdbPath, sys::path::Style::windows);1240StringRef binaryExtension =1241sys::path::extension(ctx.config.outputFile, sys::path::Style::windows);1242if (!binaryExtension.empty())1243binaryExtension = binaryExtension.substr(1); // %_EXT% does not include '.'.12441245// Invariant:1246// +--------- cursor ('a...' might be the empty string).1247// | +----- firstMark1248// | | +- secondMark1249// v v v1250// a...%...%...1251size_t cursor = 0;1252while (cursor < ctx.config.pdbAltPath.size()) {1253size_t firstMark, secondMark;1254if ((firstMark = ctx.config.pdbAltPath.find('%', cursor)) ==1255StringRef::npos ||1256(secondMark = ctx.config.pdbAltPath.find('%', firstMark + 1)) ==1257StringRef::npos) {1258// Didn't find another full fragment, treat rest of string as literal.1259buf.append(ctx.config.pdbAltPath.substr(cursor));1260break;1261}12621263// Found a full fragment. Append text in front of first %, and interpret1264// text between first and second % as variable name.1265buf.append(ctx.config.pdbAltPath.substr(cursor, firstMark - cursor));1266StringRef var =1267ctx.config.pdbAltPath.substr(firstMark, secondMark - firstMark + 1);1268if (var.equals_insensitive("%_pdb%"))1269buf.append(pdbBasename);1270else if (var.equals_insensitive("%_ext%"))1271buf.append(binaryExtension);1272else {1273warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " + var +1274" as literal");1275buf.append(var);1276}12771278cursor = secondMark + 1;1279}12801281ctx.config.pdbAltPath = buf;1282}12831284/// Convert resource files and potentially merge input resource object1285/// trees into one resource tree.1286/// Call after ObjFile::Instances is complete.1287void LinkerDriver::convertResources() {1288llvm::TimeTraceScope timeScope("Convert resources");1289std::vector<ObjFile *> resourceObjFiles;12901291for (ObjFile *f : ctx.objFileInstances) {1292if (f->isResourceObjFile())1293resourceObjFiles.push_back(f);1294}12951296if (!ctx.config.mingw &&1297(resourceObjFiles.size() > 1 ||1298(resourceObjFiles.size() == 1 && !resources.empty()))) {1299error((!resources.empty() ? "internal .obj file created from .res files"1300: toString(resourceObjFiles[1])) +1301": more than one resource obj file not allowed, already got " +1302toString(resourceObjFiles.front()));1303return;1304}13051306if (resources.empty() && resourceObjFiles.size() <= 1) {1307// No resources to convert, and max one resource object file in1308// the input. Keep that preconverted resource section as is.1309for (ObjFile *f : resourceObjFiles)1310f->includeResourceChunks();1311return;1312}1313ObjFile *f =1314make<ObjFile>(ctx, convertResToCOFF(resources, resourceObjFiles));1315ctx.symtab.addFile(f);1316f->includeResourceChunks();1317}13181319// In MinGW, if no symbols are chosen to be exported, then all symbols are1320// automatically exported by default. This behavior can be forced by the1321// -export-all-symbols option, so that it happens even when exports are1322// explicitly specified. The automatic behavior can be disabled using the1323// -exclude-all-symbols option, so that lld-link behaves like link.exe rather1324// than MinGW in the case that nothing is explicitly exported.1325void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {1326if (!args.hasArg(OPT_export_all_symbols)) {1327if (!ctx.config.dll)1328return;13291330if (!ctx.config.exports.empty())1331return;1332if (args.hasArg(OPT_exclude_all_symbols))1333return;1334}13351336AutoExporter exporter(ctx, excludedSymbols);13371338for (auto *arg : args.filtered(OPT_wholearchive_file))1339if (std::optional<StringRef> path = findFile(arg->getValue()))1340exporter.addWholeArchive(*path);13411342for (auto *arg : args.filtered(OPT_exclude_symbols)) {1343SmallVector<StringRef, 2> vec;1344StringRef(arg->getValue()).split(vec, ',');1345for (StringRef sym : vec)1346exporter.addExcludedSymbol(mangle(sym));1347}13481349ctx.symtab.forEachSymbol([&](Symbol *s) {1350auto *def = dyn_cast<Defined>(s);1351if (!exporter.shouldExport(def))1352return;13531354if (!def->isGCRoot) {1355def->isGCRoot = true;1356ctx.config.gcroot.push_back(def);1357}13581359Export e;1360e.name = def->getName();1361e.sym = def;1362if (Chunk *c = def->getChunk())1363if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))1364e.data = true;1365s->isUsedInRegularObj = true;1366ctx.config.exports.push_back(e);1367});1368}13691370// lld has a feature to create a tar file containing all input files as well as1371// all command line options, so that other people can run lld again with exactly1372// the same inputs. This feature is accessible via /linkrepro and /reproduce.1373//1374// /linkrepro and /reproduce are very similar, but /linkrepro takes a directory1375// name while /reproduce takes a full path. We have /linkrepro for compatibility1376// with Microsoft link.exe.1377std::optional<std::string> getReproduceFile(const opt::InputArgList &args) {1378if (auto *arg = args.getLastArg(OPT_reproduce))1379return std::string(arg->getValue());13801381if (auto *arg = args.getLastArg(OPT_linkrepro)) {1382SmallString<64> path = StringRef(arg->getValue());1383sys::path::append(path, "repro.tar");1384return std::string(path);1385}13861387// This is intentionally not guarded by OPT_lldignoreenv since writing1388// a repro tar file doesn't affect the main output.1389if (auto *path = getenv("LLD_REPRODUCE"))1390return std::string(path);13911392return std::nullopt;1393}13941395static std::unique_ptr<llvm::vfs::FileSystem>1396getVFS(const opt::InputArgList &args) {1397using namespace llvm::vfs;13981399const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay);1400if (!arg)1401return nullptr;14021403auto bufOrErr = llvm::MemoryBuffer::getFile(arg->getValue());1404if (!bufOrErr) {1405checkError(errorCodeToError(bufOrErr.getError()));1406return nullptr;1407}14081409if (auto ret = vfs::getVFSFromYAML(std::move(*bufOrErr),1410/*DiagHandler*/ nullptr, arg->getValue()))1411return ret;14121413error("Invalid vfs overlay");1414return nullptr;1415}14161417void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {1418ScopedTimer rootTimer(ctx.rootTimer);1419Configuration *config = &ctx.config;14201421// Needed for LTO.1422InitializeAllTargetInfos();1423InitializeAllTargets();1424InitializeAllTargetMCs();1425InitializeAllAsmParsers();1426InitializeAllAsmPrinters();14271428// If the first command line argument is "/lib", link.exe acts like lib.exe.1429// We call our own implementation of lib.exe that understands bitcode files.1430if (argsArr.size() > 1 &&1431(StringRef(argsArr[1]).equals_insensitive("/lib") ||1432StringRef(argsArr[1]).equals_insensitive("-lib"))) {1433if (llvm::libDriverMain(argsArr.slice(1)) != 0)1434fatal("lib failed");1435return;1436}14371438// Parse command line options.1439ArgParser parser(ctx);1440opt::InputArgList args = parser.parse(argsArr);14411442// Initialize time trace profiler.1443config->timeTraceEnabled = args.hasArg(OPT_time_trace_eq);1444config->timeTraceGranularity =1445args::getInteger(args, OPT_time_trace_granularity_eq, 500);14461447if (config->timeTraceEnabled)1448timeTraceProfilerInitialize(config->timeTraceGranularity, argsArr[0]);14491450llvm::TimeTraceScope timeScope("COFF link");14511452// Parse and evaluate -mllvm options.1453std::vector<const char *> v;1454v.push_back("lld-link (LLVM option parsing)");1455for (const auto *arg : args.filtered(OPT_mllvm)) {1456v.push_back(arg->getValue());1457config->mllvmOpts.emplace_back(arg->getValue());1458}1459{1460llvm::TimeTraceScope timeScope2("Parse cl::opt");1461cl::ResetAllOptionOccurrences();1462cl::ParseCommandLineOptions(v.size(), v.data());1463}14641465// Handle /errorlimit early, because error() depends on it.1466if (auto *arg = args.getLastArg(OPT_errorlimit)) {1467int n = 20;1468StringRef s = arg->getValue();1469if (s.getAsInteger(10, n))1470error(arg->getSpelling() + " number expected, but got " + s);1471errorHandler().errorLimit = n;1472}14731474config->vfs = getVFS(args);14751476// Handle /help1477if (args.hasArg(OPT_help)) {1478printHelp(argsArr[0]);1479return;1480}14811482// /threads: takes a positive integer and provides the default value for1483// /opt:lldltojobs=.1484if (auto *arg = args.getLastArg(OPT_threads)) {1485StringRef v(arg->getValue());1486unsigned threads = 0;1487if (!llvm::to_integer(v, threads, 0) || threads == 0)1488error(arg->getSpelling() + ": expected a positive integer, but got '" +1489arg->getValue() + "'");1490parallel::strategy = hardware_concurrency(threads);1491config->thinLTOJobs = v.str();1492}14931494if (args.hasArg(OPT_show_timing))1495config->showTiming = true;14961497config->showSummary = args.hasArg(OPT_summary);1498config->printSearchPaths = args.hasArg(OPT_print_search_paths);14991500// Handle --version, which is an lld extension. This option is a bit odd1501// because it doesn't start with "/", but we deliberately chose "--" to1502// avoid conflict with /version and for compatibility with clang-cl.1503if (args.hasArg(OPT_dash_dash_version)) {1504message(getLLDVersion());1505return;1506}15071508// Handle /lldmingw early, since it can potentially affect how other1509// options are handled.1510config->mingw = args.hasArg(OPT_lldmingw);1511if (config->mingw)1512ctx.e.errorLimitExceededMsg = "too many errors emitted, stopping now"1513" (use --error-limit=0 to see all errors)";15141515// Handle /linkrepro and /reproduce.1516{1517llvm::TimeTraceScope timeScope2("Reproducer");1518if (std::optional<std::string> path = getReproduceFile(args)) {1519Expected<std::unique_ptr<TarWriter>> errOrWriter =1520TarWriter::create(*path, sys::path::stem(*path));15211522if (errOrWriter) {1523tar = std::move(*errOrWriter);1524} else {1525error("/linkrepro: failed to open " + *path + ": " +1526toString(errOrWriter.takeError()));1527}1528}1529}15301531if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {1532if (args.hasArg(OPT_deffile))1533config->noEntry = true;1534else1535fatal("no input files");1536}15371538// Construct search path list.1539{1540llvm::TimeTraceScope timeScope2("Search paths");1541searchPaths.emplace_back("");1542for (auto *arg : args.filtered(OPT_libpath))1543searchPaths.push_back(arg->getValue());1544if (!config->mingw) {1545// Prefer the Clang provided builtins over the ones bundled with MSVC.1546// In MinGW mode, the compiler driver passes the necessary libpath1547// options explicitly.1548addClangLibSearchPaths(argsArr[0]);1549// Don't automatically deduce the lib path from the environment or MSVC1550// installations when operating in mingw mode. (This also makes LLD ignore1551// winsysroot and vctoolsdir arguments.)1552detectWinSysRoot(args);1553if (!args.hasArg(OPT_lldignoreenv) && !args.hasArg(OPT_winsysroot))1554addLibSearchPaths();1555} else {1556if (args.hasArg(OPT_vctoolsdir, OPT_winsysroot))1557warn("ignoring /vctoolsdir or /winsysroot flags in MinGW mode");1558}1559}15601561// Handle /ignore1562for (auto *arg : args.filtered(OPT_ignore)) {1563SmallVector<StringRef, 8> vec;1564StringRef(arg->getValue()).split(vec, ',');1565for (StringRef s : vec) {1566if (s == "4037")1567config->warnMissingOrderSymbol = false;1568else if (s == "4099")1569config->warnDebugInfoUnusable = false;1570else if (s == "4217")1571config->warnLocallyDefinedImported = false;1572else if (s == "longsections")1573config->warnLongSectionNames = false;1574// Other warning numbers are ignored.1575}1576}15771578// Handle /out1579if (auto *arg = args.getLastArg(OPT_out))1580config->outputFile = arg->getValue();15811582// Handle /verbose1583if (args.hasArg(OPT_verbose))1584config->verbose = true;1585errorHandler().verbose = config->verbose;15861587// Handle /force or /force:unresolved1588if (args.hasArg(OPT_force, OPT_force_unresolved))1589config->forceUnresolved = true;15901591// Handle /force or /force:multiple1592if (args.hasArg(OPT_force, OPT_force_multiple))1593config->forceMultiple = true;15941595// Handle /force or /force:multipleres1596if (args.hasArg(OPT_force, OPT_force_multipleres))1597config->forceMultipleRes = true;15981599// Don't warn about long section names, such as .debug_info, for mingw (or1600// when -debug:dwarf is requested, handled below).1601if (config->mingw)1602config->warnLongSectionNames = false;16031604bool doGC = true;16051606// Handle /debug1607bool shouldCreatePDB = false;1608for (auto *arg : args.filtered(OPT_debug, OPT_debug_opt)) {1609std::string str;1610if (arg->getOption().getID() == OPT_debug)1611str = "full";1612else1613str = StringRef(arg->getValue()).lower();1614SmallVector<StringRef, 1> vec;1615StringRef(str).split(vec, ',');1616for (StringRef s : vec) {1617if (s == "fastlink") {1618warn("/debug:fastlink unsupported; using /debug:full");1619s = "full";1620}1621if (s == "none") {1622config->debug = false;1623config->incremental = false;1624config->includeDwarfChunks = false;1625config->debugGHashes = false;1626config->writeSymtab = false;1627shouldCreatePDB = false;1628doGC = true;1629} else if (s == "full" || s == "ghash" || s == "noghash") {1630config->debug = true;1631config->incremental = true;1632config->includeDwarfChunks = true;1633if (s == "full" || s == "ghash")1634config->debugGHashes = true;1635shouldCreatePDB = true;1636doGC = false;1637} else if (s == "dwarf") {1638config->debug = true;1639config->incremental = true;1640config->includeDwarfChunks = true;1641config->writeSymtab = true;1642config->warnLongSectionNames = false;1643doGC = false;1644} else if (s == "nodwarf") {1645config->includeDwarfChunks = false;1646} else if (s == "symtab") {1647config->writeSymtab = true;1648doGC = false;1649} else if (s == "nosymtab") {1650config->writeSymtab = false;1651} else {1652error("/debug: unknown option: " + s);1653}1654}1655}16561657// Handle /demangle1658config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no, true);16591660// Handle /debugtype1661config->debugTypes = parseDebugTypes(args);16621663// Handle /driver[:uponly|:wdm].1664config->driverUponly = args.hasArg(OPT_driver_uponly) ||1665args.hasArg(OPT_driver_uponly_wdm) ||1666args.hasArg(OPT_driver_wdm_uponly);1667config->driverWdm = args.hasArg(OPT_driver_wdm) ||1668args.hasArg(OPT_driver_uponly_wdm) ||1669args.hasArg(OPT_driver_wdm_uponly);1670config->driver =1671config->driverUponly || config->driverWdm || args.hasArg(OPT_driver);16721673// Handle /pdb1674if (shouldCreatePDB) {1675if (auto *arg = args.getLastArg(OPT_pdb))1676config->pdbPath = arg->getValue();1677if (auto *arg = args.getLastArg(OPT_pdbaltpath))1678config->pdbAltPath = arg->getValue();1679if (auto *arg = args.getLastArg(OPT_pdbpagesize))1680parsePDBPageSize(arg->getValue());1681if (args.hasArg(OPT_natvis))1682config->natvisFiles = args.getAllArgValues(OPT_natvis);1683if (args.hasArg(OPT_pdbstream)) {1684for (const StringRef value : args.getAllArgValues(OPT_pdbstream)) {1685const std::pair<StringRef, StringRef> nameFile = value.split("=");1686const StringRef name = nameFile.first;1687const std::string file = nameFile.second.str();1688config->namedStreams[name] = file;1689}1690}16911692if (auto *arg = args.getLastArg(OPT_pdb_source_path))1693config->pdbSourcePath = arg->getValue();1694}16951696// Handle /pdbstripped1697if (args.hasArg(OPT_pdbstripped))1698warn("ignoring /pdbstripped flag, it is not yet supported");16991700// Handle /noentry1701if (args.hasArg(OPT_noentry)) {1702if (args.hasArg(OPT_dll))1703config->noEntry = true;1704else1705error("/noentry must be specified with /dll");1706}17071708// Handle /dll1709if (args.hasArg(OPT_dll)) {1710config->dll = true;1711config->manifestID = 2;1712}17131714// Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase1715// because we need to explicitly check whether that option or its inverse was1716// present in the argument list in order to handle /fixed.1717auto *dynamicBaseArg = args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no);1718if (dynamicBaseArg &&1719dynamicBaseArg->getOption().getID() == OPT_dynamicbase_no)1720config->dynamicBase = false;17211722// MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the1723// default setting for any other project type.", but link.exe defaults to1724// /FIXED:NO for exe outputs as well. Match behavior, not docs.1725bool fixed = args.hasFlag(OPT_fixed, OPT_fixed_no, false);1726if (fixed) {1727if (dynamicBaseArg &&1728dynamicBaseArg->getOption().getID() == OPT_dynamicbase) {1729error("/fixed must not be specified with /dynamicbase");1730} else {1731config->relocatable = false;1732config->dynamicBase = false;1733}1734}17351736// Handle /appcontainer1737config->appContainer =1738args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false);17391740// Handle /machine1741{1742llvm::TimeTraceScope timeScope2("Machine arg");1743if (auto *arg = args.getLastArg(OPT_machine)) {1744config->machine = getMachineType(arg->getValue());1745if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN)1746fatal(Twine("unknown /machine argument: ") + arg->getValue());1747addWinSysRootLibSearchPaths();1748}1749}17501751// Handle /nodefaultlib:<filename>1752{1753llvm::TimeTraceScope timeScope2("Nodefaultlib");1754for (auto *arg : args.filtered(OPT_nodefaultlib))1755config->noDefaultLibs.insert(findLib(arg->getValue()).lower());1756}17571758// Handle /nodefaultlib1759if (args.hasArg(OPT_nodefaultlib_all))1760config->noDefaultLibAll = true;17611762// Handle /base1763if (auto *arg = args.getLastArg(OPT_base))1764parseNumbers(arg->getValue(), &config->imageBase);17651766// Handle /filealign1767if (auto *arg = args.getLastArg(OPT_filealign)) {1768parseNumbers(arg->getValue(), &config->fileAlign);1769if (!isPowerOf2_64(config->fileAlign))1770error("/filealign: not a power of two: " + Twine(config->fileAlign));1771}17721773// Handle /stack1774if (auto *arg = args.getLastArg(OPT_stack))1775parseNumbers(arg->getValue(), &config->stackReserve, &config->stackCommit);17761777// Handle /guard:cf1778if (auto *arg = args.getLastArg(OPT_guard))1779parseGuard(arg->getValue());17801781// Handle /heap1782if (auto *arg = args.getLastArg(OPT_heap))1783parseNumbers(arg->getValue(), &config->heapReserve, &config->heapCommit);17841785// Handle /version1786if (auto *arg = args.getLastArg(OPT_version))1787parseVersion(arg->getValue(), &config->majorImageVersion,1788&config->minorImageVersion);17891790// Handle /subsystem1791if (auto *arg = args.getLastArg(OPT_subsystem))1792parseSubsystem(arg->getValue(), &config->subsystem,1793&config->majorSubsystemVersion,1794&config->minorSubsystemVersion);17951796// Handle /osversion1797if (auto *arg = args.getLastArg(OPT_osversion)) {1798parseVersion(arg->getValue(), &config->majorOSVersion,1799&config->minorOSVersion);1800} else {1801config->majorOSVersion = config->majorSubsystemVersion;1802config->minorOSVersion = config->minorSubsystemVersion;1803}18041805// Handle /timestamp1806if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) {1807if (arg->getOption().getID() == OPT_repro) {1808config->timestamp = 0;1809config->repro = true;1810} else {1811config->repro = false;1812StringRef value(arg->getValue());1813if (value.getAsInteger(0, config->timestamp))1814fatal(Twine("invalid timestamp: ") + value +1815". Expected 32-bit integer");1816}1817} else {1818config->repro = false;1819if (std::optional<std::string> epoch =1820Process::GetEnv("SOURCE_DATE_EPOCH")) {1821StringRef value(*epoch);1822if (value.getAsInteger(0, config->timestamp))1823fatal(Twine("invalid SOURCE_DATE_EPOCH timestamp: ") + value +1824". Expected 32-bit integer");1825} else {1826config->timestamp = time(nullptr);1827}1828}18291830// Handle /alternatename1831for (auto *arg : args.filtered(OPT_alternatename))1832parseAlternateName(arg->getValue());18331834// Handle /include1835for (auto *arg : args.filtered(OPT_incl))1836addUndefined(arg->getValue());18371838// Handle /implib1839if (auto *arg = args.getLastArg(OPT_implib))1840config->implib = arg->getValue();18411842config->noimplib = args.hasArg(OPT_noimplib);18431844if (args.hasArg(OPT_profile))1845doGC = true;1846// Handle /opt.1847std::optional<ICFLevel> icfLevel;1848if (args.hasArg(OPT_profile))1849icfLevel = ICFLevel::None;1850unsigned tailMerge = 1;1851bool ltoDebugPM = false;1852for (auto *arg : args.filtered(OPT_opt)) {1853std::string str = StringRef(arg->getValue()).lower();1854SmallVector<StringRef, 1> vec;1855StringRef(str).split(vec, ',');1856for (StringRef s : vec) {1857if (s == "ref") {1858doGC = true;1859} else if (s == "noref") {1860doGC = false;1861} else if (s == "icf" || s.starts_with("icf=")) {1862icfLevel = ICFLevel::All;1863} else if (s == "safeicf") {1864icfLevel = ICFLevel::Safe;1865} else if (s == "noicf") {1866icfLevel = ICFLevel::None;1867} else if (s == "lldtailmerge") {1868tailMerge = 2;1869} else if (s == "nolldtailmerge") {1870tailMerge = 0;1871} else if (s == "ltodebugpassmanager") {1872ltoDebugPM = true;1873} else if (s == "noltodebugpassmanager") {1874ltoDebugPM = false;1875} else if (s.consume_front("lldlto=")) {1876if (s.getAsInteger(10, config->ltoo) || config->ltoo > 3)1877error("/opt:lldlto: invalid optimization level: " + s);1878} else if (s.consume_front("lldltocgo=")) {1879config->ltoCgo.emplace();1880if (s.getAsInteger(10, *config->ltoCgo) || *config->ltoCgo > 3)1881error("/opt:lldltocgo: invalid codegen optimization level: " + s);1882} else if (s.consume_front("lldltojobs=")) {1883if (!get_threadpool_strategy(s))1884error("/opt:lldltojobs: invalid job count: " + s);1885config->thinLTOJobs = s.str();1886} else if (s.consume_front("lldltopartitions=")) {1887if (s.getAsInteger(10, config->ltoPartitions) ||1888config->ltoPartitions == 0)1889error("/opt:lldltopartitions: invalid partition count: " + s);1890} else if (s != "lbr" && s != "nolbr")1891error("/opt: unknown option: " + s);1892}1893}18941895if (!icfLevel)1896icfLevel = doGC ? ICFLevel::All : ICFLevel::None;1897config->doGC = doGC;1898config->doICF = *icfLevel;1899config->tailMerge =1900(tailMerge == 1 && config->doICF != ICFLevel::None) || tailMerge == 2;1901config->ltoDebugPassManager = ltoDebugPM;19021903// Handle /lldsavetemps1904if (args.hasArg(OPT_lldsavetemps))1905config->saveTemps = true;19061907// Handle /lldemit1908if (auto *arg = args.getLastArg(OPT_lldemit)) {1909StringRef s = arg->getValue();1910if (s == "obj")1911config->emit = EmitKind::Obj;1912else if (s == "llvm")1913config->emit = EmitKind::LLVM;1914else if (s == "asm")1915config->emit = EmitKind::ASM;1916else1917error("/lldemit: unknown option: " + s);1918}19191920// Handle /kill-at1921if (args.hasArg(OPT_kill_at))1922config->killAt = true;19231924// Handle /lldltocache1925if (auto *arg = args.getLastArg(OPT_lldltocache))1926config->ltoCache = arg->getValue();19271928// Handle /lldsavecachepolicy1929if (auto *arg = args.getLastArg(OPT_lldltocachepolicy))1930config->ltoCachePolicy = CHECK(1931parseCachePruningPolicy(arg->getValue()),1932Twine("/lldltocachepolicy: invalid cache policy: ") + arg->getValue());19331934// Handle /failifmismatch1935for (auto *arg : args.filtered(OPT_failifmismatch))1936checkFailIfMismatch(arg->getValue(), nullptr);19371938// Handle /merge1939for (auto *arg : args.filtered(OPT_merge))1940parseMerge(arg->getValue());19411942// Add default section merging rules after user rules. User rules take1943// precedence, but we will emit a warning if there is a conflict.1944parseMerge(".idata=.rdata");1945parseMerge(".didat=.rdata");1946parseMerge(".edata=.rdata");1947parseMerge(".xdata=.rdata");1948parseMerge(".00cfg=.rdata");1949parseMerge(".bss=.data");19501951if (isArm64EC(config->machine))1952parseMerge(".wowthk=.text");19531954if (config->mingw) {1955parseMerge(".ctors=.rdata");1956parseMerge(".dtors=.rdata");1957parseMerge(".CRT=.rdata");1958}19591960// Handle /section1961for (auto *arg : args.filtered(OPT_section))1962parseSection(arg->getValue());19631964// Handle /align1965if (auto *arg = args.getLastArg(OPT_align)) {1966parseNumbers(arg->getValue(), &config->align);1967if (!isPowerOf2_64(config->align))1968error("/align: not a power of two: " + StringRef(arg->getValue()));1969if (!args.hasArg(OPT_driver))1970warn("/align specified without /driver; image may not run");1971}19721973// Handle /aligncomm1974for (auto *arg : args.filtered(OPT_aligncomm))1975parseAligncomm(arg->getValue());19761977// Handle /manifestdependency.1978for (auto *arg : args.filtered(OPT_manifestdependency))1979config->manifestDependencies.insert(arg->getValue());19801981// Handle /manifest and /manifest:1982if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) {1983if (arg->getOption().getID() == OPT_manifest)1984config->manifest = Configuration::SideBySide;1985else1986parseManifest(arg->getValue());1987}19881989// Handle /manifestuac1990if (auto *arg = args.getLastArg(OPT_manifestuac))1991parseManifestUAC(arg->getValue());19921993// Handle /manifestfile1994if (auto *arg = args.getLastArg(OPT_manifestfile))1995config->manifestFile = arg->getValue();19961997// Handle /manifestinput1998for (auto *arg : args.filtered(OPT_manifestinput))1999config->manifestInput.push_back(arg->getValue());20002001if (!config->manifestInput.empty() &&2002config->manifest != Configuration::Embed) {2003fatal("/manifestinput: requires /manifest:embed");2004}20052006// Handle /dwodir2007config->dwoDir = args.getLastArgValue(OPT_dwodir);20082009config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);2010config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||2011args.hasArg(OPT_thinlto_index_only_arg);2012config->thinLTOIndexOnlyArg =2013args.getLastArgValue(OPT_thinlto_index_only_arg);2014std::tie(config->thinLTOPrefixReplaceOld, config->thinLTOPrefixReplaceNew,2015config->thinLTOPrefixReplaceNativeObject) =2016getOldNewOptionsExtra(args, OPT_thinlto_prefix_replace);2017config->thinLTOObjectSuffixReplace =2018getOldNewOptions(args, OPT_thinlto_object_suffix_replace);2019config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path);2020config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate);2021config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file);2022config->ltoSampleProfileName = args.getLastArgValue(OPT_lto_sample_profile);2023// Handle miscellaneous boolean flags.2024config->ltoPGOWarnMismatch = args.hasFlag(OPT_lto_pgo_warn_mismatch,2025OPT_lto_pgo_warn_mismatch_no, true);2026config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);2027config->allowIsolation =2028args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);2029config->incremental =2030args.hasFlag(OPT_incremental, OPT_incremental_no,2031!config->doGC && config->doICF == ICFLevel::None &&2032!args.hasArg(OPT_order) && !args.hasArg(OPT_profile));2033config->integrityCheck =2034args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);2035config->cetCompat = args.hasFlag(OPT_cetcompat, OPT_cetcompat_no, false);2036config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);2037for (auto *arg : args.filtered(OPT_swaprun))2038parseSwaprun(arg->getValue());2039config->terminalServerAware =2040!config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);2041config->autoImport =2042args.hasFlag(OPT_auto_import, OPT_auto_import_no, config->mingw);2043config->pseudoRelocs = args.hasFlag(2044OPT_runtime_pseudo_reloc, OPT_runtime_pseudo_reloc_no, config->mingw);2045config->callGraphProfileSort = args.hasFlag(2046OPT_call_graph_profile_sort, OPT_call_graph_profile_sort_no, true);2047config->stdcallFixup =2048args.hasFlag(OPT_stdcall_fixup, OPT_stdcall_fixup_no, config->mingw);2049config->warnStdcallFixup = !args.hasArg(OPT_stdcall_fixup);2050config->allowDuplicateWeak =2051args.hasFlag(OPT_lld_allow_duplicate_weak,2052OPT_lld_allow_duplicate_weak_no, config->mingw);20532054if (args.hasFlag(OPT_inferasanlibs, OPT_inferasanlibs_no, false))2055warn("ignoring '/inferasanlibs', this flag is not supported");20562057if (config->incremental && args.hasArg(OPT_profile)) {2058warn("ignoring '/incremental' due to '/profile' specification");2059config->incremental = false;2060}20612062if (config->incremental && args.hasArg(OPT_order)) {2063warn("ignoring '/incremental' due to '/order' specification");2064config->incremental = false;2065}20662067if (config->incremental && config->doGC) {2068warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to "2069"disable");2070config->incremental = false;2071}20722073if (config->incremental && config->doICF != ICFLevel::None) {2074warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to "2075"disable");2076config->incremental = false;2077}20782079if (errorCount())2080return;20812082std::set<sys::fs::UniqueID> wholeArchives;2083for (auto *arg : args.filtered(OPT_wholearchive_file))2084if (std::optional<StringRef> path = findFile(arg->getValue()))2085if (std::optional<sys::fs::UniqueID> id = getUniqueID(*path))2086wholeArchives.insert(*id);20872088// A predicate returning true if a given path is an argument for2089// /wholearchive:, or /wholearchive is enabled globally.2090// This function is a bit tricky because "foo.obj /wholearchive:././foo.obj"2091// needs to be handled as "/wholearchive:foo.obj foo.obj".2092auto isWholeArchive = [&](StringRef path) -> bool {2093if (args.hasArg(OPT_wholearchive_flag))2094return true;2095if (std::optional<sys::fs::UniqueID> id = getUniqueID(path))2096return wholeArchives.count(*id);2097return false;2098};20992100// Create a list of input files. These can be given as OPT_INPUT options2101// and OPT_wholearchive_file options, and we also need to track OPT_start_lib2102// and OPT_end_lib.2103{2104llvm::TimeTraceScope timeScope2("Parse & queue inputs");2105bool inLib = false;2106for (auto *arg : args) {2107switch (arg->getOption().getID()) {2108case OPT_end_lib:2109if (!inLib)2110error("stray " + arg->getSpelling());2111inLib = false;2112break;2113case OPT_start_lib:2114if (inLib)2115error("nested " + arg->getSpelling());2116inLib = true;2117break;2118case OPT_wholearchive_file:2119if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))2120enqueuePath(*path, true, inLib);2121break;2122case OPT_INPUT:2123if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))2124enqueuePath(*path, isWholeArchive(*path), inLib);2125break;2126default:2127// Ignore other options.2128break;2129}2130}2131}21322133// Read all input files given via the command line.2134run();2135if (errorCount())2136return;21372138// We should have inferred a machine type by now from the input files, but if2139// not we assume x64.2140if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {2141warn("/machine is not specified. x64 is assumed");2142config->machine = AMD64;2143addWinSysRootLibSearchPaths();2144}2145config->wordsize = config->is64() ? 8 : 4;21462147if (config->printSearchPaths) {2148SmallString<256> buffer;2149raw_svector_ostream stream(buffer);2150stream << "Library search paths:\n";21512152for (StringRef path : searchPaths) {2153if (path == "")2154path = "(cwd)";2155stream << " " << path << "\n";2156}21572158message(buffer);2159}21602161// Process files specified as /defaultlib. These must be processed after2162// addWinSysRootLibSearchPaths(), which is why they are in a separate loop.2163for (auto *arg : args.filtered(OPT_defaultlib))2164if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))2165enqueuePath(*path, false, false);2166run();2167if (errorCount())2168return;21692170// Handle /RELEASE2171if (args.hasArg(OPT_release))2172config->writeCheckSum = true;21732174// Handle /safeseh, x86 only, on by default, except for mingw.2175if (config->machine == I386) {2176config->safeSEH = args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw);2177config->noSEH = args.hasArg(OPT_noseh);2178}21792180// Handle /functionpadmin2181for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))2182parseFunctionPadMin(arg);21832184// Handle /dependentloadflag2185for (auto *arg :2186args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt))2187parseDependentLoadFlags(arg);21882189if (tar) {2190llvm::TimeTraceScope timeScope("Reproducer: response file");2191tar->append("response.txt",2192createResponseFile(args, filePaths,2193ArrayRef<StringRef>(searchPaths).slice(1)));2194}21952196// Handle /largeaddressaware2197config->largeAddressAware = args.hasFlag(2198OPT_largeaddressaware, OPT_largeaddressaware_no, config->is64());21992200// Handle /highentropyva2201config->highEntropyVA =2202config->is64() &&2203args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true);22042205if (!config->dynamicBase &&2206(config->machine == ARMNT || isAnyArm64(config->machine)))2207error("/dynamicbase:no is not compatible with " +2208machineToStr(config->machine));22092210// Handle /export2211{2212llvm::TimeTraceScope timeScope("Parse /export");2213for (auto *arg : args.filtered(OPT_export)) {2214Export e = parseExport(arg->getValue());2215if (config->machine == I386) {2216if (!isDecorated(e.name))2217e.name = saver().save("_" + e.name);2218if (!e.extName.empty() && !isDecorated(e.extName))2219e.extName = saver().save("_" + e.extName);2220}2221config->exports.push_back(e);2222}2223}22242225// Handle /def2226if (auto *arg = args.getLastArg(OPT_deffile)) {2227// parseModuleDefs mutates Config object.2228parseModuleDefs(arg->getValue());2229}22302231// Handle generation of import library from a def file.2232if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {2233fixupExports();2234if (!config->noimplib)2235createImportLibrary(/*asLib=*/true);2236return;2237}22382239// Windows specific -- if no /subsystem is given, we need to infer2240// that from entry point name. Must happen before /entry handling,2241// and after the early return when just writing an import library.2242if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {2243llvm::TimeTraceScope timeScope("Infer subsystem");2244config->subsystem = inferSubsystem();2245if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN)2246fatal("subsystem must be defined");2247}22482249// Handle /entry and /dll2250{2251llvm::TimeTraceScope timeScope("Entry point");2252if (auto *arg = args.getLastArg(OPT_entry)) {2253if (!arg->getValue()[0])2254fatal("missing entry point symbol name");2255config->entry = addUndefined(mangle(arg->getValue()));2256} else if (!config->entry && !config->noEntry) {2257if (args.hasArg(OPT_dll)) {2258StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"2259: "_DllMainCRTStartup";2260config->entry = addUndefined(s);2261} else if (config->driverWdm) {2262// /driver:wdm implies /entry:_NtProcessStartup2263config->entry = addUndefined(mangle("_NtProcessStartup"));2264} else {2265// Windows specific -- If entry point name is not given, we need to2266// infer that from user-defined entry name.2267StringRef s = findDefaultEntry();2268if (s.empty())2269fatal("entry point must be defined");2270config->entry = addUndefined(s);2271log("Entry name inferred: " + s);2272}2273}2274}22752276// Handle /delayload2277{2278llvm::TimeTraceScope timeScope("Delay load");2279for (auto *arg : args.filtered(OPT_delayload)) {2280config->delayLoads.insert(StringRef(arg->getValue()).lower());2281if (config->machine == I386) {2282config->delayLoadHelper = addUndefined("___delayLoadHelper2@8");2283} else {2284config->delayLoadHelper = addUndefined("__delayLoadHelper2");2285}2286}2287}22882289// Set default image name if neither /out or /def set it.2290if (config->outputFile.empty()) {2291config->outputFile = getOutputPath(2292(*args.filtered(OPT_INPUT, OPT_wholearchive_file).begin())->getValue(),2293config->dll, config->driver);2294}22952296// Fail early if an output file is not writable.2297if (auto e = tryCreateFile(config->outputFile)) {2298error("cannot open output file " + config->outputFile + ": " + e.message());2299return;2300}23012302config->lldmapFile = getMapFile(args, OPT_lldmap, OPT_lldmap_file);2303config->mapFile = getMapFile(args, OPT_map, OPT_map_file);23042305if (config->mapFile != "" && args.hasArg(OPT_map_info)) {2306for (auto *arg : args.filtered(OPT_map_info)) {2307std::string s = StringRef(arg->getValue()).lower();2308if (s == "exports")2309config->mapInfo = true;2310else2311error("unknown option: /mapinfo:" + s);2312}2313}23142315if (config->lldmapFile != "" && config->lldmapFile == config->mapFile) {2316warn("/lldmap and /map have the same output file '" + config->mapFile +2317"'.\n>>> ignoring /lldmap");2318config->lldmapFile.clear();2319}23202321// If should create PDB, use the hash of PDB content for build id. Otherwise,2322// generate using the hash of executable content.2323if (args.hasFlag(OPT_build_id, OPT_build_id_no, false))2324config->buildIDHash = BuildIDHash::Binary;23252326if (shouldCreatePDB) {2327// Put the PDB next to the image if no /pdb flag was passed.2328if (config->pdbPath.empty()) {2329config->pdbPath = config->outputFile;2330sys::path::replace_extension(config->pdbPath, ".pdb");2331}23322333// The embedded PDB path should be the absolute path to the PDB if no2334// /pdbaltpath flag was passed.2335if (config->pdbAltPath.empty()) {2336config->pdbAltPath = config->pdbPath;23372338// It's important to make the path absolute and remove dots. This path2339// will eventually be written into the PE header, and certain Microsoft2340// tools won't work correctly if these assumptions are not held.2341sys::fs::make_absolute(config->pdbAltPath);2342sys::path::remove_dots(config->pdbAltPath);2343} else {2344// Don't do this earlier, so that ctx.OutputFile is ready.2345parsePDBAltPath();2346}2347config->buildIDHash = BuildIDHash::PDB;2348}23492350// Set default image base if /base is not given.2351if (config->imageBase == uint64_t(-1))2352config->imageBase = getDefaultImageBase();23532354ctx.symtab.addSynthetic(mangle("__ImageBase"), nullptr);2355if (config->machine == I386) {2356ctx.symtab.addAbsolute("___safe_se_handler_table", 0);2357ctx.symtab.addAbsolute("___safe_se_handler_count", 0);2358}23592360ctx.symtab.addAbsolute(mangle("__guard_fids_count"), 0);2361ctx.symtab.addAbsolute(mangle("__guard_fids_table"), 0);2362ctx.symtab.addAbsolute(mangle("__guard_flags"), 0);2363ctx.symtab.addAbsolute(mangle("__guard_iat_count"), 0);2364ctx.symtab.addAbsolute(mangle("__guard_iat_table"), 0);2365ctx.symtab.addAbsolute(mangle("__guard_longjmp_count"), 0);2366ctx.symtab.addAbsolute(mangle("__guard_longjmp_table"), 0);2367// Needed for MSVC 2017 15.5 CRT.2368ctx.symtab.addAbsolute(mangle("__enclave_config"), 0);2369// Needed for MSVC 2019 16.8 CRT.2370ctx.symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);2371ctx.symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);23722373if (isArm64EC(config->machine)) {2374ctx.symtab.addAbsolute("__arm64x_extra_rfe_table", 0);2375ctx.symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0);2376ctx.symtab.addAbsolute("__hybrid_code_map", 0);2377ctx.symtab.addAbsolute("__hybrid_code_map_count", 0);2378}23792380if (config->pseudoRelocs) {2381ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);2382ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);2383}2384if (config->mingw) {2385ctx.symtab.addAbsolute(mangle("__CTOR_LIST__"), 0);2386ctx.symtab.addAbsolute(mangle("__DTOR_LIST__"), 0);2387}2388if (config->debug || config->buildIDHash != BuildIDHash::None)2389if (ctx.symtab.findUnderscore("__buildid"))2390ctx.symtab.addUndefined(mangle("__buildid"));23912392// This code may add new undefined symbols to the link, which may enqueue more2393// symbol resolution tasks, so we need to continue executing tasks until we2394// converge.2395{2396llvm::TimeTraceScope timeScope("Add unresolved symbols");2397do {2398// Windows specific -- if entry point is not found,2399// search for its mangled names.2400if (config->entry)2401mangleMaybe(config->entry);24022403// Windows specific -- Make sure we resolve all dllexported symbols.2404for (Export &e : config->exports) {2405if (!e.forwardTo.empty())2406continue;2407e.sym = addUndefined(e.name);2408if (e.source != ExportSource::Directives)2409e.symbolName = mangleMaybe(e.sym);2410}24112412// Add weak aliases. Weak aliases is a mechanism to give remaining2413// undefined symbols final chance to be resolved successfully.2414for (auto pair : config->alternateNames) {2415StringRef from = pair.first;2416StringRef to = pair.second;2417Symbol *sym = ctx.symtab.find(from);2418if (!sym)2419continue;2420if (auto *u = dyn_cast<Undefined>(sym))2421if (!u->weakAlias)2422u->weakAlias = ctx.symtab.addUndefined(to);2423}24242425// If any inputs are bitcode files, the LTO code generator may create2426// references to library functions that are not explicit in the bitcode2427// file's symbol table. If any of those library functions are defined in a2428// bitcode file in an archive member, we need to arrange to use LTO to2429// compile those archive members by adding them to the link beforehand.2430if (!ctx.bitcodeFileInstances.empty()) {2431llvm::Triple TT(2432ctx.bitcodeFileInstances.front()->obj->getTargetTriple());2433for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))2434ctx.symtab.addLibcall(s);2435}24362437// Windows specific -- if __load_config_used can be resolved, resolve it.2438if (ctx.symtab.findUnderscore("_load_config_used"))2439addUndefined(mangle("_load_config_used"));24402441if (args.hasArg(OPT_include_optional)) {2442// Handle /includeoptional2443for (auto *arg : args.filtered(OPT_include_optional))2444if (isa_and_nonnull<LazyArchive>(ctx.symtab.find(arg->getValue())))2445addUndefined(arg->getValue());2446}2447} while (run());2448}24492450// Create wrapped symbols for -wrap option.2451std::vector<WrappedSymbol> wrapped = addWrappedSymbols(ctx, args);2452// Load more object files that might be needed for wrapped symbols.2453if (!wrapped.empty())2454while (run())2455;24562457if (config->autoImport || config->stdcallFixup) {2458// MinGW specific.2459// Load any further object files that might be needed for doing automatic2460// imports, and do stdcall fixups.2461//2462// For cases with no automatically imported symbols, this iterates once2463// over the symbol table and doesn't do anything.2464//2465// For the normal case with a few automatically imported symbols, this2466// should only need to be run once, since each new object file imported2467// is an import library and wouldn't add any new undefined references,2468// but there's nothing stopping the __imp_ symbols from coming from a2469// normal object file as well (although that won't be used for the2470// actual autoimport later on). If this pass adds new undefined references,2471// we won't iterate further to resolve them.2472//2473// If stdcall fixups only are needed for loading import entries from2474// a DLL without import library, this also just needs running once.2475// If it ends up pulling in more object files from static libraries,2476// (and maybe doing more stdcall fixups along the way), this would need2477// to loop these two calls.2478ctx.symtab.loadMinGWSymbols();2479run();2480}24812482// At this point, we should not have any symbols that cannot be resolved.2483// If we are going to do codegen for link-time optimization, check for2484// unresolvable symbols first, so we don't spend time generating code that2485// will fail to link anyway.2486if (!ctx.bitcodeFileInstances.empty() && !config->forceUnresolved)2487ctx.symtab.reportUnresolvable();2488if (errorCount())2489return;24902491config->hadExplicitExports = !config->exports.empty();2492if (config->mingw) {2493// In MinGW, all symbols are automatically exported if no symbols2494// are chosen to be exported.2495maybeExportMinGWSymbols(args);2496}24972498// Do LTO by compiling bitcode input files to a set of native COFF files then2499// link those files (unless -thinlto-index-only was given, in which case we2500// resolve symbols and write indices, but don't generate native code or link).2501ctx.symtab.compileBitcodeFiles();25022503if (Defined *d =2504dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used")))2505config->gcroot.push_back(d);25062507// If -thinlto-index-only is given, we should create only "index2508// files" and not object files. Index file creation is already done2509// in addCombinedLTOObject, so we are done if that's the case.2510// Likewise, don't emit object files for other /lldemit options.2511if (config->emit != EmitKind::Obj || config->thinLTOIndexOnly)2512return;25132514// If we generated native object files from bitcode files, this resolves2515// references to the symbols we use from them.2516run();25172518// Apply symbol renames for -wrap.2519if (!wrapped.empty())2520wrapSymbols(ctx, wrapped);25212522// Resolve remaining undefined symbols and warn about imported locals.2523ctx.symtab.resolveRemainingUndefines();2524if (errorCount())2525return;25262527if (config->mingw) {2528// Make sure the crtend.o object is the last object file. This object2529// file can contain terminating section chunks that need to be placed2530// last. GNU ld processes files and static libraries explicitly in the2531// order provided on the command line, while lld will pull in needed2532// files from static libraries only after the last object file on the2533// command line.2534for (auto i = ctx.objFileInstances.begin(), e = ctx.objFileInstances.end();2535i != e; i++) {2536ObjFile *file = *i;2537if (isCrtend(file->getName())) {2538ctx.objFileInstances.erase(i);2539ctx.objFileInstances.push_back(file);2540break;2541}2542}2543}25442545// Windows specific -- when we are creating a .dll file, we also2546// need to create a .lib file. In MinGW mode, we only do that when the2547// -implib option is given explicitly, for compatibility with GNU ld.2548if (!config->exports.empty() || config->dll) {2549llvm::TimeTraceScope timeScope("Create .lib exports");2550fixupExports();2551if (!config->noimplib && (!config->mingw || !config->implib.empty()))2552createImportLibrary(/*asLib=*/false);2553assignExportOrdinals();2554}25552556// Handle /output-def (MinGW specific).2557if (auto *arg = args.getLastArg(OPT_output_def))2558writeDefFile(arg->getValue(), config->exports);25592560// Set extra alignment for .comm symbols2561for (auto pair : config->alignComm) {2562StringRef name = pair.first;2563uint32_t alignment = pair.second;25642565Symbol *sym = ctx.symtab.find(name);2566if (!sym) {2567warn("/aligncomm symbol " + name + " not found");2568continue;2569}25702571// If the symbol isn't common, it must have been replaced with a regular2572// symbol, which will carry its own alignment.2573auto *dc = dyn_cast<DefinedCommon>(sym);2574if (!dc)2575continue;25762577CommonChunk *c = dc->getChunk();2578c->setAlignment(std::max(c->getAlignment(), alignment));2579}25802581// Windows specific -- Create an embedded or side-by-side manifest.2582// /manifestdependency: enables /manifest unless an explicit /manifest:no is2583// also passed.2584if (config->manifest == Configuration::Embed)2585addBuffer(createManifestRes(), false, false);2586else if (config->manifest == Configuration::SideBySide ||2587(config->manifest == Configuration::Default &&2588!config->manifestDependencies.empty()))2589createSideBySideManifest();25902591// Handle /order. We want to do this at this moment because we2592// need a complete list of comdat sections to warn on nonexistent2593// functions.2594if (auto *arg = args.getLastArg(OPT_order)) {2595if (args.hasArg(OPT_call_graph_ordering_file))2596error("/order and /call-graph-order-file may not be used together");2597parseOrderFile(arg->getValue());2598config->callGraphProfileSort = false;2599}26002601// Handle /call-graph-ordering-file and /call-graph-profile-sort (default on).2602if (config->callGraphProfileSort) {2603llvm::TimeTraceScope timeScope("Call graph");2604if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) {2605parseCallGraphFile(arg->getValue());2606}2607readCallGraphsFromObjectFiles(ctx);2608}26092610// Handle /print-symbol-order.2611if (auto *arg = args.getLastArg(OPT_print_symbol_order))2612config->printSymbolOrder = arg->getValue();26132614ctx.symtab.initializeEntryThunks();26152616// Identify unreferenced COMDAT sections.2617if (config->doGC) {2618if (config->mingw) {2619// markLive doesn't traverse .eh_frame, but the personality function is2620// only reached that way. The proper solution would be to parse and2621// traverse the .eh_frame section, like the ELF linker does.2622// For now, just manually try to retain the known possible personality2623// functions. This doesn't bring in more object files, but only marks2624// functions that already have been included to be retained.2625for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0",2626"rust_eh_personality"}) {2627Defined *d = dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore(n));2628if (d && !d->isGCRoot) {2629d->isGCRoot = true;2630config->gcroot.push_back(d);2631}2632}2633}26342635markLive(ctx);2636}26372638// Needs to happen after the last call to addFile().2639convertResources();26402641// Identify identical COMDAT sections to merge them.2642if (config->doICF != ICFLevel::None) {2643findKeepUniqueSections(ctx);2644doICF(ctx);2645}26462647// Write the result.2648writeResult(ctx);26492650// Stop early so we can print the results.2651rootTimer.stop();2652if (config->showTiming)2653ctx.rootTimer.print();26542655if (config->timeTraceEnabled) {2656// Manually stop the topmost "COFF link" scope, since we're shutting down.2657timeTraceProfilerEnd();26582659checkError(timeTraceProfilerWrite(2660args.getLastArgValue(OPT_time_trace_eq).str(), config->outputFile));2661timeTraceProfilerCleanup();2662}2663}26642665} // namespace lld::coff266626672668