xref: /freebsd/contrib/llvm-project/lld/COFF/DriverUtils.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- DriverUtils.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains utility functions for the driver. Because there
100b57cec5SDimitry Andric // are so many small functions, we created this separate file to make
110b57cec5SDimitry Andric // Driver.cpp less cluttered.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
15bdd1243dSDimitry Andric #include "COFFLinkerContext.h"
160b57cec5SDimitry Andric #include "Driver.h"
170b57cec5SDimitry Andric #include "Symbols.h"
180b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
190b57cec5SDimitry Andric #include "lld/Common/Memory.h"
20fcaf7f86SDimitry Andric #include "llvm/ADT/STLExtras.h"
2106c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
220b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
230b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
24*0fca6ea1SDimitry Andric #include "llvm/IR/Mangler.h"
250b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
260b57cec5SDimitry Andric #include "llvm/Object/WindowsResource.h"
270b57cec5SDimitry Andric #include "llvm/Option/Arg.h"
280b57cec5SDimitry Andric #include "llvm/Option/ArgList.h"
290b57cec5SDimitry Andric #include "llvm/Option/Option.h"
300b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
310b57cec5SDimitry Andric #include "llvm/Support/FileUtilities.h"
320b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
330b57cec5SDimitry Andric #include "llvm/Support/Process.h"
340b57cec5SDimitry Andric #include "llvm/Support/Program.h"
355f757f3fSDimitry Andric #include "llvm/Support/TimeProfiler.h"
360b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
370b57cec5SDimitry Andric #include "llvm/WindowsManifest/WindowsManifestMerger.h"
38e8d8bef9SDimitry Andric #include <limits>
390b57cec5SDimitry Andric #include <memory>
40bdd1243dSDimitry Andric #include <optional>
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric using namespace llvm::COFF;
43*0fca6ea1SDimitry Andric using namespace llvm::object;
445f757f3fSDimitry Andric using namespace llvm::opt;
450b57cec5SDimitry Andric using namespace llvm;
460b57cec5SDimitry Andric using llvm::sys::Process;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric namespace lld {
490b57cec5SDimitry Andric namespace coff {
500b57cec5SDimitry Andric namespace {
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric const uint16_t SUBLANG_ENGLISH_US = 0x0409;
530b57cec5SDimitry Andric const uint16_t RT_MANIFEST = 24;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric class Executor {
560b57cec5SDimitry Andric public:
Executor(StringRef s)5704eeddc0SDimitry Andric   explicit Executor(StringRef s) : prog(saver().save(s)) {}
add(StringRef s)5804eeddc0SDimitry Andric   void add(StringRef s) { args.push_back(saver().save(s)); }
add(std::string & s)5904eeddc0SDimitry Andric   void add(std::string &s) { args.push_back(saver().save(s)); }
add(Twine s)6004eeddc0SDimitry Andric   void add(Twine s) { args.push_back(saver().save(s)); }
add(const char * s)6104eeddc0SDimitry Andric   void add(const char *s) { args.push_back(saver().save(s)); }
620b57cec5SDimitry Andric 
run()630b57cec5SDimitry Andric   void run() {
640b57cec5SDimitry Andric     ErrorOr<std::string> exeOrErr = sys::findProgramByName(prog);
650b57cec5SDimitry Andric     if (auto ec = exeOrErr.getError())
660b57cec5SDimitry Andric       fatal("unable to find " + prog + " in PATH: " + ec.message());
6704eeddc0SDimitry Andric     StringRef exe = saver().save(*exeOrErr);
680b57cec5SDimitry Andric     args.insert(args.begin(), exe);
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric     if (sys::ExecuteAndWait(args[0], args) != 0)
710b57cec5SDimitry Andric       fatal("ExecuteAndWait failed: " +
720b57cec5SDimitry Andric             llvm::join(args.begin(), args.end(), " "));
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric private:
760b57cec5SDimitry Andric   StringRef prog;
770b57cec5SDimitry Andric   std::vector<StringRef> args;
780b57cec5SDimitry Andric };
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric } // anonymous namespace
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric // Parses a string in the form of "<integer>[,<integer>]".
parseNumbers(StringRef arg,uint64_t * addr,uint64_t * size)83bdd1243dSDimitry Andric void LinkerDriver::parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {
84bdd1243dSDimitry Andric   auto [s1, s2] = arg.split(',');
850b57cec5SDimitry Andric   if (s1.getAsInteger(0, *addr))
860b57cec5SDimitry Andric     fatal("invalid number: " + s1);
870b57cec5SDimitry Andric   if (size && !s2.empty() && s2.getAsInteger(0, *size))
880b57cec5SDimitry Andric     fatal("invalid number: " + s2);
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric // Parses a string in the form of "<integer>[.<integer>]".
920b57cec5SDimitry Andric // If second number is not present, Minor is set to 0.
parseVersion(StringRef arg,uint32_t * major,uint32_t * minor)93bdd1243dSDimitry Andric void LinkerDriver::parseVersion(StringRef arg, uint32_t *major,
94bdd1243dSDimitry Andric                                 uint32_t *minor) {
95bdd1243dSDimitry Andric   auto [s1, s2] = arg.split('.');
96e8d8bef9SDimitry Andric   if (s1.getAsInteger(10, *major))
970b57cec5SDimitry Andric     fatal("invalid number: " + s1);
980b57cec5SDimitry Andric   *minor = 0;
99e8d8bef9SDimitry Andric   if (!s2.empty() && s2.getAsInteger(10, *minor))
1000b57cec5SDimitry Andric     fatal("invalid number: " + s2);
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
parseGuard(StringRef fullArg)103bdd1243dSDimitry Andric void LinkerDriver::parseGuard(StringRef fullArg) {
1040b57cec5SDimitry Andric   SmallVector<StringRef, 1> splitArgs;
1050b57cec5SDimitry Andric   fullArg.split(splitArgs, ",");
1060b57cec5SDimitry Andric   for (StringRef arg : splitArgs) {
107fe6060f1SDimitry Andric     if (arg.equals_insensitive("no"))
108bdd1243dSDimitry Andric       ctx.config.guardCF = GuardCFLevel::Off;
109fe6060f1SDimitry Andric     else if (arg.equals_insensitive("nolongjmp"))
110bdd1243dSDimitry Andric       ctx.config.guardCF &= ~GuardCFLevel::LongJmp;
111fe6060f1SDimitry Andric     else if (arg.equals_insensitive("noehcont"))
112bdd1243dSDimitry Andric       ctx.config.guardCF &= ~GuardCFLevel::EHCont;
113bdd1243dSDimitry Andric     else if (arg.equals_insensitive("cf") || arg.equals_insensitive("longjmp"))
114bdd1243dSDimitry Andric       ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::LongJmp;
115fe6060f1SDimitry Andric     else if (arg.equals_insensitive("ehcont"))
116bdd1243dSDimitry Andric       ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::EHCont;
1170b57cec5SDimitry Andric     else
1180b57cec5SDimitry Andric       fatal("invalid argument to /guard: " + arg);
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric // Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
parseSubsystem(StringRef arg,WindowsSubsystem * sys,uint32_t * major,uint32_t * minor,bool * gotVersion)123bdd1243dSDimitry Andric void LinkerDriver::parseSubsystem(StringRef arg, WindowsSubsystem *sys,
124bdd1243dSDimitry Andric                                   uint32_t *major, uint32_t *minor,
125bdd1243dSDimitry Andric                                   bool *gotVersion) {
126bdd1243dSDimitry Andric   auto [sysStr, ver] = arg.split(',');
1270b57cec5SDimitry Andric   std::string sysStrLower = sysStr.lower();
1280b57cec5SDimitry Andric   *sys = StringSwitch<WindowsSubsystem>(sysStrLower)
1290b57cec5SDimitry Andric     .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
1300b57cec5SDimitry Andric     .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
1310b57cec5SDimitry Andric     .Case("default", IMAGE_SUBSYSTEM_UNKNOWN)
1320b57cec5SDimitry Andric     .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)
1330b57cec5SDimitry Andric     .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
1340b57cec5SDimitry Andric     .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)
1350b57cec5SDimitry Andric     .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
1360b57cec5SDimitry Andric     .Case("native", IMAGE_SUBSYSTEM_NATIVE)
1370b57cec5SDimitry Andric     .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
1380b57cec5SDimitry Andric     .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
1390b57cec5SDimitry Andric     .Default(IMAGE_SUBSYSTEM_UNKNOWN);
1400b57cec5SDimitry Andric   if (*sys == IMAGE_SUBSYSTEM_UNKNOWN && sysStrLower != "default")
1410b57cec5SDimitry Andric     fatal("unknown subsystem: " + sysStr);
1420b57cec5SDimitry Andric   if (!ver.empty())
1430b57cec5SDimitry Andric     parseVersion(ver, major, minor);
144e8d8bef9SDimitry Andric   if (gotVersion)
145e8d8bef9SDimitry Andric     *gotVersion = !ver.empty();
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric // Parse a string of the form of "<from>=<to>".
1490b57cec5SDimitry Andric // Results are directly written to Config.
parseAlternateName(StringRef s)150bdd1243dSDimitry Andric void LinkerDriver::parseAlternateName(StringRef s) {
151bdd1243dSDimitry Andric   auto [from, to] = s.split('=');
1520b57cec5SDimitry Andric   if (from.empty() || to.empty())
1530b57cec5SDimitry Andric     fatal("/alternatename: invalid argument: " + s);
154bdd1243dSDimitry Andric   auto it = ctx.config.alternateNames.find(from);
155bdd1243dSDimitry Andric   if (it != ctx.config.alternateNames.end() && it->second != to)
1560b57cec5SDimitry Andric     fatal("/alternatename: conflicts: " + s);
157bdd1243dSDimitry Andric   ctx.config.alternateNames.insert(it, std::make_pair(from, to));
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric // Parse a string of the form of "<from>=<to>".
1610b57cec5SDimitry Andric // Results are directly written to Config.
parseMerge(StringRef s)162bdd1243dSDimitry Andric void LinkerDriver::parseMerge(StringRef s) {
163bdd1243dSDimitry Andric   auto [from, to] = s.split('=');
1640b57cec5SDimitry Andric   if (from.empty() || to.empty())
1650b57cec5SDimitry Andric     fatal("/merge: invalid argument: " + s);
1660b57cec5SDimitry Andric   if (from == ".rsrc" || to == ".rsrc")
1670b57cec5SDimitry Andric     fatal("/merge: cannot merge '.rsrc' with any section");
1680b57cec5SDimitry Andric   if (from == ".reloc" || to == ".reloc")
1690b57cec5SDimitry Andric     fatal("/merge: cannot merge '.reloc' with any section");
170bdd1243dSDimitry Andric   auto pair = ctx.config.merge.insert(std::make_pair(from, to));
1710b57cec5SDimitry Andric   bool inserted = pair.second;
1720b57cec5SDimitry Andric   if (!inserted) {
1730b57cec5SDimitry Andric     StringRef existing = pair.first->second;
1740b57cec5SDimitry Andric     if (existing != to)
1750b57cec5SDimitry Andric       warn(s + ": already merged into " + existing);
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
parsePDBPageSize(StringRef s)179bdd1243dSDimitry Andric void LinkerDriver::parsePDBPageSize(StringRef s) {
180349cc55cSDimitry Andric   int v;
181349cc55cSDimitry Andric   if (s.getAsInteger(0, v)) {
182349cc55cSDimitry Andric     error("/pdbpagesize: invalid argument: " + s);
183349cc55cSDimitry Andric     return;
184349cc55cSDimitry Andric   }
185349cc55cSDimitry Andric   if (v != 4096 && v != 8192 && v != 16384 && v != 32768) {
186349cc55cSDimitry Andric     error("/pdbpagesize: invalid argument: " + s);
187349cc55cSDimitry Andric     return;
188349cc55cSDimitry Andric   }
189349cc55cSDimitry Andric 
190bdd1243dSDimitry Andric   ctx.config.pdbPageSize = v;
191349cc55cSDimitry Andric }
192349cc55cSDimitry Andric 
parseSectionAttributes(StringRef s)1930b57cec5SDimitry Andric static uint32_t parseSectionAttributes(StringRef s) {
1940b57cec5SDimitry Andric   uint32_t ret = 0;
1950b57cec5SDimitry Andric   for (char c : s.lower()) {
1960b57cec5SDimitry Andric     switch (c) {
1970b57cec5SDimitry Andric     case 'd':
1980b57cec5SDimitry Andric       ret |= IMAGE_SCN_MEM_DISCARDABLE;
1990b57cec5SDimitry Andric       break;
2000b57cec5SDimitry Andric     case 'e':
2010b57cec5SDimitry Andric       ret |= IMAGE_SCN_MEM_EXECUTE;
2020b57cec5SDimitry Andric       break;
2030b57cec5SDimitry Andric     case 'k':
2040b57cec5SDimitry Andric       ret |= IMAGE_SCN_MEM_NOT_CACHED;
2050b57cec5SDimitry Andric       break;
2060b57cec5SDimitry Andric     case 'p':
2070b57cec5SDimitry Andric       ret |= IMAGE_SCN_MEM_NOT_PAGED;
2080b57cec5SDimitry Andric       break;
2090b57cec5SDimitry Andric     case 'r':
2100b57cec5SDimitry Andric       ret |= IMAGE_SCN_MEM_READ;
2110b57cec5SDimitry Andric       break;
2120b57cec5SDimitry Andric     case 's':
2130b57cec5SDimitry Andric       ret |= IMAGE_SCN_MEM_SHARED;
2140b57cec5SDimitry Andric       break;
2150b57cec5SDimitry Andric     case 'w':
2160b57cec5SDimitry Andric       ret |= IMAGE_SCN_MEM_WRITE;
2170b57cec5SDimitry Andric       break;
2180b57cec5SDimitry Andric     default:
2190b57cec5SDimitry Andric       fatal("/section: invalid argument: " + s);
2200b57cec5SDimitry Andric     }
2210b57cec5SDimitry Andric   }
2220b57cec5SDimitry Andric   return ret;
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric // Parses /section option argument.
parseSection(StringRef s)226bdd1243dSDimitry Andric void LinkerDriver::parseSection(StringRef s) {
227bdd1243dSDimitry Andric   auto [name, attrs] = s.split(',');
2280b57cec5SDimitry Andric   if (name.empty() || attrs.empty())
2290b57cec5SDimitry Andric     fatal("/section: invalid argument: " + s);
230bdd1243dSDimitry Andric   ctx.config.section[name] = parseSectionAttributes(attrs);
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric // Parses /aligncomm option argument.
parseAligncomm(StringRef s)234bdd1243dSDimitry Andric void LinkerDriver::parseAligncomm(StringRef s) {
235bdd1243dSDimitry Andric   auto [name, align] = s.split(',');
2360b57cec5SDimitry Andric   if (name.empty() || align.empty()) {
2370b57cec5SDimitry Andric     error("/aligncomm: invalid argument: " + s);
2380b57cec5SDimitry Andric     return;
2390b57cec5SDimitry Andric   }
2400b57cec5SDimitry Andric   int v;
2410b57cec5SDimitry Andric   if (align.getAsInteger(0, v)) {
2420b57cec5SDimitry Andric     error("/aligncomm: invalid argument: " + s);
2430b57cec5SDimitry Andric     return;
2440b57cec5SDimitry Andric   }
245bdd1243dSDimitry Andric   ctx.config.alignComm[std::string(name)] =
246bdd1243dSDimitry Andric       std::max(ctx.config.alignComm[std::string(name)], 1 << v);
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric // Parses /functionpadmin option argument.
parseFunctionPadMin(llvm::opt::Arg * a)250bdd1243dSDimitry Andric void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
2510b57cec5SDimitry Andric   StringRef arg = a->getNumValues() ? a->getValue() : "";
2520b57cec5SDimitry Andric   if (!arg.empty()) {
2530b57cec5SDimitry Andric     // Optional padding in bytes is given.
254bdd1243dSDimitry Andric     if (arg.getAsInteger(0, ctx.config.functionPadMin))
2550b57cec5SDimitry Andric       error("/functionpadmin: invalid argument: " + arg);
2560b57cec5SDimitry Andric     return;
2570b57cec5SDimitry Andric   }
2580b57cec5SDimitry Andric   // No optional argument given.
2590b57cec5SDimitry Andric   // Set default padding based on machine, similar to link.exe.
2600b57cec5SDimitry Andric   // There is no default padding for ARM platforms.
261bdd1243dSDimitry Andric   if (ctx.config.machine == I386) {
262bdd1243dSDimitry Andric     ctx.config.functionPadMin = 5;
263bdd1243dSDimitry Andric   } else if (ctx.config.machine == AMD64) {
264bdd1243dSDimitry Andric     ctx.config.functionPadMin = 6;
2650b57cec5SDimitry Andric   } else {
2660b57cec5SDimitry Andric     error("/functionpadmin: invalid argument for this machine: " + arg);
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric 
2705f757f3fSDimitry Andric // Parses /dependentloadflag option argument.
parseDependentLoadFlags(llvm::opt::Arg * a)2715f757f3fSDimitry Andric void LinkerDriver::parseDependentLoadFlags(llvm::opt::Arg *a) {
2725f757f3fSDimitry Andric   StringRef arg = a->getNumValues() ? a->getValue() : "";
2735f757f3fSDimitry Andric   if (!arg.empty()) {
2745f757f3fSDimitry Andric     if (arg.getAsInteger(0, ctx.config.dependentLoadFlags))
2755f757f3fSDimitry Andric       error("/dependentloadflag: invalid argument: " + arg);
2765f757f3fSDimitry Andric     return;
2775f757f3fSDimitry Andric   }
2785f757f3fSDimitry Andric   // MSVC linker reports error "no argument specified", although MSDN describes
2795f757f3fSDimitry Andric   // argument as optional.
2805f757f3fSDimitry Andric   error("/dependentloadflag: no argument specified");
2815f757f3fSDimitry Andric }
2825f757f3fSDimitry Andric 
2830b57cec5SDimitry Andric // Parses a string in the form of "EMBED[,=<integer>]|NO".
284bdd1243dSDimitry Andric // Results are directly written to
285bdd1243dSDimitry Andric // Config.
parseManifest(StringRef arg)286bdd1243dSDimitry Andric void LinkerDriver::parseManifest(StringRef arg) {
287fe6060f1SDimitry Andric   if (arg.equals_insensitive("no")) {
288bdd1243dSDimitry Andric     ctx.config.manifest = Configuration::No;
2890b57cec5SDimitry Andric     return;
2900b57cec5SDimitry Andric   }
29106c3fb27SDimitry Andric   if (!arg.starts_with_insensitive("embed"))
2920b57cec5SDimitry Andric     fatal("invalid option " + arg);
293bdd1243dSDimitry Andric   ctx.config.manifest = Configuration::Embed;
2940b57cec5SDimitry Andric   arg = arg.substr(strlen("embed"));
2950b57cec5SDimitry Andric   if (arg.empty())
2960b57cec5SDimitry Andric     return;
29706c3fb27SDimitry Andric   if (!arg.starts_with_insensitive(",id="))
2980b57cec5SDimitry Andric     fatal("invalid option " + arg);
2990b57cec5SDimitry Andric   arg = arg.substr(strlen(",id="));
300bdd1243dSDimitry Andric   if (arg.getAsInteger(0, ctx.config.manifestID))
3010b57cec5SDimitry Andric     fatal("invalid option " + arg);
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric 
3040b57cec5SDimitry Andric // Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
3050b57cec5SDimitry Andric // Results are directly written to Config.
parseManifestUAC(StringRef arg)306bdd1243dSDimitry Andric void LinkerDriver::parseManifestUAC(StringRef arg) {
307fe6060f1SDimitry Andric   if (arg.equals_insensitive("no")) {
308bdd1243dSDimitry Andric     ctx.config.manifestUAC = false;
3090b57cec5SDimitry Andric     return;
3100b57cec5SDimitry Andric   }
3110b57cec5SDimitry Andric   for (;;) {
3120b57cec5SDimitry Andric     arg = arg.ltrim();
3130b57cec5SDimitry Andric     if (arg.empty())
3140b57cec5SDimitry Andric       return;
3157a6dacacSDimitry Andric     if (arg.consume_front_insensitive("level=")) {
316bdd1243dSDimitry Andric       std::tie(ctx.config.manifestLevel, arg) = arg.split(" ");
3170b57cec5SDimitry Andric       continue;
3180b57cec5SDimitry Andric     }
3197a6dacacSDimitry Andric     if (arg.consume_front_insensitive("uiaccess=")) {
320bdd1243dSDimitry Andric       std::tie(ctx.config.manifestUIAccess, arg) = arg.split(" ");
3210b57cec5SDimitry Andric       continue;
3220b57cec5SDimitry Andric     }
3230b57cec5SDimitry Andric     fatal("invalid option " + arg);
3240b57cec5SDimitry Andric   }
3250b57cec5SDimitry Andric }
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric // Parses a string in the form of "cd|net[,(cd|net)]*"
3280b57cec5SDimitry Andric // Results are directly written to Config.
parseSwaprun(StringRef arg)329bdd1243dSDimitry Andric void LinkerDriver::parseSwaprun(StringRef arg) {
3300b57cec5SDimitry Andric   do {
331bdd1243dSDimitry Andric     auto [swaprun, newArg] = arg.split(',');
332fe6060f1SDimitry Andric     if (swaprun.equals_insensitive("cd"))
333bdd1243dSDimitry Andric       ctx.config.swaprunCD = true;
334fe6060f1SDimitry Andric     else if (swaprun.equals_insensitive("net"))
335bdd1243dSDimitry Andric       ctx.config.swaprunNet = true;
3360b57cec5SDimitry Andric     else if (swaprun.empty())
3370b57cec5SDimitry Andric       error("/swaprun: missing argument");
3380b57cec5SDimitry Andric     else
3390b57cec5SDimitry Andric       error("/swaprun: invalid argument: " + swaprun);
3400b57cec5SDimitry Andric     // To catch trailing commas, e.g. `/spawrun:cd,`
34106c3fb27SDimitry Andric     if (newArg.empty() && arg.ends_with(","))
3420b57cec5SDimitry Andric       error("/swaprun: missing argument");
3430b57cec5SDimitry Andric     arg = newArg;
3440b57cec5SDimitry Andric   } while (!arg.empty());
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric // An RAII temporary file class that automatically removes a temporary file.
3480b57cec5SDimitry Andric namespace {
3490b57cec5SDimitry Andric class TemporaryFile {
3500b57cec5SDimitry Andric public:
TemporaryFile(StringRef prefix,StringRef extn,StringRef contents="")3510b57cec5SDimitry Andric   TemporaryFile(StringRef prefix, StringRef extn, StringRef contents = "") {
3520b57cec5SDimitry Andric     SmallString<128> s;
3530b57cec5SDimitry Andric     if (auto ec = sys::fs::createTemporaryFile("lld-" + prefix, extn, s))
3540b57cec5SDimitry Andric       fatal("cannot create a temporary file: " + ec.message());
3557a6dacacSDimitry Andric     path = std::string(s);
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric     if (!contents.empty()) {
3580b57cec5SDimitry Andric       std::error_code ec;
35985868e8aSDimitry Andric       raw_fd_ostream os(path, ec, sys::fs::OF_None);
3600b57cec5SDimitry Andric       if (ec)
3610b57cec5SDimitry Andric         fatal("failed to open " + path + ": " + ec.message());
3620b57cec5SDimitry Andric       os << contents;
3630b57cec5SDimitry Andric     }
3640b57cec5SDimitry Andric   }
3650b57cec5SDimitry Andric 
TemporaryFile(TemporaryFile && obj)36606c3fb27SDimitry Andric   TemporaryFile(TemporaryFile &&obj) noexcept { std::swap(path, obj.path); }
3670b57cec5SDimitry Andric 
~TemporaryFile()3680b57cec5SDimitry Andric   ~TemporaryFile() {
3690b57cec5SDimitry Andric     if (path.empty())
3700b57cec5SDimitry Andric       return;
3710b57cec5SDimitry Andric     if (sys::fs::remove(path))
3720b57cec5SDimitry Andric       fatal("failed to remove " + path);
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric   // Returns a memory buffer of this temporary file.
3760b57cec5SDimitry Andric   // Note that this function does not leave the file open,
3770b57cec5SDimitry Andric   // so it is safe to remove the file immediately after this function
3780b57cec5SDimitry Andric   // is called (you cannot remove an opened file on Windows.)
getMemoryBuffer()3790b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
3800b57cec5SDimitry Andric     // IsVolatile=true forces MemoryBuffer to not use mmap().
381fe6060f1SDimitry Andric     return CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
3820b57cec5SDimitry Andric                                        /*RequiresNullTerminator=*/false,
3830b57cec5SDimitry Andric                                        /*IsVolatile=*/true),
3840b57cec5SDimitry Andric                  "could not open " + path);
3850b57cec5SDimitry Andric   }
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   std::string path;
3880b57cec5SDimitry Andric };
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric 
createDefaultXml()391bdd1243dSDimitry Andric std::string LinkerDriver::createDefaultXml() {
3920b57cec5SDimitry Andric   std::string ret;
3930b57cec5SDimitry Andric   raw_string_ostream os(ret);
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   // Emit the XML. Note that we do *not* verify that the XML attributes are
3960b57cec5SDimitry Andric   // syntactically correct. This is intentional for link.exe compatibility.
3970b57cec5SDimitry Andric   os << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
3980b57cec5SDimitry Andric      << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
3990b57cec5SDimitry Andric      << "          manifestVersion=\"1.0\">\n";
400bdd1243dSDimitry Andric   if (ctx.config.manifestUAC) {
4010b57cec5SDimitry Andric     os << "  <trustInfo>\n"
4020b57cec5SDimitry Andric        << "    <security>\n"
4030b57cec5SDimitry Andric        << "      <requestedPrivileges>\n"
404bdd1243dSDimitry Andric        << "         <requestedExecutionLevel level=" << ctx.config.manifestLevel
405bdd1243dSDimitry Andric        << " uiAccess=" << ctx.config.manifestUIAccess << "/>\n"
4060b57cec5SDimitry Andric        << "      </requestedPrivileges>\n"
4070b57cec5SDimitry Andric        << "    </security>\n"
4080b57cec5SDimitry Andric        << "  </trustInfo>\n";
4090b57cec5SDimitry Andric   }
410bdd1243dSDimitry Andric   for (auto manifestDependency : ctx.config.manifestDependencies) {
4110b57cec5SDimitry Andric     os << "  <dependency>\n"
4120b57cec5SDimitry Andric        << "    <dependentAssembly>\n"
413349cc55cSDimitry Andric        << "      <assemblyIdentity " << manifestDependency << " />\n"
4140b57cec5SDimitry Andric        << "    </dependentAssembly>\n"
4150b57cec5SDimitry Andric        << "  </dependency>\n";
4160b57cec5SDimitry Andric   }
4170b57cec5SDimitry Andric   os << "</assembly>\n";
4180b57cec5SDimitry Andric   return os.str();
4190b57cec5SDimitry Andric }
4200b57cec5SDimitry Andric 
421bdd1243dSDimitry Andric std::string
createManifestXmlWithInternalMt(StringRef defaultXml)422bdd1243dSDimitry Andric LinkerDriver::createManifestXmlWithInternalMt(StringRef defaultXml) {
4230b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> defaultXmlCopy =
4240b57cec5SDimitry Andric       MemoryBuffer::getMemBufferCopy(defaultXml);
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric   windows_manifest::WindowsManifestMerger merger;
4270b57cec5SDimitry Andric   if (auto e = merger.merge(*defaultXmlCopy.get()))
4280b57cec5SDimitry Andric     fatal("internal manifest tool failed on default xml: " +
4290b57cec5SDimitry Andric           toString(std::move(e)));
4300b57cec5SDimitry Andric 
431bdd1243dSDimitry Andric   for (StringRef filename : ctx.config.manifestInput) {
4320b57cec5SDimitry Andric     std::unique_ptr<MemoryBuffer> manifest =
4330b57cec5SDimitry Andric         check(MemoryBuffer::getFile(filename));
434349cc55cSDimitry Andric     // Call takeBuffer to include in /reproduce: output if applicable.
435bdd1243dSDimitry Andric     if (auto e = merger.merge(takeBuffer(std::move(manifest))))
4360b57cec5SDimitry Andric       fatal("internal manifest tool failed on file " + filename + ": " +
4370b57cec5SDimitry Andric             toString(std::move(e)));
4380b57cec5SDimitry Andric   }
4390b57cec5SDimitry Andric 
4405ffd83dbSDimitry Andric   return std::string(merger.getMergedManifest().get()->getBuffer());
4410b57cec5SDimitry Andric }
4420b57cec5SDimitry Andric 
443bdd1243dSDimitry Andric std::string
createManifestXmlWithExternalMt(StringRef defaultXml)444bdd1243dSDimitry Andric LinkerDriver::createManifestXmlWithExternalMt(StringRef defaultXml) {
4450b57cec5SDimitry Andric   // Create the default manifest file as a temporary file.
4460b57cec5SDimitry Andric   TemporaryFile Default("defaultxml", "manifest");
4470b57cec5SDimitry Andric   std::error_code ec;
448fe6060f1SDimitry Andric   raw_fd_ostream os(Default.path, ec, sys::fs::OF_TextWithCRLF);
4490b57cec5SDimitry Andric   if (ec)
4500b57cec5SDimitry Andric     fatal("failed to open " + Default.path + ": " + ec.message());
4510b57cec5SDimitry Andric   os << defaultXml;
4520b57cec5SDimitry Andric   os.close();
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   // Merge user-supplied manifests if they are given.  Since libxml2 is not
4550b57cec5SDimitry Andric   // enabled, we must shell out to Microsoft's mt.exe tool.
4560b57cec5SDimitry Andric   TemporaryFile user("user", "manifest");
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric   Executor e("mt.exe");
4590b57cec5SDimitry Andric   e.add("/manifest");
4600b57cec5SDimitry Andric   e.add(Default.path);
461bdd1243dSDimitry Andric   for (StringRef filename : ctx.config.manifestInput) {
4620b57cec5SDimitry Andric     e.add("/manifest");
4630b57cec5SDimitry Andric     e.add(filename);
464349cc55cSDimitry Andric 
465349cc55cSDimitry Andric     // Manually add the file to the /reproduce: tar if needed.
466bdd1243dSDimitry Andric     if (tar)
467349cc55cSDimitry Andric       if (auto mbOrErr = MemoryBuffer::getFile(filename))
468bdd1243dSDimitry Andric         takeBuffer(std::move(*mbOrErr));
4690b57cec5SDimitry Andric   }
4700b57cec5SDimitry Andric   e.add("/nologo");
4710b57cec5SDimitry Andric   e.add("/out:" + StringRef(user.path));
4720b57cec5SDimitry Andric   e.run();
4730b57cec5SDimitry Andric 
4745ffd83dbSDimitry Andric   return std::string(
4755ffd83dbSDimitry Andric       CHECK(MemoryBuffer::getFile(user.path), "could not open " + user.path)
4760b57cec5SDimitry Andric           .get()
4775ffd83dbSDimitry Andric           ->getBuffer());
4780b57cec5SDimitry Andric }
4790b57cec5SDimitry Andric 
createManifestXml()480bdd1243dSDimitry Andric std::string LinkerDriver::createManifestXml() {
4810b57cec5SDimitry Andric   std::string defaultXml = createDefaultXml();
482bdd1243dSDimitry Andric   if (ctx.config.manifestInput.empty())
4830b57cec5SDimitry Andric     return defaultXml;
4840b57cec5SDimitry Andric 
4850b57cec5SDimitry Andric   if (windows_manifest::isAvailable())
4860b57cec5SDimitry Andric     return createManifestXmlWithInternalMt(defaultXml);
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric   return createManifestXmlWithExternalMt(defaultXml);
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric 
491bdd1243dSDimitry Andric std::unique_ptr<WritableMemoryBuffer>
createMemoryBufferForManifestRes(size_t manifestSize)492bdd1243dSDimitry Andric LinkerDriver::createMemoryBufferForManifestRes(size_t manifestSize) {
4930b57cec5SDimitry Andric   size_t resSize = alignTo(
4940b57cec5SDimitry Andric       object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
4950b57cec5SDimitry Andric           sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
4960b57cec5SDimitry Andric           sizeof(object::WinResHeaderSuffix) + manifestSize,
4970b57cec5SDimitry Andric       object::WIN_RES_DATA_ALIGNMENT);
498bdd1243dSDimitry Andric   return WritableMemoryBuffer::getNewMemBuffer(resSize, ctx.config.outputFile +
4990b57cec5SDimitry Andric                                                             ".manifest.res");
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric 
writeResFileHeader(char * & buf)5020b57cec5SDimitry Andric static void writeResFileHeader(char *&buf) {
5030b57cec5SDimitry Andric   memcpy(buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
5040b57cec5SDimitry Andric   buf += sizeof(COFF::WinResMagic);
5050b57cec5SDimitry Andric   memset(buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
5060b57cec5SDimitry Andric   buf += object::WIN_RES_NULL_ENTRY_SIZE;
5070b57cec5SDimitry Andric }
5080b57cec5SDimitry Andric 
writeResEntryHeader(char * & buf,size_t manifestSize,int manifestID)509bdd1243dSDimitry Andric static void writeResEntryHeader(char *&buf, size_t manifestSize,
510bdd1243dSDimitry Andric                                 int manifestID) {
5110b57cec5SDimitry Andric   // Write the prefix.
5120b57cec5SDimitry Andric   auto *prefix = reinterpret_cast<object::WinResHeaderPrefix *>(buf);
5130b57cec5SDimitry Andric   prefix->DataSize = manifestSize;
5140b57cec5SDimitry Andric   prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
5150b57cec5SDimitry Andric                        sizeof(object::WinResIDs) +
5160b57cec5SDimitry Andric                        sizeof(object::WinResHeaderSuffix);
5170b57cec5SDimitry Andric   buf += sizeof(object::WinResHeaderPrefix);
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   // Write the Type/Name IDs.
5200b57cec5SDimitry Andric   auto *iDs = reinterpret_cast<object::WinResIDs *>(buf);
5210b57cec5SDimitry Andric   iDs->setType(RT_MANIFEST);
522bdd1243dSDimitry Andric   iDs->setName(manifestID);
5230b57cec5SDimitry Andric   buf += sizeof(object::WinResIDs);
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric   // Write the suffix.
5260b57cec5SDimitry Andric   auto *suffix = reinterpret_cast<object::WinResHeaderSuffix *>(buf);
5270b57cec5SDimitry Andric   suffix->DataVersion = 0;
5280b57cec5SDimitry Andric   suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
5290b57cec5SDimitry Andric   suffix->Language = SUBLANG_ENGLISH_US;
5300b57cec5SDimitry Andric   suffix->Version = 0;
5310b57cec5SDimitry Andric   suffix->Characteristics = 0;
5320b57cec5SDimitry Andric   buf += sizeof(object::WinResHeaderSuffix);
5330b57cec5SDimitry Andric }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric // Create a resource file containing a manifest XML.
createManifestRes()536bdd1243dSDimitry Andric std::unique_ptr<MemoryBuffer> LinkerDriver::createManifestRes() {
5370b57cec5SDimitry Andric   std::string manifest = createManifestXml();
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric   std::unique_ptr<WritableMemoryBuffer> res =
5400b57cec5SDimitry Andric       createMemoryBufferForManifestRes(manifest.size());
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric   char *buf = res->getBufferStart();
5430b57cec5SDimitry Andric   writeResFileHeader(buf);
544bdd1243dSDimitry Andric   writeResEntryHeader(buf, manifest.size(), ctx.config.manifestID);
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric   // Copy the manifest data into the .res file.
5470b57cec5SDimitry Andric   std::copy(manifest.begin(), manifest.end(), buf);
5480b57cec5SDimitry Andric   return std::move(res);
5490b57cec5SDimitry Andric }
5500b57cec5SDimitry Andric 
createSideBySideManifest()551bdd1243dSDimitry Andric void LinkerDriver::createSideBySideManifest() {
552bdd1243dSDimitry Andric   std::string path = std::string(ctx.config.manifestFile);
5530b57cec5SDimitry Andric   if (path == "")
554bdd1243dSDimitry Andric     path = ctx.config.outputFile + ".manifest";
5550b57cec5SDimitry Andric   std::error_code ec;
556fe6060f1SDimitry Andric   raw_fd_ostream out(path, ec, sys::fs::OF_TextWithCRLF);
5570b57cec5SDimitry Andric   if (ec)
5580b57cec5SDimitry Andric     fatal("failed to create manifest: " + ec.message());
5590b57cec5SDimitry Andric   out << createManifestXml();
5600b57cec5SDimitry Andric }
5610b57cec5SDimitry Andric 
5620b57cec5SDimitry Andric // Parse a string in the form of
5630b57cec5SDimitry Andric // "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
5640b57cec5SDimitry Andric // or "<name>=<dllname>.<name>".
5650b57cec5SDimitry Andric // Used for parsing /export arguments.
parseExport(StringRef arg)566bdd1243dSDimitry Andric Export LinkerDriver::parseExport(StringRef arg) {
5670b57cec5SDimitry Andric   Export e;
56806c3fb27SDimitry Andric   e.source = ExportSource::Export;
56906c3fb27SDimitry Andric 
5700b57cec5SDimitry Andric   StringRef rest;
5710b57cec5SDimitry Andric   std::tie(e.name, rest) = arg.split(",");
5720b57cec5SDimitry Andric   if (e.name.empty())
5730b57cec5SDimitry Andric     goto err;
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric   if (e.name.contains('=')) {
576bdd1243dSDimitry Andric     auto [x, y] = e.name.split("=");
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric     // If "<name>=<dllname>.<name>".
5790b57cec5SDimitry Andric     if (y.contains(".")) {
5800b57cec5SDimitry Andric       e.name = x;
5810b57cec5SDimitry Andric       e.forwardTo = y;
582*0fca6ea1SDimitry Andric     } else {
5830b57cec5SDimitry Andric       e.extName = x;
5840b57cec5SDimitry Andric       e.name = y;
5850b57cec5SDimitry Andric       if (e.name.empty())
5860b57cec5SDimitry Andric         goto err;
5870b57cec5SDimitry Andric     }
588*0fca6ea1SDimitry Andric   }
5890b57cec5SDimitry Andric 
590*0fca6ea1SDimitry Andric   // Optional parameters
591*0fca6ea1SDimitry Andric   // "[,@ordinal[,NONAME]][,DATA][,PRIVATE][,EXPORTAS,exportname]"
5920b57cec5SDimitry Andric   while (!rest.empty()) {
5930b57cec5SDimitry Andric     StringRef tok;
5940b57cec5SDimitry Andric     std::tie(tok, rest) = rest.split(",");
595fe6060f1SDimitry Andric     if (tok.equals_insensitive("noname")) {
5960b57cec5SDimitry Andric       if (e.ordinal == 0)
5970b57cec5SDimitry Andric         goto err;
5980b57cec5SDimitry Andric       e.noname = true;
5990b57cec5SDimitry Andric       continue;
6000b57cec5SDimitry Andric     }
601fe6060f1SDimitry Andric     if (tok.equals_insensitive("data")) {
6020b57cec5SDimitry Andric       e.data = true;
6030b57cec5SDimitry Andric       continue;
6040b57cec5SDimitry Andric     }
605fe6060f1SDimitry Andric     if (tok.equals_insensitive("constant")) {
6060b57cec5SDimitry Andric       e.constant = true;
6070b57cec5SDimitry Andric       continue;
6080b57cec5SDimitry Andric     }
609fe6060f1SDimitry Andric     if (tok.equals_insensitive("private")) {
6100b57cec5SDimitry Andric       e.isPrivate = true;
6110b57cec5SDimitry Andric       continue;
6120b57cec5SDimitry Andric     }
613*0fca6ea1SDimitry Andric     if (tok.equals_insensitive("exportas")) {
614*0fca6ea1SDimitry Andric       if (!rest.empty() && !rest.contains(','))
615*0fca6ea1SDimitry Andric         e.exportAs = rest;
616*0fca6ea1SDimitry Andric       else
617*0fca6ea1SDimitry Andric         error("invalid EXPORTAS value: " + rest);
618*0fca6ea1SDimitry Andric       break;
619*0fca6ea1SDimitry Andric     }
62006c3fb27SDimitry Andric     if (tok.starts_with("@")) {
6210b57cec5SDimitry Andric       int32_t ord;
6220b57cec5SDimitry Andric       if (tok.substr(1).getAsInteger(0, ord))
6230b57cec5SDimitry Andric         goto err;
6240b57cec5SDimitry Andric       if (ord <= 0 || 65535 < ord)
6250b57cec5SDimitry Andric         goto err;
6260b57cec5SDimitry Andric       e.ordinal = ord;
6270b57cec5SDimitry Andric       continue;
6280b57cec5SDimitry Andric     }
6290b57cec5SDimitry Andric     goto err;
6300b57cec5SDimitry Andric   }
6310b57cec5SDimitry Andric   return e;
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric err:
6340b57cec5SDimitry Andric   fatal("invalid /export: " + arg);
6350b57cec5SDimitry Andric }
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric // Convert stdcall/fastcall style symbols into unsuffixed symbols,
6380b57cec5SDimitry Andric // with or without a leading underscore. (MinGW specific.)
killAt(StringRef sym,bool prefix)6390b57cec5SDimitry Andric static StringRef killAt(StringRef sym, bool prefix) {
6400b57cec5SDimitry Andric   if (sym.empty())
6410b57cec5SDimitry Andric     return sym;
6420b57cec5SDimitry Andric   // Strip any trailing stdcall suffix
6430b57cec5SDimitry Andric   sym = sym.substr(0, sym.find('@', 1));
64406c3fb27SDimitry Andric   if (!sym.starts_with("@")) {
64506c3fb27SDimitry Andric     if (prefix && !sym.starts_with("_"))
64604eeddc0SDimitry Andric       return saver().save("_" + sym);
6470b57cec5SDimitry Andric     return sym;
6480b57cec5SDimitry Andric   }
6490b57cec5SDimitry Andric   // For fastcall, remove the leading @ and replace it with an
6500b57cec5SDimitry Andric   // underscore, if prefixes are used.
6510b57cec5SDimitry Andric   sym = sym.substr(1);
6520b57cec5SDimitry Andric   if (prefix)
65304eeddc0SDimitry Andric     sym = saver().save("_" + sym);
6540b57cec5SDimitry Andric   return sym;
6550b57cec5SDimitry Andric }
6560b57cec5SDimitry Andric 
exportSourceName(ExportSource s)65706c3fb27SDimitry Andric static StringRef exportSourceName(ExportSource s) {
65806c3fb27SDimitry Andric   switch (s) {
65906c3fb27SDimitry Andric   case ExportSource::Directives:
66006c3fb27SDimitry Andric     return "source file (directives)";
66106c3fb27SDimitry Andric   case ExportSource::Export:
66206c3fb27SDimitry Andric     return "/export";
66306c3fb27SDimitry Andric   case ExportSource::ModuleDefinition:
66406c3fb27SDimitry Andric     return "/def";
66506c3fb27SDimitry Andric   default:
66606c3fb27SDimitry Andric     llvm_unreachable("unknown ExportSource");
66706c3fb27SDimitry Andric   }
66806c3fb27SDimitry Andric }
66906c3fb27SDimitry Andric 
6700b57cec5SDimitry Andric // Performs error checking on all /export arguments.
6710b57cec5SDimitry Andric // It also sets ordinals.
fixupExports()672bdd1243dSDimitry Andric void LinkerDriver::fixupExports() {
6735f757f3fSDimitry Andric   llvm::TimeTraceScope timeScope("Fixup exports");
6740b57cec5SDimitry Andric   // Symbol ordinals must be unique.
6750b57cec5SDimitry Andric   std::set<uint16_t> ords;
676bdd1243dSDimitry Andric   for (Export &e : ctx.config.exports) {
6770b57cec5SDimitry Andric     if (e.ordinal == 0)
6780b57cec5SDimitry Andric       continue;
6790b57cec5SDimitry Andric     if (!ords.insert(e.ordinal).second)
6800b57cec5SDimitry Andric       fatal("duplicate export ordinal: " + e.name);
6810b57cec5SDimitry Andric   }
6820b57cec5SDimitry Andric 
683bdd1243dSDimitry Andric   for (Export &e : ctx.config.exports) {
684*0fca6ea1SDimitry Andric     if (!e.exportAs.empty()) {
685*0fca6ea1SDimitry Andric       e.exportName = e.exportAs;
686*0fca6ea1SDimitry Andric       continue;
6870b57cec5SDimitry Andric     }
688*0fca6ea1SDimitry Andric 
689*0fca6ea1SDimitry Andric     StringRef sym =
690*0fca6ea1SDimitry Andric         !e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName;
691*0fca6ea1SDimitry Andric     if (ctx.config.machine == I386 && sym.starts_with("_")) {
692*0fca6ea1SDimitry Andric       // In MSVC mode, a fully decorated stdcall function is exported
693*0fca6ea1SDimitry Andric       // as-is with the leading underscore (with type IMPORT_NAME).
694*0fca6ea1SDimitry Andric       // In MinGW mode, a decorated stdcall function gets the underscore
695*0fca6ea1SDimitry Andric       // removed, just like normal cdecl functions.
696*0fca6ea1SDimitry Andric       if (ctx.config.mingw || !sym.contains('@')) {
697*0fca6ea1SDimitry Andric         e.exportName = sym.substr(1);
698*0fca6ea1SDimitry Andric         continue;
699*0fca6ea1SDimitry Andric       }
700*0fca6ea1SDimitry Andric     }
701*0fca6ea1SDimitry Andric     if (isArm64EC(ctx.config.machine) && !e.data && !e.constant) {
702*0fca6ea1SDimitry Andric       if (std::optional<std::string> demangledName =
703*0fca6ea1SDimitry Andric               getArm64ECDemangledFunctionName(sym)) {
704*0fca6ea1SDimitry Andric         e.exportName = saver().save(*demangledName);
705*0fca6ea1SDimitry Andric         continue;
706*0fca6ea1SDimitry Andric       }
707*0fca6ea1SDimitry Andric     }
708*0fca6ea1SDimitry Andric     e.exportName = sym;
7090b57cec5SDimitry Andric   }
7100b57cec5SDimitry Andric 
711bdd1243dSDimitry Andric   if (ctx.config.killAt && ctx.config.machine == I386) {
712bdd1243dSDimitry Andric     for (Export &e : ctx.config.exports) {
7130b57cec5SDimitry Andric       e.name = killAt(e.name, true);
7140b57cec5SDimitry Andric       e.exportName = killAt(e.exportName, false);
7150b57cec5SDimitry Andric       e.extName = killAt(e.extName, true);
7160b57cec5SDimitry Andric       e.symbolName = killAt(e.symbolName, true);
7170b57cec5SDimitry Andric     }
7180b57cec5SDimitry Andric   }
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   // Uniquefy by name.
72106c3fb27SDimitry Andric   DenseMap<StringRef, std::pair<Export *, unsigned>> map(
72206c3fb27SDimitry Andric       ctx.config.exports.size());
7230b57cec5SDimitry Andric   std::vector<Export> v;
724bdd1243dSDimitry Andric   for (Export &e : ctx.config.exports) {
72506c3fb27SDimitry Andric     auto pair = map.insert(std::make_pair(e.exportName, std::make_pair(&e, 0)));
7260b57cec5SDimitry Andric     bool inserted = pair.second;
7270b57cec5SDimitry Andric     if (inserted) {
72806c3fb27SDimitry Andric       pair.first->second.second = v.size();
7290b57cec5SDimitry Andric       v.push_back(e);
7300b57cec5SDimitry Andric       continue;
7310b57cec5SDimitry Andric     }
73206c3fb27SDimitry Andric     Export *existing = pair.first->second.first;
7330b57cec5SDimitry Andric     if (e == *existing || e.name != existing->name)
7340b57cec5SDimitry Andric       continue;
73506c3fb27SDimitry Andric     // If the existing export comes from .OBJ directives, we are allowed to
73606c3fb27SDimitry Andric     // overwrite it with /DEF: or /EXPORT without any warning, as MSVC link.exe
73706c3fb27SDimitry Andric     // does.
73806c3fb27SDimitry Andric     if (existing->source == ExportSource::Directives) {
73906c3fb27SDimitry Andric       *existing = e;
74006c3fb27SDimitry Andric       v[pair.first->second.second] = e;
74106c3fb27SDimitry Andric       continue;
74206c3fb27SDimitry Andric     }
74306c3fb27SDimitry Andric     if (existing->source == e.source) {
74406c3fb27SDimitry Andric       warn(Twine("duplicate ") + exportSourceName(existing->source) +
74506c3fb27SDimitry Andric            " option: " + e.name);
74606c3fb27SDimitry Andric     } else {
74706c3fb27SDimitry Andric       warn("duplicate export: " + e.name +
74806c3fb27SDimitry Andric            Twine(" first seen in " + exportSourceName(existing->source) +
74906c3fb27SDimitry Andric                  Twine(", now in " + exportSourceName(e.source))));
75006c3fb27SDimitry Andric     }
7510b57cec5SDimitry Andric   }
752bdd1243dSDimitry Andric   ctx.config.exports = std::move(v);
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   // Sort by name.
755bdd1243dSDimitry Andric   llvm::sort(ctx.config.exports, [](const Export &a, const Export &b) {
7560b57cec5SDimitry Andric     return a.exportName < b.exportName;
7570b57cec5SDimitry Andric   });
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric 
assignExportOrdinals()760bdd1243dSDimitry Andric void LinkerDriver::assignExportOrdinals() {
7610b57cec5SDimitry Andric   // Assign unique ordinals if default (= 0).
762e8d8bef9SDimitry Andric   uint32_t max = 0;
763bdd1243dSDimitry Andric   for (Export &e : ctx.config.exports)
764e8d8bef9SDimitry Andric     max = std::max(max, (uint32_t)e.ordinal);
765bdd1243dSDimitry Andric   for (Export &e : ctx.config.exports)
7660b57cec5SDimitry Andric     if (e.ordinal == 0)
7670b57cec5SDimitry Andric       e.ordinal = ++max;
768e8d8bef9SDimitry Andric   if (max > std::numeric_limits<uint16_t>::max())
769fcaf7f86SDimitry Andric     fatal("too many exported symbols (got " + Twine(max) + ", max " +
770e8d8bef9SDimitry Andric           Twine(std::numeric_limits<uint16_t>::max()) + ")");
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric // Parses a string in the form of "key=value" and check
7740b57cec5SDimitry Andric // if value matches previous values for the same key.
checkFailIfMismatch(StringRef arg,InputFile * source)775bdd1243dSDimitry Andric void LinkerDriver::checkFailIfMismatch(StringRef arg, InputFile *source) {
776bdd1243dSDimitry Andric   auto [k, v] = arg.split('=');
7770b57cec5SDimitry Andric   if (k.empty() || v.empty())
7780b57cec5SDimitry Andric     fatal("/failifmismatch: invalid argument: " + arg);
779bdd1243dSDimitry Andric   std::pair<StringRef, InputFile *> existing = ctx.config.mustMatch[k];
7800b57cec5SDimitry Andric   if (!existing.first.empty() && v != existing.first) {
7810b57cec5SDimitry Andric     std::string sourceStr = source ? toString(source) : "cmd-line";
7820b57cec5SDimitry Andric     std::string existingStr =
7830b57cec5SDimitry Andric         existing.second ? toString(existing.second) : "cmd-line";
7840b57cec5SDimitry Andric     fatal("/failifmismatch: mismatch detected for '" + k + "':\n>>> " +
7850b57cec5SDimitry Andric           existingStr + " has value " + existing.first + "\n>>> " + sourceStr +
7860b57cec5SDimitry Andric           " has value " + v);
7870b57cec5SDimitry Andric   }
788bdd1243dSDimitry Andric   ctx.config.mustMatch[k] = {v, source};
7890b57cec5SDimitry Andric }
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric // Convert Windows resource files (.res files) to a .obj file.
7920b57cec5SDimitry Andric // Does what cvtres.exe does, but in-process and cross-platform.
convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,ArrayRef<ObjFile * > objs)793bdd1243dSDimitry Andric MemoryBufferRef LinkerDriver::convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
79485868e8aSDimitry Andric                                                ArrayRef<ObjFile *> objs) {
795bdd1243dSDimitry Andric   object::WindowsResourceParser parser(/* MinGW */ ctx.config.mingw);
7960b57cec5SDimitry Andric 
79785868e8aSDimitry Andric   std::vector<std::string> duplicates;
7980b57cec5SDimitry Andric   for (MemoryBufferRef mb : mbs) {
7990b57cec5SDimitry Andric     std::unique_ptr<object::Binary> bin = check(object::createBinary(mb));
8000b57cec5SDimitry Andric     object::WindowsResource *rf = dyn_cast<object::WindowsResource>(bin.get());
8010b57cec5SDimitry Andric     if (!rf)
8020b57cec5SDimitry Andric       fatal("cannot compile non-resource file as resource");
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric     if (auto ec = parser.parse(rf, duplicates))
8050b57cec5SDimitry Andric       fatal(toString(std::move(ec)));
80685868e8aSDimitry Andric   }
80785868e8aSDimitry Andric 
80885868e8aSDimitry Andric   // Note: This processes all .res files before all objs. Ideally they'd be
80985868e8aSDimitry Andric   // handled in the same order they were linked (to keep the right one, if
81085868e8aSDimitry Andric   // there are duplicates that are tolerated due to forceMultipleRes).
81185868e8aSDimitry Andric   for (ObjFile *f : objs) {
81285868e8aSDimitry Andric     object::ResourceSectionRef rsf;
81385868e8aSDimitry Andric     if (auto ec = rsf.load(f->getCOFFObj()))
81485868e8aSDimitry Andric       fatal(toString(f) + ": " + toString(std::move(ec)));
81585868e8aSDimitry Andric 
81685868e8aSDimitry Andric     if (auto ec = parser.parse(rsf, f->getName(), duplicates))
81785868e8aSDimitry Andric       fatal(toString(std::move(ec)));
81885868e8aSDimitry Andric   }
81985868e8aSDimitry Andric 
820bdd1243dSDimitry Andric   if (ctx.config.mingw)
82185868e8aSDimitry Andric     parser.cleanUpManifests(duplicates);
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric   for (const auto &dupeDiag : duplicates)
824bdd1243dSDimitry Andric     if (ctx.config.forceMultipleRes)
8250b57cec5SDimitry Andric       warn(dupeDiag);
8260b57cec5SDimitry Andric     else
8270b57cec5SDimitry Andric       error(dupeDiag);
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric   Expected<std::unique_ptr<MemoryBuffer>> e =
830bdd1243dSDimitry Andric       llvm::object::writeWindowsResourceCOFF(ctx.config.machine, parser,
831bdd1243dSDimitry Andric                                              ctx.config.timestamp);
8320b57cec5SDimitry Andric   if (!e)
8330b57cec5SDimitry Andric     fatal("failed to write .res to COFF: " + toString(e.takeError()));
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric   MemoryBufferRef mbref = **e;
8360b57cec5SDimitry Andric   make<std::unique_ptr<MemoryBuffer>>(std::move(*e)); // take ownership
8370b57cec5SDimitry Andric   return mbref;
8380b57cec5SDimitry Andric }
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric // Create OptTable
8410b57cec5SDimitry Andric 
8420b57cec5SDimitry Andric // Create prefix string literals used in Options.td
843bdd1243dSDimitry Andric #define PREFIX(NAME, VALUE)                                                    \
844bdd1243dSDimitry Andric   static constexpr llvm::StringLiteral NAME##_init[] = VALUE;                  \
845bdd1243dSDimitry Andric   static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME(                   \
846bdd1243dSDimitry Andric       NAME##_init, std::size(NAME##_init) - 1);
8470b57cec5SDimitry Andric #include "Options.inc"
8480b57cec5SDimitry Andric #undef PREFIX
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric // Create table mapping all options defined in Options.td
851bdd1243dSDimitry Andric static constexpr llvm::opt::OptTable::Info infoTable[] = {
8525f757f3fSDimitry Andric #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
8530b57cec5SDimitry Andric #include "Options.inc"
8540b57cec5SDimitry Andric #undef OPTION
8550b57cec5SDimitry Andric };
8560b57cec5SDimitry Andric 
COFFOptTable()857bdd1243dSDimitry Andric COFFOptTable::COFFOptTable() : GenericOptTable(infoTable, true) {}
8585ffd83dbSDimitry Andric 
8590b57cec5SDimitry Andric // Set color diagnostics according to --color-diagnostics={auto,always,never}
8600b57cec5SDimitry Andric // or --no-color-diagnostics flags.
handleColorDiagnostics(opt::InputArgList & args)8610b57cec5SDimitry Andric static void handleColorDiagnostics(opt::InputArgList &args) {
8620b57cec5SDimitry Andric   auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
8630b57cec5SDimitry Andric                               OPT_no_color_diagnostics);
8640b57cec5SDimitry Andric   if (!arg)
8650b57cec5SDimitry Andric     return;
8660b57cec5SDimitry Andric   if (arg->getOption().getID() == OPT_color_diagnostics) {
867480093f4SDimitry Andric     lld::errs().enable_colors(true);
8680b57cec5SDimitry Andric   } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
869480093f4SDimitry Andric     lld::errs().enable_colors(false);
8700b57cec5SDimitry Andric   } else {
8710b57cec5SDimitry Andric     StringRef s = arg->getValue();
8720b57cec5SDimitry Andric     if (s == "always")
873480093f4SDimitry Andric       lld::errs().enable_colors(true);
8740b57cec5SDimitry Andric     else if (s == "never")
875480093f4SDimitry Andric       lld::errs().enable_colors(false);
8760b57cec5SDimitry Andric     else if (s != "auto")
8770b57cec5SDimitry Andric       error("unknown option: --color-diagnostics=" + s);
8780b57cec5SDimitry Andric   }
8790b57cec5SDimitry Andric }
8800b57cec5SDimitry Andric 
getQuotingStyle(opt::InputArgList & args)8810b57cec5SDimitry Andric static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
8820b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
8830b57cec5SDimitry Andric     StringRef s = arg->getValue();
8840b57cec5SDimitry Andric     if (s != "windows" && s != "posix")
8850b57cec5SDimitry Andric       error("invalid response file quoting: " + s);
8860b57cec5SDimitry Andric     if (s == "windows")
8870b57cec5SDimitry Andric       return cl::TokenizeWindowsCommandLine;
8880b57cec5SDimitry Andric     return cl::TokenizeGNUCommandLine;
8890b57cec5SDimitry Andric   }
8900b57cec5SDimitry Andric   // The COFF linker always defaults to Windows quoting.
8910b57cec5SDimitry Andric   return cl::TokenizeWindowsCommandLine;
8920b57cec5SDimitry Andric }
8930b57cec5SDimitry Andric 
ArgParser(COFFLinkerContext & c)894bdd1243dSDimitry Andric ArgParser::ArgParser(COFFLinkerContext &c) : ctx(c) {}
895bdd1243dSDimitry Andric 
8960b57cec5SDimitry Andric // Parses a given list of options.
parse(ArrayRef<const char * > argv)8970b57cec5SDimitry Andric opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
8980b57cec5SDimitry Andric   // Make InputArgList from string vectors.
8990b57cec5SDimitry Andric   unsigned missingIndex;
9000b57cec5SDimitry Andric   unsigned missingCount;
9010b57cec5SDimitry Andric 
9020b57cec5SDimitry Andric   // We need to get the quoting style for response files before parsing all
9030b57cec5SDimitry Andric   // options so we parse here before and ignore all the options but
90485868e8aSDimitry Andric   // --rsp-quoting and /lldignoreenv.
90585868e8aSDimitry Andric   // (This means --rsp-quoting can't be added through %LINK%.)
906bdd1243dSDimitry Andric   opt::InputArgList args =
907bdd1243dSDimitry Andric       ctx.optTable.ParseArgs(argv, missingIndex, missingCount);
90885868e8aSDimitry Andric 
90985868e8aSDimitry Andric   // Expand response files (arguments in the form of @<filename>) and insert
91085868e8aSDimitry Andric   // flags from %LINK% and %_LINK_%, and then parse the argument again.
9110b57cec5SDimitry Andric   SmallVector<const char *, 256> expandedArgv(argv.data(),
9120b57cec5SDimitry Andric                                               argv.data() + argv.size());
91385868e8aSDimitry Andric   if (!args.hasArg(OPT_lldignoreenv))
91485868e8aSDimitry Andric     addLINK(expandedArgv);
91504eeddc0SDimitry Andric   cl::ExpandResponseFiles(saver(), getQuotingStyle(args), expandedArgv);
916bdd1243dSDimitry Andric   args = ctx.optTable.ParseArgs(ArrayRef(expandedArgv).drop_front(),
9175ffd83dbSDimitry Andric                                 missingIndex, missingCount);
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric   // Print the real command line if response files are expanded.
9200b57cec5SDimitry Andric   if (args.hasArg(OPT_verbose) && argv.size() != expandedArgv.size()) {
9210b57cec5SDimitry Andric     std::string msg = "Command line:";
9220b57cec5SDimitry Andric     for (const char *s : expandedArgv)
9230b57cec5SDimitry Andric       msg += " " + std::string(s);
9240b57cec5SDimitry Andric     message(msg);
9250b57cec5SDimitry Andric   }
9260b57cec5SDimitry Andric 
9270b57cec5SDimitry Andric   // Save the command line after response file expansion so we can write it to
928bdd1243dSDimitry Andric   // the PDB if necessary. Mimic MSVC, which skips input files.
929bdd1243dSDimitry Andric   ctx.config.argv = {argv[0]};
930bdd1243dSDimitry Andric   for (opt::Arg *arg : args) {
931bdd1243dSDimitry Andric     if (arg->getOption().getKind() != opt::Option::InputClass) {
93206c3fb27SDimitry Andric       ctx.config.argv.emplace_back(args.getArgString(arg->getIndex()));
933bdd1243dSDimitry Andric     }
934bdd1243dSDimitry Andric   }
9350b57cec5SDimitry Andric 
9360b57cec5SDimitry Andric   // Handle /WX early since it converts missing argument warnings to errors.
9370b57cec5SDimitry Andric   errorHandler().fatalWarnings = args.hasFlag(OPT_WX, OPT_WX_no, false);
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric   if (missingCount)
9400b57cec5SDimitry Andric     fatal(Twine(args.getArgString(missingIndex)) + ": missing argument");
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   handleColorDiagnostics(args);
9430b57cec5SDimitry Andric 
944e8d8bef9SDimitry Andric   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
9450b57cec5SDimitry Andric     std::string nearest;
946bdd1243dSDimitry Andric     if (ctx.optTable.findNearest(arg->getAsString(args), nearest) > 1)
9470b57cec5SDimitry Andric       warn("ignoring unknown argument '" + arg->getAsString(args) + "'");
9480b57cec5SDimitry Andric     else
9490b57cec5SDimitry Andric       warn("ignoring unknown argument '" + arg->getAsString(args) +
9500b57cec5SDimitry Andric            "', did you mean '" + nearest + "'");
9510b57cec5SDimitry Andric   }
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric   if (args.hasArg(OPT_lib))
9540b57cec5SDimitry Andric     warn("ignoring /lib since it's not the first argument");
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric   return args;
9570b57cec5SDimitry Andric }
9580b57cec5SDimitry Andric 
9590b57cec5SDimitry Andric // Tokenizes and parses a given string as command line in .drective section.
parseDirectives(StringRef s)9605ffd83dbSDimitry Andric ParsedDirectives ArgParser::parseDirectives(StringRef s) {
9615ffd83dbSDimitry Andric   ParsedDirectives result;
9620b57cec5SDimitry Andric   SmallVector<const char *, 16> rest;
9630b57cec5SDimitry Andric 
9645ffd83dbSDimitry Andric   // Handle /EXPORT and /INCLUDE in a fast path. These directives can appear for
9655ffd83dbSDimitry Andric   // potentially every symbol in the object, so they must be handled quickly.
9665ffd83dbSDimitry Andric   SmallVector<StringRef, 16> tokens;
96704eeddc0SDimitry Andric   cl::TokenizeWindowsCommandLineNoCopy(s, saver(), tokens);
9685ffd83dbSDimitry Andric   for (StringRef tok : tokens) {
96906c3fb27SDimitry Andric     if (tok.starts_with_insensitive("/export:") ||
97006c3fb27SDimitry Andric         tok.starts_with_insensitive("-export:"))
9715ffd83dbSDimitry Andric       result.exports.push_back(tok.substr(strlen("/export:")));
97206c3fb27SDimitry Andric     else if (tok.starts_with_insensitive("/include:") ||
97306c3fb27SDimitry Andric              tok.starts_with_insensitive("-include:"))
9745ffd83dbSDimitry Andric       result.includes.push_back(tok.substr(strlen("/include:")));
97506c3fb27SDimitry Andric     else if (tok.starts_with_insensitive("/exclude-symbols:") ||
97606c3fb27SDimitry Andric              tok.starts_with_insensitive("-exclude-symbols:"))
97761cfbce3SDimitry Andric       result.excludes.push_back(tok.substr(strlen("/exclude-symbols:")));
9785ffd83dbSDimitry Andric     else {
979e8d8bef9SDimitry Andric       // Copy substrings that are not valid C strings. The tokenizer may have
980e8d8bef9SDimitry Andric       // already copied quoted arguments for us, so those do not need to be
981e8d8bef9SDimitry Andric       // copied again.
982e8d8bef9SDimitry Andric       bool HasNul = tok.end() != s.end() && tok.data()[tok.size()] == '\0';
98304eeddc0SDimitry Andric       rest.push_back(HasNul ? tok.data() : saver().save(tok).data());
9845ffd83dbSDimitry Andric     }
9850b57cec5SDimitry Andric   }
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric   // Make InputArgList from unparsed string vectors.
9880b57cec5SDimitry Andric   unsigned missingIndex;
9890b57cec5SDimitry Andric   unsigned missingCount;
9900b57cec5SDimitry Andric 
991bdd1243dSDimitry Andric   result.args = ctx.optTable.ParseArgs(rest, missingIndex, missingCount);
9920b57cec5SDimitry Andric 
9930b57cec5SDimitry Andric   if (missingCount)
9945ffd83dbSDimitry Andric     fatal(Twine(result.args.getArgString(missingIndex)) + ": missing argument");
9955ffd83dbSDimitry Andric   for (auto *arg : result.args.filtered(OPT_UNKNOWN))
9965ffd83dbSDimitry Andric     warn("ignoring unknown argument: " + arg->getAsString(result.args));
9975ffd83dbSDimitry Andric   return result;
9980b57cec5SDimitry Andric }
9990b57cec5SDimitry Andric 
10000b57cec5SDimitry Andric // link.exe has an interesting feature. If LINK or _LINK_ environment
10010b57cec5SDimitry Andric // variables exist, their contents are handled as command line strings.
10020b57cec5SDimitry Andric // So you can pass extra arguments using them.
addLINK(SmallVector<const char *,256> & argv)100385868e8aSDimitry Andric void ArgParser::addLINK(SmallVector<const char *, 256> &argv) {
10040b57cec5SDimitry Andric   // Concatenate LINK env and command line arguments, and then parse them.
1005bdd1243dSDimitry Andric   if (std::optional<std::string> s = Process::GetEnv("LINK")) {
10060b57cec5SDimitry Andric     std::vector<const char *> v = tokenize(*s);
10070b57cec5SDimitry Andric     argv.insert(std::next(argv.begin()), v.begin(), v.end());
10080b57cec5SDimitry Andric   }
1009bdd1243dSDimitry Andric   if (std::optional<std::string> s = Process::GetEnv("_LINK_")) {
10100b57cec5SDimitry Andric     std::vector<const char *> v = tokenize(*s);
10110b57cec5SDimitry Andric     argv.insert(std::next(argv.begin()), v.begin(), v.end());
10120b57cec5SDimitry Andric   }
10130b57cec5SDimitry Andric }
10140b57cec5SDimitry Andric 
tokenize(StringRef s)10150b57cec5SDimitry Andric std::vector<const char *> ArgParser::tokenize(StringRef s) {
10160b57cec5SDimitry Andric   SmallVector<const char *, 16> tokens;
101704eeddc0SDimitry Andric   cl::TokenizeWindowsCommandLine(s, saver(), tokens);
10180b57cec5SDimitry Andric   return std::vector<const char *>(tokens.begin(), tokens.end());
10190b57cec5SDimitry Andric }
10200b57cec5SDimitry Andric 
printHelp(const char * argv0)1021bdd1243dSDimitry Andric void LinkerDriver::printHelp(const char *argv0) {
1022bdd1243dSDimitry Andric   ctx.optTable.printHelp(lld::outs(),
10230b57cec5SDimitry Andric                          (std::string(argv0) + " [options] file...").c_str(),
10240b57cec5SDimitry Andric                          "LLVM Linker", false);
10250b57cec5SDimitry Andric }
10260b57cec5SDimitry Andric 
10270b57cec5SDimitry Andric } // namespace coff
10280b57cec5SDimitry Andric } // namespace lld
1029