llvm-project
1028 строк · 34.4 Кб
1//===- DriverUtils.cpp ----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains utility functions for the driver. Because there
10// are so many small functions, we created this separate file to make
11// Driver.cpp less cluttered.
12//
13//===----------------------------------------------------------------------===//
14
15#include "COFFLinkerContext.h"16#include "Driver.h"17#include "Symbols.h"18#include "lld/Common/ErrorHandler.h"19#include "lld/Common/Memory.h"20#include "llvm/ADT/STLExtras.h"21#include "llvm/ADT/StringExtras.h"22#include "llvm/ADT/StringSwitch.h"23#include "llvm/BinaryFormat/COFF.h"24#include "llvm/IR/Mangler.h"25#include "llvm/Object/COFF.h"26#include "llvm/Object/WindowsResource.h"27#include "llvm/Option/Arg.h"28#include "llvm/Option/ArgList.h"29#include "llvm/Option/Option.h"30#include "llvm/Support/CommandLine.h"31#include "llvm/Support/FileUtilities.h"32#include "llvm/Support/MathExtras.h"33#include "llvm/Support/Process.h"34#include "llvm/Support/Program.h"35#include "llvm/Support/TimeProfiler.h"36#include "llvm/Support/raw_ostream.h"37#include "llvm/WindowsManifest/WindowsManifestMerger.h"38#include <limits>39#include <memory>40#include <optional>41
42using namespace llvm::COFF;43using namespace llvm::object;44using namespace llvm::opt;45using namespace llvm;46using llvm::sys::Process;47
48namespace lld {49namespace coff {50namespace {51
52const uint16_t SUBLANG_ENGLISH_US = 0x0409;53const uint16_t RT_MANIFEST = 24;54
55class Executor {56public:57explicit Executor(StringRef s) : prog(saver().save(s)) {}58void add(StringRef s) { args.push_back(saver().save(s)); }59void add(std::string &s) { args.push_back(saver().save(s)); }60void add(Twine s) { args.push_back(saver().save(s)); }61void add(const char *s) { args.push_back(saver().save(s)); }62
63void run() {64ErrorOr<std::string> exeOrErr = sys::findProgramByName(prog);65if (auto ec = exeOrErr.getError())66fatal("unable to find " + prog + " in PATH: " + ec.message());67StringRef exe = saver().save(*exeOrErr);68args.insert(args.begin(), exe);69
70if (sys::ExecuteAndWait(args[0], args) != 0)71fatal("ExecuteAndWait failed: " +72llvm::join(args.begin(), args.end(), " "));73}74
75private:76StringRef prog;77std::vector<StringRef> args;78};79
80} // anonymous namespace81
82// Parses a string in the form of "<integer>[,<integer>]".
83void LinkerDriver::parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {84auto [s1, s2] = arg.split(',');85if (s1.getAsInteger(0, *addr))86fatal("invalid number: " + s1);87if (size && !s2.empty() && s2.getAsInteger(0, *size))88fatal("invalid number: " + s2);89}
90
91// Parses a string in the form of "<integer>[.<integer>]".
92// If second number is not present, Minor is set to 0.
93void LinkerDriver::parseVersion(StringRef arg, uint32_t *major,94uint32_t *minor) {95auto [s1, s2] = arg.split('.');96if (s1.getAsInteger(10, *major))97fatal("invalid number: " + s1);98*minor = 0;99if (!s2.empty() && s2.getAsInteger(10, *minor))100fatal("invalid number: " + s2);101}
102
103void LinkerDriver::parseGuard(StringRef fullArg) {104SmallVector<StringRef, 1> splitArgs;105fullArg.split(splitArgs, ",");106for (StringRef arg : splitArgs) {107if (arg.equals_insensitive("no"))108ctx.config.guardCF = GuardCFLevel::Off;109else if (arg.equals_insensitive("nolongjmp"))110ctx.config.guardCF &= ~GuardCFLevel::LongJmp;111else if (arg.equals_insensitive("noehcont"))112ctx.config.guardCF &= ~GuardCFLevel::EHCont;113else if (arg.equals_insensitive("cf") || arg.equals_insensitive("longjmp"))114ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::LongJmp;115else if (arg.equals_insensitive("ehcont"))116ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::EHCont;117else118fatal("invalid argument to /guard: " + arg);119}120}
121
122// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
123void LinkerDriver::parseSubsystem(StringRef arg, WindowsSubsystem *sys,124uint32_t *major, uint32_t *minor,125bool *gotVersion) {126auto [sysStr, ver] = arg.split(',');127std::string sysStrLower = sysStr.lower();128*sys = StringSwitch<WindowsSubsystem>(sysStrLower)129.Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)130.Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)131.Case("default", IMAGE_SUBSYSTEM_UNKNOWN)132.Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)133.Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)134.Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)135.Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)136.Case("native", IMAGE_SUBSYSTEM_NATIVE)137.Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)138.Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)139.Default(IMAGE_SUBSYSTEM_UNKNOWN);140if (*sys == IMAGE_SUBSYSTEM_UNKNOWN && sysStrLower != "default")141fatal("unknown subsystem: " + sysStr);142if (!ver.empty())143parseVersion(ver, major, minor);144if (gotVersion)145*gotVersion = !ver.empty();146}
147
148// Parse a string of the form of "<from>=<to>".
149// Results are directly written to Config.
150void LinkerDriver::parseAlternateName(StringRef s) {151auto [from, to] = s.split('=');152if (from.empty() || to.empty())153fatal("/alternatename: invalid argument: " + s);154auto it = ctx.config.alternateNames.find(from);155if (it != ctx.config.alternateNames.end() && it->second != to)156fatal("/alternatename: conflicts: " + s);157ctx.config.alternateNames.insert(it, std::make_pair(from, to));158}
159
160// Parse a string of the form of "<from>=<to>".
161// Results are directly written to Config.
162void LinkerDriver::parseMerge(StringRef s) {163auto [from, to] = s.split('=');164if (from.empty() || to.empty())165fatal("/merge: invalid argument: " + s);166if (from == ".rsrc" || to == ".rsrc")167fatal("/merge: cannot merge '.rsrc' with any section");168if (from == ".reloc" || to == ".reloc")169fatal("/merge: cannot merge '.reloc' with any section");170auto pair = ctx.config.merge.insert(std::make_pair(from, to));171bool inserted = pair.second;172if (!inserted) {173StringRef existing = pair.first->second;174if (existing != to)175warn(s + ": already merged into " + existing);176}177}
178
179void LinkerDriver::parsePDBPageSize(StringRef s) {180int v;181if (s.getAsInteger(0, v)) {182error("/pdbpagesize: invalid argument: " + s);183return;184}185if (v != 4096 && v != 8192 && v != 16384 && v != 32768) {186error("/pdbpagesize: invalid argument: " + s);187return;188}189
190ctx.config.pdbPageSize = v;191}
192
193static uint32_t parseSectionAttributes(StringRef s) {194uint32_t ret = 0;195for (char c : s.lower()) {196switch (c) {197case 'd':198ret |= IMAGE_SCN_MEM_DISCARDABLE;199break;200case 'e':201ret |= IMAGE_SCN_MEM_EXECUTE;202break;203case 'k':204ret |= IMAGE_SCN_MEM_NOT_CACHED;205break;206case 'p':207ret |= IMAGE_SCN_MEM_NOT_PAGED;208break;209case 'r':210ret |= IMAGE_SCN_MEM_READ;211break;212case 's':213ret |= IMAGE_SCN_MEM_SHARED;214break;215case 'w':216ret |= IMAGE_SCN_MEM_WRITE;217break;218default:219fatal("/section: invalid argument: " + s);220}221}222return ret;223}
224
225// Parses /section option argument.
226void LinkerDriver::parseSection(StringRef s) {227auto [name, attrs] = s.split(',');228if (name.empty() || attrs.empty())229fatal("/section: invalid argument: " + s);230ctx.config.section[name] = parseSectionAttributes(attrs);231}
232
233// Parses /aligncomm option argument.
234void LinkerDriver::parseAligncomm(StringRef s) {235auto [name, align] = s.split(',');236if (name.empty() || align.empty()) {237error("/aligncomm: invalid argument: " + s);238return;239}240int v;241if (align.getAsInteger(0, v)) {242error("/aligncomm: invalid argument: " + s);243return;244}245ctx.config.alignComm[std::string(name)] =246std::max(ctx.config.alignComm[std::string(name)], 1 << v);247}
248
249// Parses /functionpadmin option argument.
250void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {251StringRef arg = a->getNumValues() ? a->getValue() : "";252if (!arg.empty()) {253// Optional padding in bytes is given.254if (arg.getAsInteger(0, ctx.config.functionPadMin))255error("/functionpadmin: invalid argument: " + arg);256return;257}258// No optional argument given.259// Set default padding based on machine, similar to link.exe.260// There is no default padding for ARM platforms.261if (ctx.config.machine == I386) {262ctx.config.functionPadMin = 5;263} else if (ctx.config.machine == AMD64) {264ctx.config.functionPadMin = 6;265} else {266error("/functionpadmin: invalid argument for this machine: " + arg);267}268}
269
270// Parses /dependentloadflag option argument.
271void LinkerDriver::parseDependentLoadFlags(llvm::opt::Arg *a) {272StringRef arg = a->getNumValues() ? a->getValue() : "";273if (!arg.empty()) {274if (arg.getAsInteger(0, ctx.config.dependentLoadFlags))275error("/dependentloadflag: invalid argument: " + arg);276return;277}278// MSVC linker reports error "no argument specified", although MSDN describes279// argument as optional.280error("/dependentloadflag: no argument specified");281}
282
283// Parses a string in the form of "EMBED[,=<integer>]|NO".
284// Results are directly written to
285// Config.
286void LinkerDriver::parseManifest(StringRef arg) {287if (arg.equals_insensitive("no")) {288ctx.config.manifest = Configuration::No;289return;290}291if (!arg.starts_with_insensitive("embed"))292fatal("invalid option " + arg);293ctx.config.manifest = Configuration::Embed;294arg = arg.substr(strlen("embed"));295if (arg.empty())296return;297if (!arg.starts_with_insensitive(",id="))298fatal("invalid option " + arg);299arg = arg.substr(strlen(",id="));300if (arg.getAsInteger(0, ctx.config.manifestID))301fatal("invalid option " + arg);302}
303
304// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
305// Results are directly written to Config.
306void LinkerDriver::parseManifestUAC(StringRef arg) {307if (arg.equals_insensitive("no")) {308ctx.config.manifestUAC = false;309return;310}311for (;;) {312arg = arg.ltrim();313if (arg.empty())314return;315if (arg.consume_front_insensitive("level=")) {316std::tie(ctx.config.manifestLevel, arg) = arg.split(" ");317continue;318}319if (arg.consume_front_insensitive("uiaccess=")) {320std::tie(ctx.config.manifestUIAccess, arg) = arg.split(" ");321continue;322}323fatal("invalid option " + arg);324}325}
326
327// Parses a string in the form of "cd|net[,(cd|net)]*"
328// Results are directly written to Config.
329void LinkerDriver::parseSwaprun(StringRef arg) {330do {331auto [swaprun, newArg] = arg.split(',');332if (swaprun.equals_insensitive("cd"))333ctx.config.swaprunCD = true;334else if (swaprun.equals_insensitive("net"))335ctx.config.swaprunNet = true;336else if (swaprun.empty())337error("/swaprun: missing argument");338else339error("/swaprun: invalid argument: " + swaprun);340// To catch trailing commas, e.g. `/spawrun:cd,`341if (newArg.empty() && arg.ends_with(","))342error("/swaprun: missing argument");343arg = newArg;344} while (!arg.empty());345}
346
347// An RAII temporary file class that automatically removes a temporary file.
348namespace {349class TemporaryFile {350public:351TemporaryFile(StringRef prefix, StringRef extn, StringRef contents = "") {352SmallString<128> s;353if (auto ec = sys::fs::createTemporaryFile("lld-" + prefix, extn, s))354fatal("cannot create a temporary file: " + ec.message());355path = std::string(s);356
357if (!contents.empty()) {358std::error_code ec;359raw_fd_ostream os(path, ec, sys::fs::OF_None);360if (ec)361fatal("failed to open " + path + ": " + ec.message());362os << contents;363}364}365
366TemporaryFile(TemporaryFile &&obj) noexcept { std::swap(path, obj.path); }367
368~TemporaryFile() {369if (path.empty())370return;371if (sys::fs::remove(path))372fatal("failed to remove " + path);373}374
375// Returns a memory buffer of this temporary file.376// Note that this function does not leave the file open,377// so it is safe to remove the file immediately after this function378// is called (you cannot remove an opened file on Windows.)379std::unique_ptr<MemoryBuffer> getMemoryBuffer() {380// IsVolatile=true forces MemoryBuffer to not use mmap().381return CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,382/*RequiresNullTerminator=*/false,383/*IsVolatile=*/true),384"could not open " + path);385}386
387std::string path;388};389}
390
391std::string LinkerDriver::createDefaultXml() {392std::string ret;393raw_string_ostream os(ret);394
395// Emit the XML. Note that we do *not* verify that the XML attributes are396// syntactically correct. This is intentional for link.exe compatibility.397os << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"398<< "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"399<< " manifestVersion=\"1.0\">\n";400if (ctx.config.manifestUAC) {401os << " <trustInfo>\n"402<< " <security>\n"403<< " <requestedPrivileges>\n"404<< " <requestedExecutionLevel level=" << ctx.config.manifestLevel405<< " uiAccess=" << ctx.config.manifestUIAccess << "/>\n"406<< " </requestedPrivileges>\n"407<< " </security>\n"408<< " </trustInfo>\n";409}410for (auto manifestDependency : ctx.config.manifestDependencies) {411os << " <dependency>\n"412<< " <dependentAssembly>\n"413<< " <assemblyIdentity " << manifestDependency << " />\n"414<< " </dependentAssembly>\n"415<< " </dependency>\n";416}417os << "</assembly>\n";418return os.str();419}
420
421std::string422LinkerDriver::createManifestXmlWithInternalMt(StringRef defaultXml) {423std::unique_ptr<MemoryBuffer> defaultXmlCopy =424MemoryBuffer::getMemBufferCopy(defaultXml);425
426windows_manifest::WindowsManifestMerger merger;427if (auto e = merger.merge(*defaultXmlCopy.get()))428fatal("internal manifest tool failed on default xml: " +429toString(std::move(e)));430
431for (StringRef filename : ctx.config.manifestInput) {432std::unique_ptr<MemoryBuffer> manifest =433check(MemoryBuffer::getFile(filename));434// Call takeBuffer to include in /reproduce: output if applicable.435if (auto e = merger.merge(takeBuffer(std::move(manifest))))436fatal("internal manifest tool failed on file " + filename + ": " +437toString(std::move(e)));438}439
440return std::string(merger.getMergedManifest().get()->getBuffer());441}
442
443std::string444LinkerDriver::createManifestXmlWithExternalMt(StringRef defaultXml) {445// Create the default manifest file as a temporary file.446TemporaryFile Default("defaultxml", "manifest");447std::error_code ec;448raw_fd_ostream os(Default.path, ec, sys::fs::OF_TextWithCRLF);449if (ec)450fatal("failed to open " + Default.path + ": " + ec.message());451os << defaultXml;452os.close();453
454// Merge user-supplied manifests if they are given. Since libxml2 is not455// enabled, we must shell out to Microsoft's mt.exe tool.456TemporaryFile user("user", "manifest");457
458Executor e("mt.exe");459e.add("/manifest");460e.add(Default.path);461for (StringRef filename : ctx.config.manifestInput) {462e.add("/manifest");463e.add(filename);464
465// Manually add the file to the /reproduce: tar if needed.466if (tar)467if (auto mbOrErr = MemoryBuffer::getFile(filename))468takeBuffer(std::move(*mbOrErr));469}470e.add("/nologo");471e.add("/out:" + StringRef(user.path));472e.run();473
474return std::string(475CHECK(MemoryBuffer::getFile(user.path), "could not open " + user.path)476.get()477->getBuffer());478}
479
480std::string LinkerDriver::createManifestXml() {481std::string defaultXml = createDefaultXml();482if (ctx.config.manifestInput.empty())483return defaultXml;484
485if (windows_manifest::isAvailable())486return createManifestXmlWithInternalMt(defaultXml);487
488return createManifestXmlWithExternalMt(defaultXml);489}
490
491std::unique_ptr<WritableMemoryBuffer>492LinkerDriver::createMemoryBufferForManifestRes(size_t manifestSize) {493size_t resSize = alignTo(494object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +495sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +496sizeof(object::WinResHeaderSuffix) + manifestSize,497object::WIN_RES_DATA_ALIGNMENT);498return WritableMemoryBuffer::getNewMemBuffer(resSize, ctx.config.outputFile +499".manifest.res");500}
501
502static void writeResFileHeader(char *&buf) {503memcpy(buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));504buf += sizeof(COFF::WinResMagic);505memset(buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);506buf += object::WIN_RES_NULL_ENTRY_SIZE;507}
508
509static void writeResEntryHeader(char *&buf, size_t manifestSize,510int manifestID) {511// Write the prefix.512auto *prefix = reinterpret_cast<object::WinResHeaderPrefix *>(buf);513prefix->DataSize = manifestSize;514prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +515sizeof(object::WinResIDs) +516sizeof(object::WinResHeaderSuffix);517buf += sizeof(object::WinResHeaderPrefix);518
519// Write the Type/Name IDs.520auto *iDs = reinterpret_cast<object::WinResIDs *>(buf);521iDs->setType(RT_MANIFEST);522iDs->setName(manifestID);523buf += sizeof(object::WinResIDs);524
525// Write the suffix.526auto *suffix = reinterpret_cast<object::WinResHeaderSuffix *>(buf);527suffix->DataVersion = 0;528suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;529suffix->Language = SUBLANG_ENGLISH_US;530suffix->Version = 0;531suffix->Characteristics = 0;532buf += sizeof(object::WinResHeaderSuffix);533}
534
535// Create a resource file containing a manifest XML.
536std::unique_ptr<MemoryBuffer> LinkerDriver::createManifestRes() {537std::string manifest = createManifestXml();538
539std::unique_ptr<WritableMemoryBuffer> res =540createMemoryBufferForManifestRes(manifest.size());541
542char *buf = res->getBufferStart();543writeResFileHeader(buf);544writeResEntryHeader(buf, manifest.size(), ctx.config.manifestID);545
546// Copy the manifest data into the .res file.547std::copy(manifest.begin(), manifest.end(), buf);548return std::move(res);549}
550
551void LinkerDriver::createSideBySideManifest() {552std::string path = std::string(ctx.config.manifestFile);553if (path == "")554path = ctx.config.outputFile + ".manifest";555std::error_code ec;556raw_fd_ostream out(path, ec, sys::fs::OF_TextWithCRLF);557if (ec)558fatal("failed to create manifest: " + ec.message());559out << createManifestXml();560}
561
562// Parse a string in the form of
563// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
564// or "<name>=<dllname>.<name>".
565// Used for parsing /export arguments.
566Export LinkerDriver::parseExport(StringRef arg) {567Export e;568e.source = ExportSource::Export;569
570StringRef rest;571std::tie(e.name, rest) = arg.split(",");572if (e.name.empty())573goto err;574
575if (e.name.contains('=')) {576auto [x, y] = e.name.split("=");577
578// If "<name>=<dllname>.<name>".579if (y.contains(".")) {580e.name = x;581e.forwardTo = y;582} else {583e.extName = x;584e.name = y;585if (e.name.empty())586goto err;587}588}589
590// Optional parameters591// "[,@ordinal[,NONAME]][,DATA][,PRIVATE][,EXPORTAS,exportname]"592while (!rest.empty()) {593StringRef tok;594std::tie(tok, rest) = rest.split(",");595if (tok.equals_insensitive("noname")) {596if (e.ordinal == 0)597goto err;598e.noname = true;599continue;600}601if (tok.equals_insensitive("data")) {602e.data = true;603continue;604}605if (tok.equals_insensitive("constant")) {606e.constant = true;607continue;608}609if (tok.equals_insensitive("private")) {610e.isPrivate = true;611continue;612}613if (tok.equals_insensitive("exportas")) {614if (!rest.empty() && !rest.contains(','))615e.exportAs = rest;616else617error("invalid EXPORTAS value: " + rest);618break;619}620if (tok.starts_with("@")) {621int32_t ord;622if (tok.substr(1).getAsInteger(0, ord))623goto err;624if (ord <= 0 || 65535 < ord)625goto err;626e.ordinal = ord;627continue;628}629goto err;630}631return e;632
633err:634fatal("invalid /export: " + arg);635}
636
637// Convert stdcall/fastcall style symbols into unsuffixed symbols,
638// with or without a leading underscore. (MinGW specific.)
639static StringRef killAt(StringRef sym, bool prefix) {640if (sym.empty())641return sym;642// Strip any trailing stdcall suffix643sym = sym.substr(0, sym.find('@', 1));644if (!sym.starts_with("@")) {645if (prefix && !sym.starts_with("_"))646return saver().save("_" + sym);647return sym;648}649// For fastcall, remove the leading @ and replace it with an650// underscore, if prefixes are used.651sym = sym.substr(1);652if (prefix)653sym = saver().save("_" + sym);654return sym;655}
656
657static StringRef exportSourceName(ExportSource s) {658switch (s) {659case ExportSource::Directives:660return "source file (directives)";661case ExportSource::Export:662return "/export";663case ExportSource::ModuleDefinition:664return "/def";665default:666llvm_unreachable("unknown ExportSource");667}668}
669
670// Performs error checking on all /export arguments.
671// It also sets ordinals.
672void LinkerDriver::fixupExports() {673llvm::TimeTraceScope timeScope("Fixup exports");674// Symbol ordinals must be unique.675std::set<uint16_t> ords;676for (Export &e : ctx.config.exports) {677if (e.ordinal == 0)678continue;679if (!ords.insert(e.ordinal).second)680fatal("duplicate export ordinal: " + e.name);681}682
683for (Export &e : ctx.config.exports) {684if (!e.exportAs.empty()) {685e.exportName = e.exportAs;686continue;687}688
689StringRef sym =690!e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName;691if (ctx.config.machine == I386 && sym.starts_with("_")) {692// In MSVC mode, a fully decorated stdcall function is exported693// as-is with the leading underscore (with type IMPORT_NAME).694// In MinGW mode, a decorated stdcall function gets the underscore695// removed, just like normal cdecl functions.696if (ctx.config.mingw || !sym.contains('@')) {697e.exportName = sym.substr(1);698continue;699}700}701if (isArm64EC(ctx.config.machine) && !e.data && !e.constant) {702if (std::optional<std::string> demangledName =703getArm64ECDemangledFunctionName(sym)) {704e.exportName = saver().save(*demangledName);705continue;706}707}708e.exportName = sym;709}710
711if (ctx.config.killAt && ctx.config.machine == I386) {712for (Export &e : ctx.config.exports) {713e.name = killAt(e.name, true);714e.exportName = killAt(e.exportName, false);715e.extName = killAt(e.extName, true);716e.symbolName = killAt(e.symbolName, true);717}718}719
720// Uniquefy by name.721DenseMap<StringRef, std::pair<Export *, unsigned>> map(722ctx.config.exports.size());723std::vector<Export> v;724for (Export &e : ctx.config.exports) {725auto pair = map.insert(std::make_pair(e.exportName, std::make_pair(&e, 0)));726bool inserted = pair.second;727if (inserted) {728pair.first->second.second = v.size();729v.push_back(e);730continue;731}732Export *existing = pair.first->second.first;733if (e == *existing || e.name != existing->name)734continue;735// If the existing export comes from .OBJ directives, we are allowed to736// overwrite it with /DEF: or /EXPORT without any warning, as MSVC link.exe737// does.738if (existing->source == ExportSource::Directives) {739*existing = e;740v[pair.first->second.second] = e;741continue;742}743if (existing->source == e.source) {744warn(Twine("duplicate ") + exportSourceName(existing->source) +745" option: " + e.name);746} else {747warn("duplicate export: " + e.name +748Twine(" first seen in " + exportSourceName(existing->source) +749Twine(", now in " + exportSourceName(e.source))));750}751}752ctx.config.exports = std::move(v);753
754// Sort by name.755llvm::sort(ctx.config.exports, [](const Export &a, const Export &b) {756return a.exportName < b.exportName;757});758}
759
760void LinkerDriver::assignExportOrdinals() {761// Assign unique ordinals if default (= 0).762uint32_t max = 0;763for (Export &e : ctx.config.exports)764max = std::max(max, (uint32_t)e.ordinal);765for (Export &e : ctx.config.exports)766if (e.ordinal == 0)767e.ordinal = ++max;768if (max > std::numeric_limits<uint16_t>::max())769fatal("too many exported symbols (got " + Twine(max) + ", max " +770Twine(std::numeric_limits<uint16_t>::max()) + ")");771}
772
773// Parses a string in the form of "key=value" and check
774// if value matches previous values for the same key.
775void LinkerDriver::checkFailIfMismatch(StringRef arg, InputFile *source) {776auto [k, v] = arg.split('=');777if (k.empty() || v.empty())778fatal("/failifmismatch: invalid argument: " + arg);779std::pair<StringRef, InputFile *> existing = ctx.config.mustMatch[k];780if (!existing.first.empty() && v != existing.first) {781std::string sourceStr = source ? toString(source) : "cmd-line";782std::string existingStr =783existing.second ? toString(existing.second) : "cmd-line";784fatal("/failifmismatch: mismatch detected for '" + k + "':\n>>> " +785existingStr + " has value " + existing.first + "\n>>> " + sourceStr +786" has value " + v);787}788ctx.config.mustMatch[k] = {v, source};789}
790
791// Convert Windows resource files (.res files) to a .obj file.
792// Does what cvtres.exe does, but in-process and cross-platform.
793MemoryBufferRef LinkerDriver::convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,794ArrayRef<ObjFile *> objs) {795object::WindowsResourceParser parser(/* MinGW */ ctx.config.mingw);796
797std::vector<std::string> duplicates;798for (MemoryBufferRef mb : mbs) {799std::unique_ptr<object::Binary> bin = check(object::createBinary(mb));800object::WindowsResource *rf = dyn_cast<object::WindowsResource>(bin.get());801if (!rf)802fatal("cannot compile non-resource file as resource");803
804if (auto ec = parser.parse(rf, duplicates))805fatal(toString(std::move(ec)));806}807
808// Note: This processes all .res files before all objs. Ideally they'd be809// handled in the same order they were linked (to keep the right one, if810// there are duplicates that are tolerated due to forceMultipleRes).811for (ObjFile *f : objs) {812object::ResourceSectionRef rsf;813if (auto ec = rsf.load(f->getCOFFObj()))814fatal(toString(f) + ": " + toString(std::move(ec)));815
816if (auto ec = parser.parse(rsf, f->getName(), duplicates))817fatal(toString(std::move(ec)));818}819
820if (ctx.config.mingw)821parser.cleanUpManifests(duplicates);822
823for (const auto &dupeDiag : duplicates)824if (ctx.config.forceMultipleRes)825warn(dupeDiag);826else827error(dupeDiag);828
829Expected<std::unique_ptr<MemoryBuffer>> e =830llvm::object::writeWindowsResourceCOFF(ctx.config.machine, parser,831ctx.config.timestamp);832if (!e)833fatal("failed to write .res to COFF: " + toString(e.takeError()));834
835MemoryBufferRef mbref = **e;836make<std::unique_ptr<MemoryBuffer>>(std::move(*e)); // take ownership837return mbref;838}
839
840// Create OptTable
841
842// Create prefix string literals used in Options.td
843#define PREFIX(NAME, VALUE) \844static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \845static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \846NAME##_init, std::size(NAME##_init) - 1);847#include "Options.inc"848#undef PREFIX849
850// Create table mapping all options defined in Options.td
851static constexpr llvm::opt::OptTable::Info infoTable[] = {852#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),853#include "Options.inc"854#undef OPTION855};856
857COFFOptTable::COFFOptTable() : GenericOptTable(infoTable, true) {}858
859// Set color diagnostics according to --color-diagnostics={auto,always,never}
860// or --no-color-diagnostics flags.
861static void handleColorDiagnostics(opt::InputArgList &args) {862auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,863OPT_no_color_diagnostics);864if (!arg)865return;866if (arg->getOption().getID() == OPT_color_diagnostics) {867lld::errs().enable_colors(true);868} else if (arg->getOption().getID() == OPT_no_color_diagnostics) {869lld::errs().enable_colors(false);870} else {871StringRef s = arg->getValue();872if (s == "always")873lld::errs().enable_colors(true);874else if (s == "never")875lld::errs().enable_colors(false);876else if (s != "auto")877error("unknown option: --color-diagnostics=" + s);878}879}
880
881static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {882if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {883StringRef s = arg->getValue();884if (s != "windows" && s != "posix")885error("invalid response file quoting: " + s);886if (s == "windows")887return cl::TokenizeWindowsCommandLine;888return cl::TokenizeGNUCommandLine;889}890// The COFF linker always defaults to Windows quoting.891return cl::TokenizeWindowsCommandLine;892}
893
894ArgParser::ArgParser(COFFLinkerContext &c) : ctx(c) {}895
896// Parses a given list of options.
897opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {898// Make InputArgList from string vectors.899unsigned missingIndex;900unsigned missingCount;901
902// We need to get the quoting style for response files before parsing all903// options so we parse here before and ignore all the options but904// --rsp-quoting and /lldignoreenv.905// (This means --rsp-quoting can't be added through %LINK%.)906opt::InputArgList args =907ctx.optTable.ParseArgs(argv, missingIndex, missingCount);908
909// Expand response files (arguments in the form of @<filename>) and insert910// flags from %LINK% and %_LINK_%, and then parse the argument again.911SmallVector<const char *, 256> expandedArgv(argv.data(),912argv.data() + argv.size());913if (!args.hasArg(OPT_lldignoreenv))914addLINK(expandedArgv);915cl::ExpandResponseFiles(saver(), getQuotingStyle(args), expandedArgv);916args = ctx.optTable.ParseArgs(ArrayRef(expandedArgv).drop_front(),917missingIndex, missingCount);918
919// Print the real command line if response files are expanded.920if (args.hasArg(OPT_verbose) && argv.size() != expandedArgv.size()) {921std::string msg = "Command line:";922for (const char *s : expandedArgv)923msg += " " + std::string(s);924message(msg);925}926
927// Save the command line after response file expansion so we can write it to928// the PDB if necessary. Mimic MSVC, which skips input files.929ctx.config.argv = {argv[0]};930for (opt::Arg *arg : args) {931if (arg->getOption().getKind() != opt::Option::InputClass) {932ctx.config.argv.emplace_back(args.getArgString(arg->getIndex()));933}934}935
936// Handle /WX early since it converts missing argument warnings to errors.937errorHandler().fatalWarnings = args.hasFlag(OPT_WX, OPT_WX_no, false);938
939if (missingCount)940fatal(Twine(args.getArgString(missingIndex)) + ": missing argument");941
942handleColorDiagnostics(args);943
944for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {945std::string nearest;946if (ctx.optTable.findNearest(arg->getAsString(args), nearest) > 1)947warn("ignoring unknown argument '" + arg->getAsString(args) + "'");948else949warn("ignoring unknown argument '" + arg->getAsString(args) +950"', did you mean '" + nearest + "'");951}952
953if (args.hasArg(OPT_lib))954warn("ignoring /lib since it's not the first argument");955
956return args;957}
958
959// Tokenizes and parses a given string as command line in .drective section.
960ParsedDirectives ArgParser::parseDirectives(StringRef s) {961ParsedDirectives result;962SmallVector<const char *, 16> rest;963
964// Handle /EXPORT and /INCLUDE in a fast path. These directives can appear for965// potentially every symbol in the object, so they must be handled quickly.966SmallVector<StringRef, 16> tokens;967cl::TokenizeWindowsCommandLineNoCopy(s, saver(), tokens);968for (StringRef tok : tokens) {969if (tok.starts_with_insensitive("/export:") ||970tok.starts_with_insensitive("-export:"))971result.exports.push_back(tok.substr(strlen("/export:")));972else if (tok.starts_with_insensitive("/include:") ||973tok.starts_with_insensitive("-include:"))974result.includes.push_back(tok.substr(strlen("/include:")));975else if (tok.starts_with_insensitive("/exclude-symbols:") ||976tok.starts_with_insensitive("-exclude-symbols:"))977result.excludes.push_back(tok.substr(strlen("/exclude-symbols:")));978else {979// Copy substrings that are not valid C strings. The tokenizer may have980// already copied quoted arguments for us, so those do not need to be981// copied again.982bool HasNul = tok.end() != s.end() && tok.data()[tok.size()] == '\0';983rest.push_back(HasNul ? tok.data() : saver().save(tok).data());984}985}986
987// Make InputArgList from unparsed string vectors.988unsigned missingIndex;989unsigned missingCount;990
991result.args = ctx.optTable.ParseArgs(rest, missingIndex, missingCount);992
993if (missingCount)994fatal(Twine(result.args.getArgString(missingIndex)) + ": missing argument");995for (auto *arg : result.args.filtered(OPT_UNKNOWN))996warn("ignoring unknown argument: " + arg->getAsString(result.args));997return result;998}
999
1000// link.exe has an interesting feature. If LINK or _LINK_ environment
1001// variables exist, their contents are handled as command line strings.
1002// So you can pass extra arguments using them.
1003void ArgParser::addLINK(SmallVector<const char *, 256> &argv) {1004// Concatenate LINK env and command line arguments, and then parse them.1005if (std::optional<std::string> s = Process::GetEnv("LINK")) {1006std::vector<const char *> v = tokenize(*s);1007argv.insert(std::next(argv.begin()), v.begin(), v.end());1008}1009if (std::optional<std::string> s = Process::GetEnv("_LINK_")) {1010std::vector<const char *> v = tokenize(*s);1011argv.insert(std::next(argv.begin()), v.begin(), v.end());1012}1013}
1014
1015std::vector<const char *> ArgParser::tokenize(StringRef s) {1016SmallVector<const char *, 16> tokens;1017cl::TokenizeWindowsCommandLine(s, saver(), tokens);1018return std::vector<const char *>(tokens.begin(), tokens.end());1019}
1020
1021void LinkerDriver::printHelp(const char *argv0) {1022ctx.optTable.printHelp(lld::outs(),1023(std::string(argv0) + " [options] file...").c_str(),1024"LLVM Linker", false);1025}
1026
1027} // namespace coff1028} // namespace lld1029