in lld/COFF/Driver.cpp [1252:2281]
void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ScopedTimer rootTimer(ctx.rootTimer);
// Needed for LTO.
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
// If the first command line argument is "/lib", link.exe acts like lib.exe.
// We call our own implementation of lib.exe that understands bitcode files.
if (argsArr.size() > 1 &&
(StringRef(argsArr[1]).equals_insensitive("/lib") ||
StringRef(argsArr[1]).equals_insensitive("-lib"))) {
if (llvm::libDriverMain(argsArr.slice(1)) != 0)
fatal("lib failed");
return;
}
// Parse command line options.
ArgParser parser;
opt::InputArgList args = parser.parse(argsArr);
// Parse and evaluate -mllvm options.
std::vector<const char *> v;
v.push_back("lld-link (LLVM option parsing)");
for (auto *arg : args.filtered(OPT_mllvm))
v.push_back(arg->getValue());
cl::ResetAllOptionOccurrences();
cl::ParseCommandLineOptions(v.size(), v.data());
// Handle /errorlimit early, because error() depends on it.
if (auto *arg = args.getLastArg(OPT_errorlimit)) {
int n = 20;
StringRef s = arg->getValue();
if (s.getAsInteger(10, n))
error(arg->getSpelling() + " number expected, but got " + s);
errorHandler().errorLimit = n;
}
// Handle /help
if (args.hasArg(OPT_help)) {
printHelp(argsArr[0]);
return;
}
// /threads: takes a positive integer and provides the default value for
// /opt:lldltojobs=.
if (auto *arg = args.getLastArg(OPT_threads)) {
StringRef v(arg->getValue());
unsigned threads = 0;
if (!llvm::to_integer(v, threads, 0) || threads == 0)
error(arg->getSpelling() + ": expected a positive integer, but got '" +
arg->getValue() + "'");
parallel::strategy = hardware_concurrency(threads);
config->thinLTOJobs = v.str();
}
if (args.hasArg(OPT_show_timing))
config->showTiming = true;
config->showSummary = args.hasArg(OPT_summary);
// Handle --version, which is an lld extension. This option is a bit odd
// because it doesn't start with "/", but we deliberately chose "--" to
// avoid conflict with /version and for compatibility with clang-cl.
if (args.hasArg(OPT_dash_dash_version)) {
message(getLLDVersion());
return;
}
// Handle /lldmingw early, since it can potentially affect how other
// options are handled.
config->mingw = args.hasArg(OPT_lldmingw);
// Handle /linkrepro and /reproduce.
if (Optional<std::string> path = getReproduceFile(args)) {
Expected<std::unique_ptr<TarWriter>> errOrWriter =
TarWriter::create(*path, sys::path::stem(*path));
if (errOrWriter) {
tar = std::move(*errOrWriter);
} else {
error("/linkrepro: failed to open " + *path + ": " +
toString(errOrWriter.takeError()));
}
}
if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {
if (args.hasArg(OPT_deffile))
config->noEntry = true;
else
fatal("no input files");
}
// Construct search path list.
searchPaths.push_back("");
for (auto *arg : args.filtered(OPT_libpath))
searchPaths.push_back(arg->getValue());
if (!args.hasArg(OPT_lldignoreenv))
addLibSearchPaths();
// Handle /ignore
for (auto *arg : args.filtered(OPT_ignore)) {
SmallVector<StringRef, 8> vec;
StringRef(arg->getValue()).split(vec, ',');
for (StringRef s : vec) {
if (s == "4037")
config->warnMissingOrderSymbol = false;
else if (s == "4099")
config->warnDebugInfoUnusable = false;
else if (s == "4217")
config->warnLocallyDefinedImported = false;
else if (s == "longsections")
config->warnLongSectionNames = false;
// Other warning numbers are ignored.
}
}
// Handle /out
if (auto *arg = args.getLastArg(OPT_out))
config->outputFile = arg->getValue();
// Handle /verbose
if (args.hasArg(OPT_verbose))
config->verbose = true;
errorHandler().verbose = config->verbose;
// Handle /force or /force:unresolved
if (args.hasArg(OPT_force, OPT_force_unresolved))
config->forceUnresolved = true;
// Handle /force or /force:multiple
if (args.hasArg(OPT_force, OPT_force_multiple))
config->forceMultiple = true;
// Handle /force or /force:multipleres
if (args.hasArg(OPT_force, OPT_force_multipleres))
config->forceMultipleRes = true;
// Handle /debug
DebugKind debug = parseDebugKind(args);
if (debug == DebugKind::Full || debug == DebugKind::Dwarf ||
debug == DebugKind::GHash || debug == DebugKind::NoGHash) {
config->debug = true;
config->incremental = true;
}
// Handle /demangle
config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no);
// Handle /debugtype
config->debugTypes = parseDebugTypes(args);
// Handle /driver[:uponly|:wdm].
config->driverUponly = args.hasArg(OPT_driver_uponly) ||
args.hasArg(OPT_driver_uponly_wdm) ||
args.hasArg(OPT_driver_wdm_uponly);
config->driverWdm = args.hasArg(OPT_driver_wdm) ||
args.hasArg(OPT_driver_uponly_wdm) ||
args.hasArg(OPT_driver_wdm_uponly);
config->driver =
config->driverUponly || config->driverWdm || args.hasArg(OPT_driver);
// Handle /pdb
bool shouldCreatePDB =
(debug == DebugKind::Full || debug == DebugKind::GHash ||
debug == DebugKind::NoGHash);
if (shouldCreatePDB) {
if (auto *arg = args.getLastArg(OPT_pdb))
config->pdbPath = arg->getValue();
if (auto *arg = args.getLastArg(OPT_pdbaltpath))
config->pdbAltPath = arg->getValue();
if (auto *arg = args.getLastArg(OPT_pdbpagesize))
parsePDBPageSize(arg->getValue());
if (args.hasArg(OPT_natvis))
config->natvisFiles = args.getAllArgValues(OPT_natvis);
if (args.hasArg(OPT_pdbstream)) {
for (const StringRef value : args.getAllArgValues(OPT_pdbstream)) {
const std::pair<StringRef, StringRef> nameFile = value.split("=");
const StringRef name = nameFile.first;
const std::string file = nameFile.second.str();
config->namedStreams[name] = file;
}
}
if (auto *arg = args.getLastArg(OPT_pdb_source_path))
config->pdbSourcePath = arg->getValue();
}
// Handle /pdbstripped
if (args.hasArg(OPT_pdbstripped))
warn("ignoring /pdbstripped flag, it is not yet supported");
// Handle /noentry
if (args.hasArg(OPT_noentry)) {
if (args.hasArg(OPT_dll))
config->noEntry = true;
else
error("/noentry must be specified with /dll");
}
// Handle /dll
if (args.hasArg(OPT_dll)) {
config->dll = true;
config->manifestID = 2;
}
// Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase
// because we need to explicitly check whether that option or its inverse was
// present in the argument list in order to handle /fixed.
auto *dynamicBaseArg = args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no);
if (dynamicBaseArg &&
dynamicBaseArg->getOption().getID() == OPT_dynamicbase_no)
config->dynamicBase = false;
// MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the
// default setting for any other project type.", but link.exe defaults to
// /FIXED:NO for exe outputs as well. Match behavior, not docs.
bool fixed = args.hasFlag(OPT_fixed, OPT_fixed_no, false);
if (fixed) {
if (dynamicBaseArg &&
dynamicBaseArg->getOption().getID() == OPT_dynamicbase) {
error("/fixed must not be specified with /dynamicbase");
} else {
config->relocatable = false;
config->dynamicBase = false;
}
}
// Handle /appcontainer
config->appContainer =
args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false);
// Handle /machine
if (auto *arg = args.getLastArg(OPT_machine)) {
config->machine = getMachineType(arg->getValue());
if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN)
fatal(Twine("unknown /machine argument: ") + arg->getValue());
}
// Handle /nodefaultlib:<filename>
for (auto *arg : args.filtered(OPT_nodefaultlib))
config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower());
// Handle /nodefaultlib
if (args.hasArg(OPT_nodefaultlib_all))
config->noDefaultLibAll = true;
// Handle /base
if (auto *arg = args.getLastArg(OPT_base))
parseNumbers(arg->getValue(), &config->imageBase);
// Handle /filealign
if (auto *arg = args.getLastArg(OPT_filealign)) {
parseNumbers(arg->getValue(), &config->fileAlign);
if (!isPowerOf2_64(config->fileAlign))
error("/filealign: not a power of two: " + Twine(config->fileAlign));
}
// Handle /stack
if (auto *arg = args.getLastArg(OPT_stack))
parseNumbers(arg->getValue(), &config->stackReserve, &config->stackCommit);
// Handle /guard:cf
if (auto *arg = args.getLastArg(OPT_guard))
parseGuard(arg->getValue());
// Handle /heap
if (auto *arg = args.getLastArg(OPT_heap))
parseNumbers(arg->getValue(), &config->heapReserve, &config->heapCommit);
// Handle /version
if (auto *arg = args.getLastArg(OPT_version))
parseVersion(arg->getValue(), &config->majorImageVersion,
&config->minorImageVersion);
// Handle /subsystem
if (auto *arg = args.getLastArg(OPT_subsystem))
parseSubsystem(arg->getValue(), &config->subsystem,
&config->majorSubsystemVersion,
&config->minorSubsystemVersion);
// Handle /osversion
if (auto *arg = args.getLastArg(OPT_osversion)) {
parseVersion(arg->getValue(), &config->majorOSVersion,
&config->minorOSVersion);
} else {
config->majorOSVersion = config->majorSubsystemVersion;
config->minorOSVersion = config->minorSubsystemVersion;
}
// Handle /timestamp
if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) {
if (arg->getOption().getID() == OPT_repro) {
config->timestamp = 0;
config->repro = true;
} else {
config->repro = false;
StringRef value(arg->getValue());
if (value.getAsInteger(0, config->timestamp))
fatal(Twine("invalid timestamp: ") + value +
". Expected 32-bit integer");
}
} else {
config->repro = false;
config->timestamp = time(nullptr);
}
// Handle /alternatename
for (auto *arg : args.filtered(OPT_alternatename))
parseAlternateName(arg->getValue());
// Handle /include
for (auto *arg : args.filtered(OPT_incl))
addUndefined(arg->getValue());
// Handle /implib
if (auto *arg = args.getLastArg(OPT_implib))
config->implib = arg->getValue();
// Handle /opt.
bool doGC = debug == DebugKind::None || args.hasArg(OPT_profile);
Optional<ICFLevel> icfLevel = None;
if (args.hasArg(OPT_profile))
icfLevel = ICFLevel::None;
unsigned tailMerge = 1;
bool ltoNewPM = LLVM_ENABLE_NEW_PASS_MANAGER;
bool ltoDebugPM = false;
for (auto *arg : args.filtered(OPT_opt)) {
std::string str = StringRef(arg->getValue()).lower();
SmallVector<StringRef, 1> vec;
StringRef(str).split(vec, ',');
for (StringRef s : vec) {
if (s == "ref") {
doGC = true;
} else if (s == "noref") {
doGC = false;
} else if (s == "icf" || s.startswith("icf=")) {
icfLevel = ICFLevel::All;
} else if (s == "safeicf") {
icfLevel = ICFLevel::Safe;
} else if (s == "noicf") {
icfLevel = ICFLevel::None;
} else if (s == "lldtailmerge") {
tailMerge = 2;
} else if (s == "nolldtailmerge") {
tailMerge = 0;
} else if (s == "ltonewpassmanager") {
ltoNewPM = true;
} else if (s == "noltonewpassmanager") {
ltoNewPM = false;
} else if (s == "ltodebugpassmanager") {
ltoDebugPM = true;
} else if (s == "noltodebugpassmanager") {
ltoDebugPM = false;
} else if (s.startswith("lldlto=")) {
StringRef optLevel = s.substr(7);
if (optLevel.getAsInteger(10, config->ltoo) || config->ltoo > 3)
error("/opt:lldlto: invalid optimization level: " + optLevel);
} else if (s.startswith("lldltojobs=")) {
StringRef jobs = s.substr(11);
if (!get_threadpool_strategy(jobs))
error("/opt:lldltojobs: invalid job count: " + jobs);
config->thinLTOJobs = jobs.str();
} else if (s.startswith("lldltopartitions=")) {
StringRef n = s.substr(17);
if (n.getAsInteger(10, config->ltoPartitions) ||
config->ltoPartitions == 0)
error("/opt:lldltopartitions: invalid partition count: " + n);
} else if (s != "lbr" && s != "nolbr")
error("/opt: unknown option: " + s);
}
}
if (!icfLevel)
icfLevel = doGC ? ICFLevel::All : ICFLevel::None;
config->doGC = doGC;
config->doICF = icfLevel.getValue();
config->tailMerge =
(tailMerge == 1 && config->doICF != ICFLevel::None) || tailMerge == 2;
config->ltoNewPassManager = ltoNewPM;
config->ltoDebugPassManager = ltoDebugPM;
// Handle /lldsavetemps
if (args.hasArg(OPT_lldsavetemps))
config->saveTemps = true;
// Handle /kill-at
if (args.hasArg(OPT_kill_at))
config->killAt = true;
// Handle /lldltocache
if (auto *arg = args.getLastArg(OPT_lldltocache))
config->ltoCache = arg->getValue();
// Handle /lldsavecachepolicy
if (auto *arg = args.getLastArg(OPT_lldltocachepolicy))
config->ltoCachePolicy = CHECK(
parseCachePruningPolicy(arg->getValue()),
Twine("/lldltocachepolicy: invalid cache policy: ") + arg->getValue());
// Handle /failifmismatch
for (auto *arg : args.filtered(OPT_failifmismatch))
checkFailIfMismatch(arg->getValue(), nullptr);
// Handle /merge
for (auto *arg : args.filtered(OPT_merge))
parseMerge(arg->getValue());
// Add default section merging rules after user rules. User rules take
// precedence, but we will emit a warning if there is a conflict.
parseMerge(".idata=.rdata");
parseMerge(".didat=.rdata");
parseMerge(".edata=.rdata");
parseMerge(".xdata=.rdata");
parseMerge(".bss=.data");
if (config->mingw) {
parseMerge(".ctors=.rdata");
parseMerge(".dtors=.rdata");
parseMerge(".CRT=.rdata");
}
// Handle /section
for (auto *arg : args.filtered(OPT_section))
parseSection(arg->getValue());
// Handle /align
if (auto *arg = args.getLastArg(OPT_align)) {
parseNumbers(arg->getValue(), &config->align);
if (!isPowerOf2_64(config->align))
error("/align: not a power of two: " + StringRef(arg->getValue()));
if (!args.hasArg(OPT_driver))
warn("/align specified without /driver; image may not run");
}
// Handle /aligncomm
for (auto *arg : args.filtered(OPT_aligncomm))
parseAligncomm(arg->getValue());
// Handle /manifestdependency.
for (auto *arg : args.filtered(OPT_manifestdependency))
config->manifestDependencies.insert(arg->getValue());
// Handle /manifest and /manifest:
if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
if (arg->getOption().getID() == OPT_manifest)
config->manifest = Configuration::SideBySide;
else
parseManifest(arg->getValue());
}
// Handle /manifestuac
if (auto *arg = args.getLastArg(OPT_manifestuac))
parseManifestUAC(arg->getValue());
// Handle /manifestfile
if (auto *arg = args.getLastArg(OPT_manifestfile))
config->manifestFile = arg->getValue();
// Handle /manifestinput
for (auto *arg : args.filtered(OPT_manifestinput))
config->manifestInput.push_back(arg->getValue());
if (!config->manifestInput.empty() &&
config->manifest != Configuration::Embed) {
fatal("/manifestinput: requires /manifest:embed");
}
config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);
config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||
args.hasArg(OPT_thinlto_index_only_arg);
config->thinLTOIndexOnlyArg =
args.getLastArgValue(OPT_thinlto_index_only_arg);
config->thinLTOPrefixReplace =
getOldNewOptions(args, OPT_thinlto_prefix_replace);
config->thinLTOObjectSuffixReplace =
getOldNewOptions(args, OPT_thinlto_object_suffix_replace);
config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path);
config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate);
config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file);
// Handle miscellaneous boolean flags.
config->ltoPGOWarnMismatch = args.hasFlag(OPT_lto_pgo_warn_mismatch,
OPT_lto_pgo_warn_mismatch_no, true);
config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);
config->allowIsolation =
args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);
config->incremental =
args.hasFlag(OPT_incremental, OPT_incremental_no,
!config->doGC && config->doICF == ICFLevel::None &&
!args.hasArg(OPT_order) && !args.hasArg(OPT_profile));
config->integrityCheck =
args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
config->cetCompat = args.hasFlag(OPT_cetcompat, OPT_cetcompat_no, false);
config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
for (auto *arg : args.filtered(OPT_swaprun))
parseSwaprun(arg->getValue());
config->terminalServerAware =
!config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
config->debugDwarf = debug == DebugKind::Dwarf;
config->debugGHashes = debug == DebugKind::GHash || debug == DebugKind::Full;
config->debugSymtab = debug == DebugKind::Symtab;
config->autoImport =
args.hasFlag(OPT_auto_import, OPT_auto_import_no, config->mingw);
config->pseudoRelocs = args.hasFlag(
OPT_runtime_pseudo_reloc, OPT_runtime_pseudo_reloc_no, config->mingw);
config->callGraphProfileSort = args.hasFlag(
OPT_call_graph_profile_sort, OPT_call_graph_profile_sort_no, true);
config->stdcallFixup =
args.hasFlag(OPT_stdcall_fixup, OPT_stdcall_fixup_no, config->mingw);
config->warnStdcallFixup = !args.hasArg(OPT_stdcall_fixup);
// Don't warn about long section names, such as .debug_info, for mingw or
// when -debug:dwarf is requested.
if (config->mingw || config->debugDwarf)
config->warnLongSectionNames = false;
config->lldmapFile = getMapFile(args, OPT_lldmap, OPT_lldmap_file);
config->mapFile = getMapFile(args, OPT_map, OPT_map_file);
if (config->lldmapFile != "" && config->lldmapFile == config->mapFile) {
warn("/lldmap and /map have the same output file '" + config->mapFile +
"'.\n>>> ignoring /lldmap");
config->lldmapFile.clear();
}
if (config->incremental && args.hasArg(OPT_profile)) {
warn("ignoring '/incremental' due to '/profile' specification");
config->incremental = false;
}
if (config->incremental && args.hasArg(OPT_order)) {
warn("ignoring '/incremental' due to '/order' specification");
config->incremental = false;
}
if (config->incremental && config->doGC) {
warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to "
"disable");
config->incremental = false;
}
if (config->incremental && config->doICF != ICFLevel::None) {
warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to "
"disable");
config->incremental = false;
}
if (errorCount())
return;
std::set<sys::fs::UniqueID> wholeArchives;
for (auto *arg : args.filtered(OPT_wholearchive_file))
if (Optional<StringRef> path = doFindFile(arg->getValue()))
if (Optional<sys::fs::UniqueID> id = getUniqueID(*path))
wholeArchives.insert(*id);
// A predicate returning true if a given path is an argument for
// /wholearchive:, or /wholearchive is enabled globally.
// This function is a bit tricky because "foo.obj /wholearchive:././foo.obj"
// needs to be handled as "/wholearchive:foo.obj foo.obj".
auto isWholeArchive = [&](StringRef path) -> bool {
if (args.hasArg(OPT_wholearchive_flag))
return true;
if (Optional<sys::fs::UniqueID> id = getUniqueID(path))
return wholeArchives.count(*id);
return false;
};
// Create a list of input files. These can be given as OPT_INPUT options
// and OPT_wholearchive_file options, and we also need to track OPT_start_lib
// and OPT_end_lib.
bool inLib = false;
for (auto *arg : args) {
switch (arg->getOption().getID()) {
case OPT_end_lib:
if (!inLib)
error("stray " + arg->getSpelling());
inLib = false;
break;
case OPT_start_lib:
if (inLib)
error("nested " + arg->getSpelling());
inLib = true;
break;
case OPT_wholearchive_file:
if (Optional<StringRef> path = findFile(arg->getValue()))
enqueuePath(*path, true, inLib);
break;
case OPT_INPUT:
if (Optional<StringRef> path = findFile(arg->getValue()))
enqueuePath(*path, isWholeArchive(*path), inLib);
break;
default:
// Ignore other options.
break;
}
}
// Process files specified as /defaultlib. These should be enequeued after
// other files, which is why they are in a separate loop.
for (auto *arg : args.filtered(OPT_defaultlib))
if (Optional<StringRef> path = findLib(arg->getValue()))
enqueuePath(*path, false, false);
// Read all input files given via the command line.
run();
if (errorCount())
return;
// We should have inferred a machine type by now from the input files, but if
// not we assume x64.
if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {
warn("/machine is not specified. x64 is assumed");
config->machine = AMD64;
}
config->wordsize = config->is64() ? 8 : 4;
// Handle /safeseh, x86 only, on by default, except for mingw.
if (config->machine == I386) {
config->safeSEH = args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw);
config->noSEH = args.hasArg(OPT_noseh);
}
// Handle /functionpadmin
for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
parseFunctionPadMin(arg, config->machine);
if (tar)
tar->append("response.txt",
createResponseFile(args, filePaths,
ArrayRef<StringRef>(searchPaths).slice(1)));
// Handle /largeaddressaware
config->largeAddressAware = args.hasFlag(
OPT_largeaddressaware, OPT_largeaddressaware_no, config->is64());
// Handle /highentropyva
config->highEntropyVA =
config->is64() &&
args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true);
if (!config->dynamicBase &&
(config->machine == ARMNT || config->machine == ARM64))
error("/dynamicbase:no is not compatible with " +
machineToStr(config->machine));
// Handle /export
for (auto *arg : args.filtered(OPT_export)) {
Export e = parseExport(arg->getValue());
if (config->machine == I386) {
if (!isDecorated(e.name))
e.name = saver.save("_" + e.name);
if (!e.extName.empty() && !isDecorated(e.extName))
e.extName = saver.save("_" + e.extName);
}
config->exports.push_back(e);
}
// Handle /def
if (auto *arg = args.getLastArg(OPT_deffile)) {
// parseModuleDefs mutates Config object.
parseModuleDefs(arg->getValue());
}
// Handle generation of import library from a def file.
if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {
fixupExports();
createImportLibrary(/*asLib=*/true);
return;
}
// Windows specific -- if no /subsystem is given, we need to infer
// that from entry point name. Must happen before /entry handling,
// and after the early return when just writing an import library.
if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
config->subsystem = inferSubsystem();
if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
fatal("subsystem must be defined");
}
// Handle /entry and /dll
if (auto *arg = args.getLastArg(OPT_entry)) {
config->entry = addUndefined(mangle(arg->getValue()));
} else if (!config->entry && !config->noEntry) {
if (args.hasArg(OPT_dll)) {
StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"
: "_DllMainCRTStartup";
config->entry = addUndefined(s);
} else if (config->driverWdm) {
// /driver:wdm implies /entry:_NtProcessStartup
config->entry = addUndefined(mangle("_NtProcessStartup"));
} else {
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name.
StringRef s = findDefaultEntry();
if (s.empty())
fatal("entry point must be defined");
config->entry = addUndefined(s);
log("Entry name inferred: " + s);
}
}
// Handle /delayload
for (auto *arg : args.filtered(OPT_delayload)) {
config->delayLoads.insert(StringRef(arg->getValue()).lower());
if (config->machine == I386) {
config->delayLoadHelper = addUndefined("___delayLoadHelper2@8");
} else {
config->delayLoadHelper = addUndefined("__delayLoadHelper2");
}
}
// Set default image name if neither /out or /def set it.
if (config->outputFile.empty()) {
config->outputFile = getOutputPath(
(*args.filtered(OPT_INPUT, OPT_wholearchive_file).begin())->getValue());
}
// Fail early if an output file is not writable.
if (auto e = tryCreateFile(config->outputFile)) {
error("cannot open output file " + config->outputFile + ": " + e.message());
return;
}
if (shouldCreatePDB) {
// Put the PDB next to the image if no /pdb flag was passed.
if (config->pdbPath.empty()) {
config->pdbPath = config->outputFile;
sys::path::replace_extension(config->pdbPath, ".pdb");
}
// The embedded PDB path should be the absolute path to the PDB if no
// /pdbaltpath flag was passed.
if (config->pdbAltPath.empty()) {
config->pdbAltPath = config->pdbPath;
// It's important to make the path absolute and remove dots. This path
// will eventually be written into the PE header, and certain Microsoft
// tools won't work correctly if these assumptions are not held.
sys::fs::make_absolute(config->pdbAltPath);
sys::path::remove_dots(config->pdbAltPath);
} else {
// Don't do this earlier, so that Config->OutputFile is ready.
parsePDBAltPath(config->pdbAltPath);
}
}
// Set default image base if /base is not given.
if (config->imageBase == uint64_t(-1))
config->imageBase = getDefaultImageBase();
ctx.symtab.addSynthetic(mangle("__ImageBase"), nullptr);
if (config->machine == I386) {
ctx.symtab.addAbsolute("___safe_se_handler_table", 0);
ctx.symtab.addAbsolute("___safe_se_handler_count", 0);
}
ctx.symtab.addAbsolute(mangle("__guard_fids_count"), 0);
ctx.symtab.addAbsolute(mangle("__guard_fids_table"), 0);
ctx.symtab.addAbsolute(mangle("__guard_flags"), 0);
ctx.symtab.addAbsolute(mangle("__guard_iat_count"), 0);
ctx.symtab.addAbsolute(mangle("__guard_iat_table"), 0);
ctx.symtab.addAbsolute(mangle("__guard_longjmp_count"), 0);
ctx.symtab.addAbsolute(mangle("__guard_longjmp_table"), 0);
// Needed for MSVC 2017 15.5 CRT.
ctx.symtab.addAbsolute(mangle("__enclave_config"), 0);
// Needed for MSVC 2019 16.8 CRT.
ctx.symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);
ctx.symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);
if (config->pseudoRelocs) {
ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
}
if (config->mingw) {
ctx.symtab.addAbsolute(mangle("__CTOR_LIST__"), 0);
ctx.symtab.addAbsolute(mangle("__DTOR_LIST__"), 0);
}
// This code may add new undefined symbols to the link, which may enqueue more
// symbol resolution tasks, so we need to continue executing tasks until we
// converge.
do {
// Windows specific -- if entry point is not found,
// search for its mangled names.
if (config->entry)
mangleMaybe(config->entry);
// Windows specific -- Make sure we resolve all dllexported symbols.
for (Export &e : config->exports) {
if (!e.forwardTo.empty())
continue;
e.sym = addUndefined(e.name);
if (!e.directives)
e.symbolName = mangleMaybe(e.sym);
}
// Add weak aliases. Weak aliases is a mechanism to give remaining
// undefined symbols final chance to be resolved successfully.
for (auto pair : config->alternateNames) {
StringRef from = pair.first;
StringRef to = pair.second;
Symbol *sym = ctx.symtab.find(from);
if (!sym)
continue;
if (auto *u = dyn_cast<Undefined>(sym))
if (!u->weakAlias)
u->weakAlias = ctx.symtab.addUndefined(to);
}
// If any inputs are bitcode files, the LTO code generator may create
// references to library functions that are not explicit in the bitcode
// file's symbol table. If any of those library functions are defined in a
// bitcode file in an archive member, we need to arrange to use LTO to
// compile those archive members by adding them to the link beforehand.
if (!ctx.bitcodeFileInstances.empty())
for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
ctx.symtab.addLibcall(s);
// Windows specific -- if __load_config_used can be resolved, resolve it.
if (ctx.symtab.findUnderscore("_load_config_used"))
addUndefined(mangle("_load_config_used"));
} while (run());
if (args.hasArg(OPT_include_optional)) {
// Handle /includeoptional
for (auto *arg : args.filtered(OPT_include_optional))
if (isa_and_nonnull<LazyArchive>(ctx.symtab.find(arg->getValue())))
addUndefined(arg->getValue());
while (run());
}
// Create wrapped symbols for -wrap option.
std::vector<WrappedSymbol> wrapped = addWrappedSymbols(ctx, args);
// Load more object files that might be needed for wrapped symbols.
if (!wrapped.empty())
while (run());
if (config->autoImport || config->stdcallFixup) {
// MinGW specific.
// Load any further object files that might be needed for doing automatic
// imports, and do stdcall fixups.
//
// For cases with no automatically imported symbols, this iterates once
// over the symbol table and doesn't do anything.
//
// For the normal case with a few automatically imported symbols, this
// should only need to be run once, since each new object file imported
// is an import library and wouldn't add any new undefined references,
// but there's nothing stopping the __imp_ symbols from coming from a
// normal object file as well (although that won't be used for the
// actual autoimport later on). If this pass adds new undefined references,
// we won't iterate further to resolve them.
//
// If stdcall fixups only are needed for loading import entries from
// a DLL without import library, this also just needs running once.
// If it ends up pulling in more object files from static libraries,
// (and maybe doing more stdcall fixups along the way), this would need
// to loop these two calls.
ctx.symtab.loadMinGWSymbols();
run();
}
// At this point, we should not have any symbols that cannot be resolved.
// If we are going to do codegen for link-time optimization, check for
// unresolvable symbols first, so we don't spend time generating code that
// will fail to link anyway.
if (!ctx.bitcodeFileInstances.empty() && !config->forceUnresolved)
ctx.symtab.reportUnresolvable();
if (errorCount())
return;
config->hadExplicitExports = !config->exports.empty();
if (config->mingw) {
// In MinGW, all symbols are automatically exported if no symbols
// are chosen to be exported.
maybeExportMinGWSymbols(args);
}
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files (unless -thinlto-index-only was given, in which case we
// resolve symbols and write indices, but don't generate native code or link).
ctx.symtab.compileBitcodeFiles();
// If -thinlto-index-only is given, we should create only "index
// files" and not object files. Index file creation is already done
// in compileBitcodeFiles, so we are done if that's the case.
if (config->thinLTOIndexOnly)
return;
// If we generated native object files from bitcode files, this resolves
// references to the symbols we use from them.
run();
// Apply symbol renames for -wrap.
if (!wrapped.empty())
wrapSymbols(ctx, wrapped);
// Resolve remaining undefined symbols and warn about imported locals.
ctx.symtab.resolveRemainingUndefines();
if (errorCount())
return;
if (config->mingw) {
// Make sure the crtend.o object is the last object file. This object
// file can contain terminating section chunks that need to be placed
// last. GNU ld processes files and static libraries explicitly in the
// order provided on the command line, while lld will pull in needed
// files from static libraries only after the last object file on the
// command line.
for (auto i = ctx.objFileInstances.begin(), e = ctx.objFileInstances.end();
i != e; i++) {
ObjFile *file = *i;
if (isCrtend(file->getName())) {
ctx.objFileInstances.erase(i);
ctx.objFileInstances.push_back(file);
break;
}
}
}
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file. In MinGW mode, we only do that when the
// -implib option is given explicitly, for compatibility with GNU ld.
if (!config->exports.empty() || config->dll) {
fixupExports();
if (!config->mingw || !config->implib.empty())
createImportLibrary(/*asLib=*/false);
assignExportOrdinals();
}
// Handle /output-def (MinGW specific).
if (auto *arg = args.getLastArg(OPT_output_def))
writeDefFile(arg->getValue());
// Set extra alignment for .comm symbols
for (auto pair : config->alignComm) {
StringRef name = pair.first;
uint32_t alignment = pair.second;
Symbol *sym = ctx.symtab.find(name);
if (!sym) {
warn("/aligncomm symbol " + name + " not found");
continue;
}
// If the symbol isn't common, it must have been replaced with a regular
// symbol, which will carry its own alignment.
auto *dc = dyn_cast<DefinedCommon>(sym);
if (!dc)
continue;
CommonChunk *c = dc->getChunk();
c->setAlignment(std::max(c->getAlignment(), alignment));
}
// Windows specific -- Create an embedded or side-by-side manifest.
// /manifestdependency: enables /manifest unless an explicit /manifest:no is
// also passed.
if (config->manifest == Configuration::Embed)
addBuffer(createManifestRes(), false, false);
else if (config->manifest == Configuration::SideBySide ||
(config->manifest == Configuration::Default &&
!config->manifestDependencies.empty()))
createSideBySideManifest();
// Handle /order. We want to do this at this moment because we
// need a complete list of comdat sections to warn on nonexistent
// functions.
if (auto *arg = args.getLastArg(OPT_order)) {
if (args.hasArg(OPT_call_graph_ordering_file))
error("/order and /call-graph-order-file may not be used together");
parseOrderFile(ctx, arg->getValue());
config->callGraphProfileSort = false;
}
// Handle /call-graph-ordering-file and /call-graph-profile-sort (default on).
if (config->callGraphProfileSort) {
if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) {
parseCallGraphFile(ctx, arg->getValue());
}
readCallGraphsFromObjectFiles(ctx);
}
// Handle /print-symbol-order.
if (auto *arg = args.getLastArg(OPT_print_symbol_order))
config->printSymbolOrder = arg->getValue();
// Identify unreferenced COMDAT sections.
if (config->doGC) {
if (config->mingw) {
// markLive doesn't traverse .eh_frame, but the personality function is
// only reached that way. The proper solution would be to parse and
// traverse the .eh_frame section, like the ELF linker does.
// For now, just manually try to retain the known possible personality
// functions. This doesn't bring in more object files, but only marks
// functions that already have been included to be retained.
for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0"}) {
Defined *d = dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore(n));
if (d && !d->isGCRoot) {
d->isGCRoot = true;
config->gcroot.push_back(d);
}
}
}
markLive(ctx);
}
// Needs to happen after the last call to addFile().
convertResources();
// Identify identical COMDAT sections to merge them.
if (config->doICF != ICFLevel::None) {
findKeepUniqueSections(ctx);
doICF(ctx, config->doICF);
}
// Write the result.
writeResult(ctx);
// Stop early so we can print the results.
rootTimer.stop();
if (config->showTiming)
ctx.rootTimer.print();
}