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: 5704eeddc0SDimitry Andric explicit Executor(StringRef s) : prog(saver().save(s)) {} 5804eeddc0SDimitry Andric void add(StringRef s) { args.push_back(saver().save(s)); } 5904eeddc0SDimitry Andric void add(std::string &s) { args.push_back(saver().save(s)); } 6004eeddc0SDimitry Andric void add(Twine s) { args.push_back(saver().save(s)); } 6104eeddc0SDimitry Andric void add(const char *s) { args.push_back(saver().save(s)); } 620b57cec5SDimitry Andric 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>]". 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. 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 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>]]". 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. 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. 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 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 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. 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. 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. 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. 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. 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. 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. 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: 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 36606c3fb27SDimitry Andric TemporaryFile(TemporaryFile &&obj) noexcept { std::swap(path, obj.path); } 3670b57cec5SDimitry Andric 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.) 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 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 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 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 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> 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 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 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. 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 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. 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.) 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 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. 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 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. 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. 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 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. 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 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 894bdd1243dSDimitry Andric ArgParser::ArgParser(COFFLinkerContext &c) : ctx(c) {} 895bdd1243dSDimitry Andric 8960b57cec5SDimitry Andric // Parses a given list of options. 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. 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. 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 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 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