2015-05-29 04:30:06 +08:00
|
|
|
//===- DriverUtils.cpp ----------------------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-05-29 04:30:06 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file contains utility functions for the driver. Because there
|
|
|
|
// are so many small functions, we created this separate file to make
|
|
|
|
// Driver.cpp less cluttered.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-06-05 03:21:24 +08:00
|
|
|
#include "Config.h"
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "Driver.h"
|
2015-07-16 06:21:08 +08:00
|
|
|
#include "Symbols.h"
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2017-11-29 04:39:17 +08:00
|
|
|
#include "lld/Common/Memory.h"
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "llvm/ADT/Optional.h"
|
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2017-07-08 11:06:10 +08:00
|
|
|
#include "llvm/BinaryFormat/COFF.h"
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "llvm/Object/COFF.h"
|
2017-07-08 11:06:10 +08:00
|
|
|
#include "llvm/Object/WindowsResource.h"
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "llvm/Option/Arg.h"
|
|
|
|
#include "llvm/Option/ArgList.h"
|
|
|
|
#include "llvm/Option/Option.h"
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
2015-06-18 04:40:43 +08:00
|
|
|
#include "llvm/Support/FileUtilities.h"
|
2017-07-08 11:06:10 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "llvm/Support/Process.h"
|
2015-06-15 05:50:50 +08:00
|
|
|
#include "llvm/Support/Program.h"
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-08-22 11:15:28 +08:00
|
|
|
#include "llvm/WindowsManifest/WindowsManifestMerger.h"
|
2020-08-27 19:48:22 +08:00
|
|
|
#include <limits>
|
2015-05-29 04:30:06 +08:00
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
using namespace llvm::COFF;
|
|
|
|
using namespace llvm;
|
|
|
|
using llvm::sys::Process;
|
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
namespace coff {
|
2015-06-18 05:01:56 +08:00
|
|
|
namespace {
|
|
|
|
|
2017-07-08 11:06:10 +08:00
|
|
|
const uint16_t SUBLANG_ENGLISH_US = 0x0409;
|
|
|
|
const uint16_t RT_MANIFEST = 24;
|
|
|
|
|
2015-06-18 05:01:56 +08:00
|
|
|
class Executor {
|
|
|
|
public:
|
2022-01-21 03:53:18 +08:00
|
|
|
explicit Executor(StringRef s) : prog(saver().save(s)) {}
|
|
|
|
void add(StringRef s) { args.push_back(saver().save(s)); }
|
|
|
|
void add(std::string &s) { args.push_back(saver().save(s)); }
|
|
|
|
void add(Twine s) { args.push_back(saver().save(s)); }
|
|
|
|
void add(const char *s) { args.push_back(saver().save(s)); }
|
2015-06-18 05:01:56 +08:00
|
|
|
|
2015-08-06 22:58:50 +08:00
|
|
|
void run() {
|
2016-12-09 04:50:47 +08:00
|
|
|
ErrorOr<std::string> exeOrErr = sys::findProgramByName(prog);
|
2016-07-15 08:40:46 +08:00
|
|
|
if (auto ec = exeOrErr.getError())
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("unable to find " + prog + " in PATH: " + ec.message());
|
2022-01-21 03:53:18 +08:00
|
|
|
StringRef exe = saver().save(*exeOrErr);
|
2015-06-18 05:01:56 +08:00
|
|
|
args.insert(args.begin(), exe);
|
2017-02-22 07:22:56 +08:00
|
|
|
|
2018-06-13 01:43:52 +08:00
|
|
|
if (sys::ExecuteAndWait(args[0], args) != 0)
|
2017-02-22 07:22:56 +08:00
|
|
|
fatal("ExecuteAndWait failed: " +
|
|
|
|
llvm::join(args.begin(), args.end(), " "));
|
2015-06-18 05:01:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
StringRef prog;
|
2017-02-22 07:22:56 +08:00
|
|
|
std::vector<StringRef> args;
|
2015-06-18 05:01:56 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
2015-05-29 04:30:06 +08:00
|
|
|
|
2015-05-30 00:18:15 +08:00
|
|
|
// Parses a string in the form of "<integer>[,<integer>]".
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {
|
2015-05-30 00:18:15 +08:00
|
|
|
StringRef s1, s2;
|
|
|
|
std::tie(s1, s2) = arg.split(',');
|
2015-08-06 22:58:50 +08:00
|
|
|
if (s1.getAsInteger(0, *addr))
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("invalid number: " + s1);
|
2015-08-06 22:58:50 +08:00
|
|
|
if (size && !s2.empty() && s2.getAsInteger(0, *size))
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("invalid number: " + s2);
|
2015-05-30 00:18:15 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 00:28:29 +08:00
|
|
|
// Parses a string in the form of "<integer>[.<integer>]".
|
|
|
|
// If second number is not present, Minor is set to 0.
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor) {
|
2015-05-30 00:28:29 +08:00
|
|
|
StringRef s1, s2;
|
|
|
|
std::tie(s1, s2) = arg.split('.');
|
2020-10-04 06:19:41 +08:00
|
|
|
if (s1.getAsInteger(10, *major))
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("invalid number: " + s1);
|
2015-05-30 00:28:29 +08:00
|
|
|
*minor = 0;
|
2020-10-04 06:19:41 +08:00
|
|
|
if (!s2.empty() && s2.getAsInteger(10, *minor))
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("invalid number: " + s2);
|
2015-05-30 00:28:29 +08:00
|
|
|
}
|
2019-07-11 13:40:30 +08:00
|
|
|
|
2018-02-14 04:32:53 +08:00
|
|
|
void parseGuard(StringRef fullArg) {
|
|
|
|
SmallVector<StringRef, 1> splitArgs;
|
|
|
|
fullArg.split(splitArgs, ",");
|
|
|
|
for (StringRef arg : splitArgs) {
|
2021-06-24 16:06:35 +08:00
|
|
|
if (arg.equals_insensitive("no"))
|
2018-02-14 04:32:53 +08:00
|
|
|
config->guardCF = GuardCFLevel::Off;
|
2021-06-24 16:06:35 +08:00
|
|
|
else if (arg.equals_insensitive("nolongjmp"))
|
2021-04-14 14:21:52 +08:00
|
|
|
config->guardCF &= ~GuardCFLevel::LongJmp;
|
2021-06-24 16:06:35 +08:00
|
|
|
else if (arg.equals_insensitive("noehcont"))
|
2021-04-14 14:21:52 +08:00
|
|
|
config->guardCF &= ~GuardCFLevel::EHCont;
|
2021-06-24 16:06:35 +08:00
|
|
|
else if (arg.equals_insensitive("cf"))
|
2021-04-14 14:21:52 +08:00
|
|
|
config->guardCF = GuardCFLevel::CF;
|
2021-06-24 16:06:35 +08:00
|
|
|
else if (arg.equals_insensitive("longjmp"))
|
2021-04-14 14:21:52 +08:00
|
|
|
config->guardCF |= GuardCFLevel::CF | GuardCFLevel::LongJmp;
|
2021-06-24 16:06:35 +08:00
|
|
|
else if (arg.equals_insensitive("ehcont"))
|
2021-04-14 14:21:52 +08:00
|
|
|
config->guardCF |= GuardCFLevel::CF | GuardCFLevel::EHCont;
|
2018-02-14 04:32:53 +08:00
|
|
|
else
|
2018-03-12 20:45:40 +08:00
|
|
|
fatal("invalid argument to /guard: " + arg);
|
2018-02-14 04:32:53 +08:00
|
|
|
}
|
2018-02-06 09:58:26 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 00:34:31 +08:00
|
|
|
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
|
2020-10-04 06:29:45 +08:00
|
|
|
uint32_t *minor, bool *gotVersion) {
|
2015-05-30 00:34:31 +08:00
|
|
|
StringRef sysStr, ver;
|
|
|
|
std::tie(sysStr, ver) = arg.split(',');
|
2019-06-15 01:50:29 +08:00
|
|
|
std::string sysStrLower = sysStr.lower();
|
|
|
|
*sys = StringSwitch<WindowsSubsystem>(sysStrLower)
|
2015-05-30 00:34:31 +08:00
|
|
|
.Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
|
|
|
|
.Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
|
2019-06-15 01:50:29 +08:00
|
|
|
.Case("default", IMAGE_SUBSYSTEM_UNKNOWN)
|
2015-05-30 00:34:31 +08:00
|
|
|
.Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)
|
|
|
|
.Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
|
|
|
|
.Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)
|
|
|
|
.Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
|
|
|
|
.Case("native", IMAGE_SUBSYSTEM_NATIVE)
|
|
|
|
.Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
|
|
|
|
.Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
|
|
|
.Default(IMAGE_SUBSYSTEM_UNKNOWN);
|
2019-06-15 01:50:29 +08:00
|
|
|
if (*sys == IMAGE_SUBSYSTEM_UNKNOWN && sysStrLower != "default")
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("unknown subsystem: " + sysStr);
|
2015-05-30 00:34:31 +08:00
|
|
|
if (!ver.empty())
|
2015-08-06 22:58:50 +08:00
|
|
|
parseVersion(ver, major, minor);
|
2020-10-04 06:29:45 +08:00
|
|
|
if (gotVersion)
|
|
|
|
*gotVersion = !ver.empty();
|
2015-06-19 03:09:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse a string of the form of "<from>=<to>".
|
|
|
|
// Results are directly written to Config.
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseAlternateName(StringRef s) {
|
2015-06-19 03:09:30 +08:00
|
|
|
StringRef from, to;
|
|
|
|
std::tie(from, to) = s.split('=');
|
2015-08-06 22:58:50 +08:00
|
|
|
if (from.empty() || to.empty())
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("/alternatename: invalid argument: " + s);
|
2015-06-19 07:04:26 +08:00
|
|
|
auto it = config->alternateNames.find(from);
|
2015-08-06 22:58:50 +08:00
|
|
|
if (it != config->alternateNames.end() && it->second != to)
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("/alternatename: conflicts: " + s);
|
2015-06-19 07:04:26 +08:00
|
|
|
config->alternateNames.insert(it, std::make_pair(from, to));
|
2015-05-30 00:34:31 +08:00
|
|
|
}
|
|
|
|
|
2015-07-05 07:37:32 +08:00
|
|
|
// Parse a string of the form of "<from>=<to>".
|
|
|
|
// Results are directly written to Config.
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseMerge(StringRef s) {
|
2015-07-05 07:37:32 +08:00
|
|
|
StringRef from, to;
|
|
|
|
std::tie(from, to) = s.split('=');
|
2015-08-06 22:58:50 +08:00
|
|
|
if (from.empty() || to.empty())
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("/merge: invalid argument: " + s);
|
2018-04-07 08:46:55 +08:00
|
|
|
if (from == ".rsrc" || to == ".rsrc")
|
|
|
|
fatal("/merge: cannot merge '.rsrc' with any section");
|
|
|
|
if (from == ".reloc" || to == ".reloc")
|
|
|
|
fatal("/merge: cannot merge '.reloc' with any section");
|
2015-07-05 07:37:32 +08:00
|
|
|
auto pair = config->merge.insert(std::make_pair(from, to));
|
|
|
|
bool inserted = pair.second;
|
2015-07-05 07:54:52 +08:00
|
|
|
if (!inserted) {
|
|
|
|
StringRef existing = pair.first->second;
|
|
|
|
if (existing != to)
|
2017-02-22 07:22:56 +08:00
|
|
|
warn(s + ": already merged into " + existing);
|
2015-07-05 07:54:52 +08:00
|
|
|
}
|
2015-07-05 07:37:32 +08:00
|
|
|
}
|
|
|
|
|
2021-10-30 23:22:55 +08:00
|
|
|
void parsePDBPageSize(StringRef s) {
|
|
|
|
int v;
|
|
|
|
if (s.getAsInteger(0, v)) {
|
|
|
|
error("/pdbpagesize: invalid argument: " + s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (v != 4096 && v != 8192 && v != 16384 && v != 32768) {
|
|
|
|
error("/pdbpagesize: invalid argument: " + s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
config->pdbPageSize = v;
|
|
|
|
}
|
|
|
|
|
2016-06-20 11:39:39 +08:00
|
|
|
static uint32_t parseSectionAttributes(StringRef s) {
|
|
|
|
uint32_t ret = 0;
|
|
|
|
for (char c : s.lower()) {
|
|
|
|
switch (c) {
|
|
|
|
case 'd':
|
|
|
|
ret |= IMAGE_SCN_MEM_DISCARDABLE;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
ret |= IMAGE_SCN_MEM_EXECUTE;
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
ret |= IMAGE_SCN_MEM_NOT_CACHED;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
ret |= IMAGE_SCN_MEM_NOT_PAGED;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
ret |= IMAGE_SCN_MEM_READ;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
ret |= IMAGE_SCN_MEM_SHARED;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
ret |= IMAGE_SCN_MEM_WRITE;
|
|
|
|
break;
|
|
|
|
default:
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("/section: invalid argument: " + s);
|
2016-06-20 11:39:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parses /section option argument.
|
|
|
|
void parseSection(StringRef s) {
|
|
|
|
StringRef name, attrs;
|
|
|
|
std::tie(name, attrs) = s.split(',');
|
|
|
|
if (name.empty() || attrs.empty())
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("/section: invalid argument: " + s);
|
2016-06-20 11:39:39 +08:00
|
|
|
config->section[name] = parseSectionAttributes(attrs);
|
|
|
|
}
|
|
|
|
|
2017-08-15 03:07:27 +08:00
|
|
|
// Parses /aligncomm option argument.
|
|
|
|
void parseAligncomm(StringRef s) {
|
|
|
|
StringRef name, align;
|
|
|
|
std::tie(name, align) = s.split(',');
|
|
|
|
if (name.empty() || align.empty()) {
|
|
|
|
error("/aligncomm: invalid argument: " + s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int v;
|
|
|
|
if (align.getAsInteger(0, v)) {
|
|
|
|
error("/aligncomm: invalid argument: " + s);
|
|
|
|
return;
|
|
|
|
}
|
2020-01-29 03:23:46 +08:00
|
|
|
config->alignComm[std::string(name)] =
|
|
|
|
std::max(config->alignComm[std::string(name)], 1 << v);
|
2017-08-15 03:07:27 +08:00
|
|
|
}
|
|
|
|
|
2019-02-23 09:46:18 +08:00
|
|
|
// Parses /functionpadmin option argument.
|
|
|
|
void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine) {
|
|
|
|
StringRef arg = a->getNumValues() ? a->getValue() : "";
|
|
|
|
if (!arg.empty()) {
|
|
|
|
// Optional padding in bytes is given.
|
|
|
|
if (arg.getAsInteger(0, config->functionPadMin))
|
|
|
|
error("/functionpadmin: invalid argument: " + arg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// No optional argument given.
|
|
|
|
// Set default padding based on machine, similar to link.exe.
|
|
|
|
// There is no default padding for ARM platforms.
|
|
|
|
if (machine == I386) {
|
|
|
|
config->functionPadMin = 5;
|
|
|
|
} else if (machine == AMD64) {
|
|
|
|
config->functionPadMin = 6;
|
|
|
|
} else {
|
|
|
|
error("/functionpadmin: invalid argument for this machine: " + arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-18 08:12:42 +08:00
|
|
|
// Parses a string in the form of "EMBED[,=<integer>]|NO".
|
|
|
|
// Results are directly written to Config.
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseManifest(StringRef arg) {
|
2021-06-24 16:06:35 +08:00
|
|
|
if (arg.equals_insensitive("no")) {
|
2015-06-18 08:12:42 +08:00
|
|
|
config->manifest = Configuration::No;
|
2015-08-06 22:58:50 +08:00
|
|
|
return;
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
2021-06-24 16:06:35 +08:00
|
|
|
if (!arg.startswith_insensitive("embed"))
|
2016-07-15 09:12:24 +08:00
|
|
|
fatal("invalid option " + arg);
|
2015-06-18 08:12:42 +08:00
|
|
|
config->manifest = Configuration::Embed;
|
|
|
|
arg = arg.substr(strlen("embed"));
|
|
|
|
if (arg.empty())
|
2015-08-06 22:58:50 +08:00
|
|
|
return;
|
2021-06-24 16:06:35 +08:00
|
|
|
if (!arg.startswith_insensitive(",id="))
|
2016-07-15 09:12:24 +08:00
|
|
|
fatal("invalid option " + arg);
|
2015-06-18 08:12:42 +08:00
|
|
|
arg = arg.substr(strlen(",id="));
|
|
|
|
if (arg.getAsInteger(0, config->manifestID))
|
2016-07-15 09:12:24 +08:00
|
|
|
fatal("invalid option " + arg);
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
|
|
|
|
// Results are directly written to Config.
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseManifestUAC(StringRef arg) {
|
2021-06-24 16:06:35 +08:00
|
|
|
if (arg.equals_insensitive("no")) {
|
2015-06-18 08:12:42 +08:00
|
|
|
config->manifestUAC = false;
|
2015-08-06 22:58:50 +08:00
|
|
|
return;
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
arg = arg.ltrim();
|
|
|
|
if (arg.empty())
|
2015-08-06 22:58:50 +08:00
|
|
|
return;
|
2021-06-24 16:06:35 +08:00
|
|
|
if (arg.startswith_insensitive("level=")) {
|
2015-06-18 08:12:42 +08:00
|
|
|
arg = arg.substr(strlen("level="));
|
|
|
|
std::tie(config->manifestLevel, arg) = arg.split(" ");
|
|
|
|
continue;
|
|
|
|
}
|
2021-06-24 16:06:35 +08:00
|
|
|
if (arg.startswith_insensitive("uiaccess=")) {
|
2015-06-18 08:12:42 +08:00
|
|
|
arg = arg.substr(strlen("uiaccess="));
|
|
|
|
std::tie(config->manifestUIAccess, arg) = arg.split(" ");
|
|
|
|
continue;
|
|
|
|
}
|
2016-07-15 09:12:24 +08:00
|
|
|
fatal("invalid option " + arg);
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-25 22:02:26 +08:00
|
|
|
// Parses a string in the form of "cd|net[,(cd|net)]*"
|
|
|
|
// Results are directly written to Config.
|
|
|
|
void parseSwaprun(StringRef arg) {
|
|
|
|
do {
|
|
|
|
StringRef swaprun, newArg;
|
|
|
|
std::tie(swaprun, newArg) = arg.split(',');
|
2021-06-24 16:06:35 +08:00
|
|
|
if (swaprun.equals_insensitive("cd"))
|
2019-04-25 22:02:26 +08:00
|
|
|
config->swaprunCD = true;
|
2021-06-24 16:06:35 +08:00
|
|
|
else if (swaprun.equals_insensitive("net"))
|
2019-04-25 22:02:26 +08:00
|
|
|
config->swaprunNet = true;
|
|
|
|
else if (swaprun.empty())
|
|
|
|
error("/swaprun: missing argument");
|
|
|
|
else
|
|
|
|
error("/swaprun: invalid argument: " + swaprun);
|
|
|
|
// To catch trailing commas, e.g. `/spawrun:cd,`
|
|
|
|
if (newArg.empty() && arg.endswith(","))
|
|
|
|
error("/swaprun: missing argument");
|
|
|
|
arg = newArg;
|
|
|
|
} while (!arg.empty());
|
|
|
|
}
|
|
|
|
|
2016-09-03 01:34:17 +08:00
|
|
|
// An RAII temporary file class that automatically removes a temporary file.
|
|
|
|
namespace {
|
|
|
|
class TemporaryFile {
|
|
|
|
public:
|
2017-02-07 04:47:55 +08:00
|
|
|
TemporaryFile(StringRef prefix, StringRef extn, StringRef contents = "") {
|
2016-09-03 01:34:17 +08:00
|
|
|
SmallString<128> s;
|
|
|
|
if (auto ec = sys::fs::createTemporaryFile("lld-" + prefix, extn, s))
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("cannot create a temporary file: " + ec.message());
|
2020-01-29 03:23:46 +08:00
|
|
|
path = std::string(s.str());
|
2019-07-11 13:40:30 +08:00
|
|
|
|
2017-02-07 04:47:55 +08:00
|
|
|
if (!contents.empty()) {
|
|
|
|
std::error_code ec;
|
2019-08-05 13:43:48 +08:00
|
|
|
raw_fd_ostream os(path, ec, sys::fs::OF_None);
|
2017-02-07 04:47:55 +08:00
|
|
|
if (ec)
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("failed to open " + path + ": " + ec.message());
|
2017-02-07 04:47:55 +08:00
|
|
|
os << contents;
|
|
|
|
}
|
2016-09-03 01:34:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TemporaryFile(TemporaryFile &&obj) {
|
|
|
|
std::swap(path, obj.path);
|
|
|
|
}
|
|
|
|
|
|
|
|
~TemporaryFile() {
|
|
|
|
if (path.empty())
|
|
|
|
return;
|
|
|
|
if (sys::fs::remove(path))
|
|
|
|
fatal("failed to remove " + path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a memory buffer of this temporary file.
|
|
|
|
// Note that this function does not leave the file open,
|
|
|
|
// so it is safe to remove the file immediately after this function
|
|
|
|
// is called (you cannot remove an opened file on Windows.)
|
|
|
|
std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
|
2019-07-16 16:26:38 +08:00
|
|
|
// IsVolatile=true forces MemoryBuffer to not use mmap().
|
[NFC] Reordering parameters in getFile and getFileOrSTDIN
In future patches I will be setting the IsText parameter frequently so I will refactor the args to be in the following order. I have removed the FileSize parameter because it is never used.
```
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getFile(const Twine &Filename, bool IsText = false,
bool RequiresNullTerminator = true, bool IsVolatile = false);
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getFileOrSTDIN(const Twine &Filename, bool IsText = false,
bool RequiresNullTerminator = true);
static ErrorOr<std::unique_ptr<MB>>
getFileAux(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
bool IsText, bool RequiresNullTerminator, bool IsVolatile);
static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
getFile(const Twine &Filename, bool IsVolatile = false);
```
Reviewed By: jhenderson
Differential Revision: https://reviews.llvm.org/D99182
2021-03-25 21:47:25 +08:00
|
|
|
return CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
|
2016-09-03 01:34:17 +08:00
|
|
|
/*RequiresNullTerminator=*/false,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*IsVolatile=*/true),
|
2016-09-03 01:34:17 +08:00
|
|
|
"could not open " + path);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string path;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-08-22 11:15:28 +08:00
|
|
|
static std::string createDefaultXml() {
|
|
|
|
std::string ret;
|
|
|
|
raw_string_ostream os(ret);
|
2016-04-19 09:21:58 +08:00
|
|
|
|
2015-06-18 08:12:42 +08:00
|
|
|
// Emit the XML. Note that we do *not* verify that the XML attributes are
|
|
|
|
// syntactically correct. This is intentional for link.exe compatibility.
|
|
|
|
os << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
|
|
|
|
<< "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
|
|
|
|
<< " manifestVersion=\"1.0\">\n";
|
|
|
|
if (config->manifestUAC) {
|
|
|
|
os << " <trustInfo>\n"
|
|
|
|
<< " <security>\n"
|
|
|
|
<< " <requestedPrivileges>\n"
|
|
|
|
<< " <requestedExecutionLevel level=" << config->manifestLevel
|
|
|
|
<< " uiAccess=" << config->manifestUIAccess << "/>\n"
|
|
|
|
<< " </requestedPrivileges>\n"
|
|
|
|
<< " </security>\n"
|
|
|
|
<< " </trustInfo>\n";
|
2017-07-27 07:38:10 +08:00
|
|
|
}
|
2021-08-24 22:19:21 +08:00
|
|
|
for (auto manifestDependency : config->manifestDependencies) {
|
2017-07-27 07:38:10 +08:00
|
|
|
os << " <dependency>\n"
|
|
|
|
<< " <dependentAssembly>\n"
|
2021-08-24 22:19:21 +08:00
|
|
|
<< " <assemblyIdentity " << manifestDependency << " />\n"
|
2017-07-27 07:38:10 +08:00
|
|
|
<< " </dependentAssembly>\n"
|
|
|
|
<< " </dependency>\n";
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
|
|
|
os << "</assembly>\n";
|
2017-09-06 05:17:32 +08:00
|
|
|
return os.str();
|
2016-04-19 09:21:58 +08:00
|
|
|
}
|
|
|
|
|
2017-09-06 09:50:36 +08:00
|
|
|
static std::string createManifestXmlWithInternalMt(StringRef defaultXml) {
|
2017-08-22 11:15:28 +08:00
|
|
|
std::unique_ptr<MemoryBuffer> defaultXmlCopy =
|
|
|
|
MemoryBuffer::getMemBufferCopy(defaultXml);
|
|
|
|
|
|
|
|
windows_manifest::WindowsManifestMerger merger;
|
|
|
|
if (auto e = merger.merge(*defaultXmlCopy.get()))
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("internal manifest tool failed on default xml: " +
|
|
|
|
toString(std::move(e)));
|
2017-08-22 11:15:28 +08:00
|
|
|
|
|
|
|
for (StringRef filename : config->manifestInput) {
|
|
|
|
std::unique_ptr<MemoryBuffer> manifest =
|
|
|
|
check(MemoryBuffer::getFile(filename));
|
2021-08-24 22:19:21 +08:00
|
|
|
// Call takeBuffer to include in /reproduce: output if applicable.
|
|
|
|
if (auto e = merger.merge(driver->takeBuffer(std::move(manifest))))
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("internal manifest tool failed on file " + filename + ": " +
|
|
|
|
toString(std::move(e)));
|
2017-08-22 11:15:28 +08:00
|
|
|
}
|
|
|
|
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(merger.getMergedManifest().get()->getBuffer());
|
2016-04-19 09:21:58 +08:00
|
|
|
}
|
|
|
|
|
2017-09-06 09:50:36 +08:00
|
|
|
static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
|
2017-08-22 11:15:28 +08:00
|
|
|
// Create the default manifest file as a temporary file.
|
|
|
|
TemporaryFile Default("defaultxml", "manifest");
|
|
|
|
std::error_code ec;
|
2021-04-06 19:22:41 +08:00
|
|
|
raw_fd_ostream os(Default.path, ec, sys::fs::OF_TextWithCRLF);
|
2017-08-22 11:15:28 +08:00
|
|
|
if (ec)
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("failed to open " + Default.path + ": " + ec.message());
|
2017-08-22 11:15:28 +08:00
|
|
|
os << defaultXml;
|
|
|
|
os.close();
|
2016-04-19 09:21:58 +08:00
|
|
|
|
2017-08-22 11:15:28 +08:00
|
|
|
// Merge user-supplied manifests if they are given. Since libxml2 is not
|
|
|
|
// enabled, we must shell out to Microsoft's mt.exe tool.
|
|
|
|
TemporaryFile user("user", "manifest");
|
2016-04-19 09:21:58 +08:00
|
|
|
|
|
|
|
Executor e("mt.exe");
|
|
|
|
e.add("/manifest");
|
2017-08-22 11:15:28 +08:00
|
|
|
e.add(Default.path);
|
2016-04-19 09:21:58 +08:00
|
|
|
for (StringRef filename : config->manifestInput) {
|
|
|
|
e.add("/manifest");
|
|
|
|
e.add(filename);
|
2021-08-24 22:19:21 +08:00
|
|
|
|
|
|
|
// Manually add the file to the /reproduce: tar if needed.
|
|
|
|
if (driver->tar)
|
|
|
|
if (auto mbOrErr = MemoryBuffer::getFile(filename))
|
|
|
|
driver->takeBuffer(std::move(*mbOrErr));
|
2016-04-19 09:21:58 +08:00
|
|
|
}
|
|
|
|
e.add("/nologo");
|
2017-08-22 11:15:28 +08:00
|
|
|
e.add("/out:" + StringRef(user.path));
|
2016-04-19 09:21:58 +08:00
|
|
|
e.run();
|
2017-08-22 11:15:28 +08:00
|
|
|
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(
|
|
|
|
CHECK(MemoryBuffer::getFile(user.path), "could not open " + user.path)
|
|
|
|
.get()
|
|
|
|
->getBuffer());
|
2017-08-22 11:15:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static std::string createManifestXml() {
|
|
|
|
std::string defaultXml = createDefaultXml();
|
|
|
|
if (config->manifestInput.empty())
|
|
|
|
return defaultXml;
|
|
|
|
|
2017-09-06 09:50:36 +08:00
|
|
|
if (windows_manifest::isAvailable())
|
|
|
|
return createManifestXmlWithInternalMt(defaultXml);
|
|
|
|
|
|
|
|
return createManifestXmlWithExternalMt(defaultXml);
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
|
|
|
|
2018-01-12 17:48:41 +08:00
|
|
|
static std::unique_ptr<WritableMemoryBuffer>
|
2017-07-08 11:06:10 +08:00
|
|
|
createMemoryBufferForManifestRes(size_t manifestSize) {
|
|
|
|
size_t resSize = alignTo(
|
|
|
|
object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
|
|
|
|
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
|
|
|
|
sizeof(object::WinResHeaderSuffix) + manifestSize,
|
|
|
|
object::WIN_RES_DATA_ALIGNMENT);
|
2018-01-12 17:48:41 +08:00
|
|
|
return WritableMemoryBuffer::getNewMemBuffer(resSize, config->outputFile +
|
|
|
|
".manifest.res");
|
2017-07-08 11:06:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void writeResFileHeader(char *&buf) {
|
|
|
|
memcpy(buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
|
|
|
|
buf += sizeof(COFF::WinResMagic);
|
|
|
|
memset(buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
|
|
|
|
buf += object::WIN_RES_NULL_ENTRY_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void writeResEntryHeader(char *&buf, size_t manifestSize) {
|
|
|
|
// Write the prefix.
|
|
|
|
auto *prefix = reinterpret_cast<object::WinResHeaderPrefix *>(buf);
|
|
|
|
prefix->DataSize = manifestSize;
|
|
|
|
prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
|
|
|
|
sizeof(object::WinResIDs) +
|
|
|
|
sizeof(object::WinResHeaderSuffix);
|
|
|
|
buf += sizeof(object::WinResHeaderPrefix);
|
|
|
|
|
|
|
|
// Write the Type/Name IDs.
|
|
|
|
auto *iDs = reinterpret_cast<object::WinResIDs *>(buf);
|
|
|
|
iDs->setType(RT_MANIFEST);
|
|
|
|
iDs->setName(config->manifestID);
|
|
|
|
buf += sizeof(object::WinResIDs);
|
|
|
|
|
|
|
|
// Write the suffix.
|
|
|
|
auto *suffix = reinterpret_cast<object::WinResHeaderSuffix *>(buf);
|
|
|
|
suffix->DataVersion = 0;
|
|
|
|
suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
|
|
|
|
suffix->Language = SUBLANG_ENGLISH_US;
|
|
|
|
suffix->Version = 0;
|
|
|
|
suffix->Characteristics = 0;
|
|
|
|
buf += sizeof(object::WinResHeaderSuffix);
|
|
|
|
}
|
|
|
|
|
2015-06-18 08:12:42 +08:00
|
|
|
// Create a resource file containing a manifest XML.
|
2015-08-06 22:58:50 +08:00
|
|
|
std::unique_ptr<MemoryBuffer> createManifestRes() {
|
2017-07-08 11:06:10 +08:00
|
|
|
std::string manifest = createManifestXml();
|
2017-07-06 03:04:48 +08:00
|
|
|
|
2018-01-12 17:48:41 +08:00
|
|
|
std::unique_ptr<WritableMemoryBuffer> res =
|
2017-07-08 11:06:10 +08:00
|
|
|
createMemoryBufferForManifestRes(manifest.size());
|
|
|
|
|
2018-01-12 17:48:41 +08:00
|
|
|
char *buf = res->getBufferStart();
|
2017-07-08 11:06:10 +08:00
|
|
|
writeResFileHeader(buf);
|
|
|
|
writeResEntryHeader(buf, manifest.size());
|
|
|
|
|
|
|
|
// Copy the manifest data into the .res file.
|
|
|
|
std::copy(manifest.begin(), manifest.end(), buf);
|
2018-01-12 18:09:10 +08:00
|
|
|
return std::move(res);
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
|
|
|
|
2015-08-06 22:58:50 +08:00
|
|
|
void createSideBySideManifest() {
|
2020-01-29 03:23:46 +08:00
|
|
|
std::string path = std::string(config->manifestFile);
|
2015-06-18 08:12:42 +08:00
|
|
|
if (path == "")
|
2016-07-15 07:43:36 +08:00
|
|
|
path = config->outputFile + ".manifest";
|
2015-06-18 08:12:42 +08:00
|
|
|
std::error_code ec;
|
2021-04-06 19:22:41 +08:00
|
|
|
raw_fd_ostream out(path, ec, sys::fs::OF_TextWithCRLF);
|
2016-07-15 08:40:46 +08:00
|
|
|
if (ec)
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("failed to create manifest: " + ec.message());
|
2015-06-18 08:12:42 +08:00
|
|
|
out << createManifestXml();
|
|
|
|
}
|
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
// Parse a string in the form of
|
2016-01-09 09:22:00 +08:00
|
|
|
// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
|
|
|
|
// or "<name>=<dllname>.<name>".
|
2015-06-17 08:16:33 +08:00
|
|
|
// Used for parsing /export arguments.
|
2015-08-06 22:58:50 +08:00
|
|
|
Export parseExport(StringRef arg) {
|
2015-06-17 08:16:33 +08:00
|
|
|
Export e;
|
|
|
|
StringRef rest;
|
|
|
|
std::tie(e.name, rest) = arg.split(",");
|
|
|
|
if (e.name.empty())
|
|
|
|
goto err;
|
2016-01-09 09:22:00 +08:00
|
|
|
|
2017-07-20 05:40:26 +08:00
|
|
|
if (e.name.contains('=')) {
|
2016-01-09 09:22:00 +08:00
|
|
|
StringRef x, y;
|
|
|
|
std::tie(x, y) = e.name.split("=");
|
|
|
|
|
|
|
|
// If "<name>=<dllname>.<name>".
|
2017-07-20 05:40:26 +08:00
|
|
|
if (y.contains(".")) {
|
2016-01-09 09:22:00 +08:00
|
|
|
e.name = x;
|
|
|
|
e.forwardTo = y;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
e.extName = x;
|
|
|
|
e.name = y;
|
2015-06-17 08:16:33 +08:00
|
|
|
if (e.name.empty())
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2016-01-09 09:22:00 +08:00
|
|
|
// If "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
|
2015-06-17 08:16:33 +08:00
|
|
|
while (!rest.empty()) {
|
|
|
|
StringRef tok;
|
|
|
|
std::tie(tok, rest) = rest.split(",");
|
2021-06-24 16:06:35 +08:00
|
|
|
if (tok.equals_insensitive("noname")) {
|
2015-06-17 08:16:33 +08:00
|
|
|
if (e.ordinal == 0)
|
|
|
|
goto err;
|
|
|
|
e.noname = true;
|
|
|
|
continue;
|
|
|
|
}
|
2021-06-24 16:06:35 +08:00
|
|
|
if (tok.equals_insensitive("data")) {
|
2015-06-17 08:16:33 +08:00
|
|
|
e.data = true;
|
|
|
|
continue;
|
|
|
|
}
|
2021-06-24 16:06:35 +08:00
|
|
|
if (tok.equals_insensitive("constant")) {
|
2017-04-22 02:05:46 +08:00
|
|
|
e.constant = true;
|
|
|
|
continue;
|
|
|
|
}
|
2021-06-24 16:06:35 +08:00
|
|
|
if (tok.equals_insensitive("private")) {
|
2015-06-17 08:16:33 +08:00
|
|
|
e.isPrivate = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (tok.startswith("@")) {
|
|
|
|
int32_t ord;
|
|
|
|
if (tok.substr(1).getAsInteger(0, ord))
|
|
|
|
goto err;
|
|
|
|
if (ord <= 0 || 65535 < ord)
|
|
|
|
goto err;
|
|
|
|
e.ordinal = ord;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
|
|
|
|
err:
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("invalid /export: " + arg);
|
2015-06-17 08:16:33 +08:00
|
|
|
}
|
|
|
|
|
COFF: Improve dllexported name mangling compatibility.
The rules for dllexported symbols are overly complicated due to
x86 name decoration, fuzzy symbol resolution, and the fact that
one symbol can be resolved by so many different names. The rules
are probably intended to be "intuitive", so that users don't have
to understand the name mangling schemes, but it seems that it can
lead to unintended symbol exports.
To make it clear what I'm trying to do with this patch, let me
write how the export rules are subtle and complicated.
- x86 name decoration: If machine type is i386 and export name
is given by a command line option, like /export:foo, the
real symbol name the linker has to search for is _foo because
all symbols are decorated with "_" prefixes. This doesn't happen
on non-x86 machines. This automatic name decoration happens only
when the name is not C++ mangled.
However, the symbol name exported from DLLs are ones without "_"
on all platforms.
Moreover, if the option is given via .drectve section, no
symbol decoration is done (the reason being that the .drectve
section is created by a compiler and the compiler should always
know the exact name of the symbol, I guess).
- Fuzzy symbol resolution: In addition to x86 name decoration,
the linker has to look for cdecl or C++ mangled symbols
for a given /export. For example, it searches for not only
_foo but also _foo@<number> or ??foo@... for /export:foo.
Previous implementation didn't get it right. I'm trying to make
it as compatible with MSVC linker as possible with this patch
however the rules are. The new code looks a bit messy to me, but
I don't think it can be simpler due to the ad-hoc-ness of the rules.
llvm-svn: 246424
2015-08-31 16:43:21 +08:00
|
|
|
static StringRef undecorate(StringRef sym) {
|
|
|
|
if (config->machine != I386)
|
|
|
|
return sym;
|
2018-01-20 19:44:42 +08:00
|
|
|
// In MSVC mode, a fully decorated stdcall function is exported
|
|
|
|
// as-is with the leading underscore (with type IMPORT_NAME).
|
|
|
|
// In MinGW mode, a decorated stdcall function gets the underscore
|
|
|
|
// removed, just like normal cdecl functions.
|
|
|
|
if (sym.startswith("_") && sym.contains('@') && !config->mingw)
|
|
|
|
return sym;
|
COFF: Improve dllexported name mangling compatibility.
The rules for dllexported symbols are overly complicated due to
x86 name decoration, fuzzy symbol resolution, and the fact that
one symbol can be resolved by so many different names. The rules
are probably intended to be "intuitive", so that users don't have
to understand the name mangling schemes, but it seems that it can
lead to unintended symbol exports.
To make it clear what I'm trying to do with this patch, let me
write how the export rules are subtle and complicated.
- x86 name decoration: If machine type is i386 and export name
is given by a command line option, like /export:foo, the
real symbol name the linker has to search for is _foo because
all symbols are decorated with "_" prefixes. This doesn't happen
on non-x86 machines. This automatic name decoration happens only
when the name is not C++ mangled.
However, the symbol name exported from DLLs are ones without "_"
on all platforms.
Moreover, if the option is given via .drectve section, no
symbol decoration is done (the reason being that the .drectve
section is created by a compiler and the compiler should always
know the exact name of the symbol, I guess).
- Fuzzy symbol resolution: In addition to x86 name decoration,
the linker has to look for cdecl or C++ mangled symbols
for a given /export. For example, it searches for not only
_foo but also _foo@<number> or ??foo@... for /export:foo.
Previous implementation didn't get it right. I'm trying to make
it as compatible with MSVC linker as possible with this patch
however the rules are. The new code looks a bit messy to me, but
I don't think it can be simpler due to the ad-hoc-ness of the rules.
llvm-svn: 246424
2015-08-31 16:43:21 +08:00
|
|
|
return sym.startswith("_") ? sym.substr(1) : sym;
|
|
|
|
}
|
|
|
|
|
2018-03-15 04:17:16 +08:00
|
|
|
// Convert stdcall/fastcall style symbols into unsuffixed symbols,
|
|
|
|
// with or without a leading underscore. (MinGW specific.)
|
|
|
|
static StringRef killAt(StringRef sym, bool prefix) {
|
|
|
|
if (sym.empty())
|
|
|
|
return sym;
|
|
|
|
// Strip any trailing stdcall suffix
|
|
|
|
sym = sym.substr(0, sym.find('@', 1));
|
|
|
|
if (!sym.startswith("@")) {
|
|
|
|
if (prefix && !sym.startswith("_"))
|
2022-01-21 03:53:18 +08:00
|
|
|
return saver().save("_" + sym);
|
2018-03-15 04:17:16 +08:00
|
|
|
return sym;
|
|
|
|
}
|
|
|
|
// For fastcall, remove the leading @ and replace it with an
|
|
|
|
// underscore, if prefixes are used.
|
|
|
|
sym = sym.substr(1);
|
|
|
|
if (prefix)
|
2022-01-21 03:53:18 +08:00
|
|
|
sym = saver().save("_" + sym);
|
2018-03-15 04:17:16 +08:00
|
|
|
return sym;
|
|
|
|
}
|
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
// Performs error checking on all /export arguments.
|
|
|
|
// It also sets ordinals.
|
2015-08-06 22:58:50 +08:00
|
|
|
void fixupExports() {
|
2015-06-17 08:16:33 +08:00
|
|
|
// Symbol ordinals must be unique.
|
|
|
|
std::set<uint16_t> ords;
|
|
|
|
for (Export &e : config->exports) {
|
|
|
|
if (e.ordinal == 0)
|
|
|
|
continue;
|
2015-08-06 22:58:50 +08:00
|
|
|
if (!ords.insert(e.ordinal).second)
|
2016-07-15 07:37:14 +08:00
|
|
|
fatal("duplicate export ordinal: " + e.name);
|
2015-06-17 08:16:33 +08:00
|
|
|
}
|
|
|
|
|
2016-01-09 09:22:00 +08:00
|
|
|
for (Export &e : config->exports) {
|
|
|
|
if (!e.forwardTo.empty()) {
|
|
|
|
e.exportName = undecorate(e.name);
|
|
|
|
} else {
|
|
|
|
e.exportName = undecorate(e.extName.empty() ? e.name : e.extName);
|
|
|
|
}
|
|
|
|
}
|
COFF: Improve dllexported name mangling compatibility.
The rules for dllexported symbols are overly complicated due to
x86 name decoration, fuzzy symbol resolution, and the fact that
one symbol can be resolved by so many different names. The rules
are probably intended to be "intuitive", so that users don't have
to understand the name mangling schemes, but it seems that it can
lead to unintended symbol exports.
To make it clear what I'm trying to do with this patch, let me
write how the export rules are subtle and complicated.
- x86 name decoration: If machine type is i386 and export name
is given by a command line option, like /export:foo, the
real symbol name the linker has to search for is _foo because
all symbols are decorated with "_" prefixes. This doesn't happen
on non-x86 machines. This automatic name decoration happens only
when the name is not C++ mangled.
However, the symbol name exported from DLLs are ones without "_"
on all platforms.
Moreover, if the option is given via .drectve section, no
symbol decoration is done (the reason being that the .drectve
section is created by a compiler and the compiler should always
know the exact name of the symbol, I guess).
- Fuzzy symbol resolution: In addition to x86 name decoration,
the linker has to look for cdecl or C++ mangled symbols
for a given /export. For example, it searches for not only
_foo but also _foo@<number> or ??foo@... for /export:foo.
Previous implementation didn't get it right. I'm trying to make
it as compatible with MSVC linker as possible with this patch
however the rules are. The new code looks a bit messy to me, but
I don't think it can be simpler due to the ad-hoc-ness of the rules.
llvm-svn: 246424
2015-08-31 16:43:21 +08:00
|
|
|
|
2018-03-15 04:17:16 +08:00
|
|
|
if (config->killAt && config->machine == I386) {
|
|
|
|
for (Export &e : config->exports) {
|
|
|
|
e.name = killAt(e.name, true);
|
|
|
|
e.exportName = killAt(e.exportName, false);
|
|
|
|
e.extName = killAt(e.extName, true);
|
|
|
|
e.symbolName = killAt(e.symbolName, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
// Uniquefy by name.
|
2017-11-11 03:12:01 +08:00
|
|
|
DenseMap<StringRef, Export *> map(config->exports.size());
|
2015-06-17 08:16:33 +08:00
|
|
|
std::vector<Export> v;
|
|
|
|
for (Export &e : config->exports) {
|
COFF: Improve dllexported name mangling compatibility.
The rules for dllexported symbols are overly complicated due to
x86 name decoration, fuzzy symbol resolution, and the fact that
one symbol can be resolved by so many different names. The rules
are probably intended to be "intuitive", so that users don't have
to understand the name mangling schemes, but it seems that it can
lead to unintended symbol exports.
To make it clear what I'm trying to do with this patch, let me
write how the export rules are subtle and complicated.
- x86 name decoration: If machine type is i386 and export name
is given by a command line option, like /export:foo, the
real symbol name the linker has to search for is _foo because
all symbols are decorated with "_" prefixes. This doesn't happen
on non-x86 machines. This automatic name decoration happens only
when the name is not C++ mangled.
However, the symbol name exported from DLLs are ones without "_"
on all platforms.
Moreover, if the option is given via .drectve section, no
symbol decoration is done (the reason being that the .drectve
section is created by a compiler and the compiler should always
know the exact name of the symbol, I guess).
- Fuzzy symbol resolution: In addition to x86 name decoration,
the linker has to look for cdecl or C++ mangled symbols
for a given /export. For example, it searches for not only
_foo but also _foo@<number> or ??foo@... for /export:foo.
Previous implementation didn't get it right. I'm trying to make
it as compatible with MSVC linker as possible with this patch
however the rules are. The new code looks a bit messy to me, but
I don't think it can be simpler due to the ad-hoc-ness of the rules.
llvm-svn: 246424
2015-08-31 16:43:21 +08:00
|
|
|
auto pair = map.insert(std::make_pair(e.exportName, &e));
|
2015-07-04 10:00:22 +08:00
|
|
|
bool inserted = pair.second;
|
|
|
|
if (inserted) {
|
2015-07-04 07:23:29 +08:00
|
|
|
v.push_back(e);
|
2015-06-17 08:16:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2015-07-04 10:00:22 +08:00
|
|
|
Export *existing = pair.first->second;
|
2015-07-30 06:38:27 +08:00
|
|
|
if (e == *existing || e.name != existing->name)
|
2015-07-04 07:23:29 +08:00
|
|
|
continue;
|
2017-02-22 07:22:56 +08:00
|
|
|
warn("duplicate /export option: " + e.name);
|
2015-06-17 08:16:33 +08:00
|
|
|
}
|
|
|
|
config->exports = std::move(v);
|
|
|
|
|
|
|
|
// Sort by name.
|
2015-07-29 06:34:24 +08:00
|
|
|
std::sort(config->exports.begin(), config->exports.end(),
|
|
|
|
[](const Export &a, const Export &b) {
|
COFF: Improve dllexported name mangling compatibility.
The rules for dllexported symbols are overly complicated due to
x86 name decoration, fuzzy symbol resolution, and the fact that
one symbol can be resolved by so many different names. The rules
are probably intended to be "intuitive", so that users don't have
to understand the name mangling schemes, but it seems that it can
lead to unintended symbol exports.
To make it clear what I'm trying to do with this patch, let me
write how the export rules are subtle and complicated.
- x86 name decoration: If machine type is i386 and export name
is given by a command line option, like /export:foo, the
real symbol name the linker has to search for is _foo because
all symbols are decorated with "_" prefixes. This doesn't happen
on non-x86 machines. This automatic name decoration happens only
when the name is not C++ mangled.
However, the symbol name exported from DLLs are ones without "_"
on all platforms.
Moreover, if the option is given via .drectve section, no
symbol decoration is done (the reason being that the .drectve
section is created by a compiler and the compiler should always
know the exact name of the symbol, I guess).
- Fuzzy symbol resolution: In addition to x86 name decoration,
the linker has to look for cdecl or C++ mangled symbols
for a given /export. For example, it searches for not only
_foo but also _foo@<number> or ??foo@... for /export:foo.
Previous implementation didn't get it right. I'm trying to make
it as compatible with MSVC linker as possible with this patch
however the rules are. The new code looks a bit messy to me, but
I don't think it can be simpler due to the ad-hoc-ness of the rules.
llvm-svn: 246424
2015-08-31 16:43:21 +08:00
|
|
|
return a.exportName < b.exportName;
|
2015-07-29 06:34:24 +08:00
|
|
|
});
|
2015-07-16 06:21:08 +08:00
|
|
|
}
|
2015-06-17 08:16:33 +08:00
|
|
|
|
2015-07-16 06:21:08 +08:00
|
|
|
void assignExportOrdinals() {
|
2015-06-17 08:16:33 +08:00
|
|
|
// Assign unique ordinals if default (= 0).
|
2020-08-27 19:48:22 +08:00
|
|
|
uint32_t max = 0;
|
2015-06-17 08:16:33 +08:00
|
|
|
for (Export &e : config->exports)
|
2020-08-27 19:48:22 +08:00
|
|
|
max = std::max(max, (uint32_t)e.ordinal);
|
2015-06-17 08:16:33 +08:00
|
|
|
for (Export &e : config->exports)
|
|
|
|
if (e.ordinal == 0)
|
|
|
|
e.ordinal = ++max;
|
2020-08-27 19:48:22 +08:00
|
|
|
if (max > std::numeric_limits<uint16_t>::max())
|
|
|
|
fatal("too many exported symbols (max " +
|
|
|
|
Twine(std::numeric_limits<uint16_t>::max()) + ")");
|
2015-06-17 08:16:33 +08:00
|
|
|
}
|
|
|
|
|
2015-06-05 03:21:24 +08:00
|
|
|
// Parses a string in the form of "key=value" and check
|
|
|
|
// if value matches previous values for the same key.
|
2019-03-30 03:58:58 +08:00
|
|
|
void checkFailIfMismatch(StringRef arg, InputFile *source) {
|
2015-06-19 05:23:34 +08:00
|
|
|
StringRef k, v;
|
|
|
|
std::tie(k, v) = arg.split('=');
|
2015-08-06 22:58:50 +08:00
|
|
|
if (k.empty() || v.empty())
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("/failifmismatch: invalid argument: " + arg);
|
2019-03-30 03:58:58 +08:00
|
|
|
std::pair<StringRef, InputFile *> existing = config->mustMatch[k];
|
2019-03-07 04:18:38 +08:00
|
|
|
if (!existing.first.empty() && v != existing.first) {
|
2019-03-30 03:58:58 +08:00
|
|
|
std::string sourceStr = source ? toString(source) : "cmd-line";
|
|
|
|
std::string existingStr =
|
|
|
|
existing.second ? toString(existing.second) : "cmd-line";
|
2019-03-07 04:18:38 +08:00
|
|
|
fatal("/failifmismatch: mismatch detected for '" + k + "':\n>>> " +
|
2019-03-30 03:58:58 +08:00
|
|
|
existingStr + " has value " + existing.first + "\n>>> " + sourceStr +
|
|
|
|
" has value " + v);
|
2019-03-07 04:18:38 +08:00
|
|
|
}
|
|
|
|
config->mustMatch[k] = {v, source};
|
2015-06-05 03:21:24 +08:00
|
|
|
}
|
|
|
|
|
2017-10-17 07:15:04 +08:00
|
|
|
// Convert Windows resource files (.res files) to a .obj file.
|
lld-link: Reject more than one resource .obj file
Users are exepcted to pass all .res files to the linker, which then
merges all the resource in all .res files into a tree structure and then
converts the final tree structure to a .obj file with .rsrc$01 and
.rsrc$02 sections and then links that.
If the user instead passes several .obj files containing such resources,
the correct thing to do would be to have custom code to merge the trees
in the resource sections instead of doing normal section merging -- but
link.exe rejects if multiple resource obj files are passed in with
LNK4078, so let lld-link do that too instead of silently writing broken
.rsrc sections in that case.
The only real way to run into this is if users manually convert .res
files to .obj files by running cvtres and then handing the resulting
.obj files to lld-link instead, which in practice likely never happens.
(lld-link is slightly stricter than link.exe now: If link.exe is passed
one .obj file created by cvtres, and a .res file, for some reason it
just emits a warning instead of an error and outputs strange looking
data. lld-link now errors out on mixed input like this.)
One way users could accidentally run into this is the following
scenario: If a .res file is passed to lib.exe, then lib.exe calls
cvtres.exe on the .res file before putting it in the output .lib.
(llvm-lib currently doesn't do this.)
link.exe's /wholearchive seems to only add obj files referenced from the
static library index, but lld-link current really adds all files in the
archive. So if lld-link /wholearchive is used with .lib files produced
by lib.exe and .res files were among the files handed to lib.exe, we
previously silently produced invalid output, but now we error out.
link.exe's /wholearchive semantics on the other hand mean that it
wouldn't load the resource object files from the .lib file at all.
Since this scenario is probably still an unlikely corner case,
the difference in behavior here seems fine -- and lld-link might have to
change to use link.exe's /wholearchive semantics in the future anyways.
Vaguely related to PR42180.
Differential Revision: https://reviews.llvm.org/D63109
llvm-svn: 363078
2019-06-11 23:22:28 +08:00
|
|
|
// Does what cvtres.exe does, but in-process and cross-platform.
|
2019-08-30 14:56:33 +08:00
|
|
|
MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
|
|
|
|
ArrayRef<ObjFile *> objs) {
|
[LLD] [COFF] Implement MinGW default manifest handling
In mingw environments, resources are normally compiled to resource
object files directly, instead of letting the linker convert them to
COFF format.
Since some time, GCC supports the notion of a default manifest object.
When invoking the linker, GCC looks for the default manifest object
file, and if found in the expected path, it is added to linker commands.
The default manifest is one that indicates support for the latest known
versions of windows, to implicitly unlock the modern behaviours of certain
APIs.
Not all mingw/gcc distributions include this file, but e.g. in msys2,
the default manifest object is distributed in a separate package (which
can be but might not always be installed).
This means that even if user projects only use one single resource
object file, the linker can end up with two resource object files,
and thus needs to support merging them.
The default manifest has a language id of zero, and GNU ld has got
logic for dropping a manifest with a zero language id, if there's
another manifest present with a nonzero language id. If there are
multiple manifests with a nonzero language id, the merging process
errors out.
Differential Revision: https://reviews.llvm.org/D66825
llvm-svn: 370974
2019-09-05 04:34:00 +08:00
|
|
|
object::WindowsResourceParser parser(/* MinGW */ config->mingw);
|
2015-06-15 05:50:50 +08:00
|
|
|
|
2019-08-30 14:56:33 +08:00
|
|
|
std::vector<std::string> duplicates;
|
2016-11-16 05:25:20 +08:00
|
|
|
for (MemoryBufferRef mb : mbs) {
|
2017-07-08 11:06:10 +08:00
|
|
|
std::unique_ptr<object::Binary> bin = check(object::createBinary(mb));
|
|
|
|
object::WindowsResource *rf = dyn_cast<object::WindowsResource>(bin.get());
|
|
|
|
if (!rf)
|
|
|
|
fatal("cannot compile non-resource file as resource");
|
2019-05-03 05:21:55 +08:00
|
|
|
|
|
|
|
if (auto ec = parser.parse(rf, duplicates))
|
2019-05-02 09:52:24 +08:00
|
|
|
fatal(toString(std::move(ec)));
|
2019-08-30 14:56:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Note: This processes all .res files before all objs. Ideally they'd be
|
|
|
|
// handled in the same order they were linked (to keep the right one, if
|
|
|
|
// there are duplicates that are tolerated due to forceMultipleRes).
|
|
|
|
for (ObjFile *f : objs) {
|
|
|
|
object::ResourceSectionRef rsf;
|
|
|
|
if (auto ec = rsf.load(f->getCOFFObj()))
|
|
|
|
fatal(toString(f) + ": " + toString(std::move(ec)));
|
2019-05-03 05:21:55 +08:00
|
|
|
|
2019-08-30 14:56:33 +08:00
|
|
|
if (auto ec = parser.parse(rsf, f->getName(), duplicates))
|
|
|
|
fatal(toString(std::move(ec)));
|
2016-11-16 05:25:20 +08:00
|
|
|
}
|
|
|
|
|
[LLD] [COFF] Implement MinGW default manifest handling
In mingw environments, resources are normally compiled to resource
object files directly, instead of letting the linker convert them to
COFF format.
Since some time, GCC supports the notion of a default manifest object.
When invoking the linker, GCC looks for the default manifest object
file, and if found in the expected path, it is added to linker commands.
The default manifest is one that indicates support for the latest known
versions of windows, to implicitly unlock the modern behaviours of certain
APIs.
Not all mingw/gcc distributions include this file, but e.g. in msys2,
the default manifest object is distributed in a separate package (which
can be but might not always be installed).
This means that even if user projects only use one single resource
object file, the linker can end up with two resource object files,
and thus needs to support merging them.
The default manifest has a language id of zero, and GNU ld has got
logic for dropping a manifest with a zero language id, if there's
another manifest present with a nonzero language id. If there are
multiple manifests with a nonzero language id, the merging process
errors out.
Differential Revision: https://reviews.llvm.org/D66825
llvm-svn: 370974
2019-09-05 04:34:00 +08:00
|
|
|
if (config->mingw)
|
|
|
|
parser.cleanUpManifests(duplicates);
|
2019-08-30 14:56:33 +08:00
|
|
|
|
|
|
|
for (const auto &dupeDiag : duplicates)
|
|
|
|
if (config->forceMultipleRes)
|
|
|
|
warn(dupeDiag);
|
|
|
|
else
|
|
|
|
error(dupeDiag);
|
|
|
|
|
2017-07-08 11:06:10 +08:00
|
|
|
Expected<std::unique_ptr<MemoryBuffer>> e =
|
2019-06-11 19:26:50 +08:00
|
|
|
llvm::object::writeWindowsResourceCOFF(config->machine, parser,
|
|
|
|
config->timestamp);
|
2017-07-08 11:06:10 +08:00
|
|
|
if (!e)
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
fatal("failed to write .res to COFF: " + toString(e.takeError()));
|
2017-10-17 07:15:04 +08:00
|
|
|
|
|
|
|
MemoryBufferRef mbref = **e;
|
|
|
|
make<std::unique_ptr<MemoryBuffer>>(std::move(*e)); // take ownership
|
|
|
|
return mbref;
|
2015-06-15 05:50:50 +08:00
|
|
|
}
|
|
|
|
|
2015-05-29 04:30:06 +08:00
|
|
|
// Create OptTable
|
|
|
|
|
|
|
|
// Create prefix string literals used in Options.td
|
|
|
|
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
|
|
|
|
#include "Options.inc"
|
|
|
|
#undef PREFIX
|
|
|
|
|
|
|
|
// Create table mapping all options defined in Options.td
|
2017-08-23 10:33:42 +08:00
|
|
|
static const llvm::opt::OptTable::Info infoTable[] = {
|
2017-06-21 03:17:58 +08:00
|
|
|
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
|
|
|
|
{X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \
|
|
|
|
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "Options.inc"
|
|
|
|
#undef OPTION
|
|
|
|
};
|
|
|
|
|
2017-08-29 04:46:30 +08:00
|
|
|
COFFOptTable::COFFOptTable() : OptTable(infoTable, true) {}
|
2015-05-29 04:30:06 +08:00
|
|
|
|
2020-05-03 05:53:59 +08:00
|
|
|
COFFOptTable optTable;
|
|
|
|
|
2018-05-11 02:19:02 +08:00
|
|
|
// Set color diagnostics according to --color-diagnostics={auto,always,never}
|
|
|
|
// or --no-color-diagnostics flags.
|
|
|
|
static void handleColorDiagnostics(opt::InputArgList &args) {
|
|
|
|
auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
|
|
|
|
OPT_no_color_diagnostics);
|
|
|
|
if (!arg)
|
|
|
|
return;
|
|
|
|
if (arg->getOption().getID() == OPT_color_diagnostics) {
|
2019-11-20 23:08:18 +08:00
|
|
|
lld::errs().enable_colors(true);
|
2018-05-11 02:19:02 +08:00
|
|
|
} else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
|
2019-11-20 23:08:18 +08:00
|
|
|
lld::errs().enable_colors(false);
|
2018-05-11 02:19:02 +08:00
|
|
|
} else {
|
|
|
|
StringRef s = arg->getValue();
|
|
|
|
if (s == "always")
|
2019-11-20 23:08:18 +08:00
|
|
|
lld::errs().enable_colors(true);
|
2018-05-11 02:19:02 +08:00
|
|
|
else if (s == "never")
|
2019-11-20 23:08:18 +08:00
|
|
|
lld::errs().enable_colors(false);
|
2018-05-11 02:19:02 +08:00
|
|
|
else if (s != "auto")
|
|
|
|
error("unknown option: --color-diagnostics=" + s);
|
|
|
|
}
|
|
|
|
}
|
2019-07-11 13:40:30 +08:00
|
|
|
|
2017-09-06 07:46:45 +08:00
|
|
|
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
|
|
|
|
if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
|
|
|
|
StringRef s = arg->getValue();
|
|
|
|
if (s != "windows" && s != "posix")
|
|
|
|
error("invalid response file quoting: " + s);
|
|
|
|
if (s == "windows")
|
|
|
|
return cl::TokenizeWindowsCommandLine;
|
|
|
|
return cl::TokenizeGNUCommandLine;
|
|
|
|
}
|
|
|
|
// The COFF linker always defaults to Windows quoting.
|
|
|
|
return cl::TokenizeWindowsCommandLine;
|
|
|
|
}
|
2015-06-07 10:55:19 +08:00
|
|
|
|
2017-09-06 07:46:45 +08:00
|
|
|
// Parses a given list of options.
|
|
|
|
opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
|
2015-06-07 10:55:19 +08:00
|
|
|
// Make InputArgList from string vectors.
|
2015-05-29 04:30:06 +08:00
|
|
|
unsigned missingIndex;
|
|
|
|
unsigned missingCount;
|
2017-09-06 07:46:45 +08:00
|
|
|
|
|
|
|
// We need to get the quoting style for response files before parsing all
|
|
|
|
// options so we parse here before and ignore all the options but
|
2019-09-13 21:13:52 +08:00
|
|
|
// --rsp-quoting and /lldignoreenv.
|
|
|
|
// (This means --rsp-quoting can't be added through %LINK%.)
|
2020-05-03 05:53:59 +08:00
|
|
|
opt::InputArgList args = optTable.ParseArgs(argv, missingIndex, missingCount);
|
2019-09-13 21:13:52 +08:00
|
|
|
|
|
|
|
// Expand response files (arguments in the form of @<filename>) and insert
|
|
|
|
// flags from %LINK% and %_LINK_%, and then parse the argument again.
|
2019-05-24 01:58:33 +08:00
|
|
|
SmallVector<const char *, 256> expandedArgv(argv.data(),
|
|
|
|
argv.data() + argv.size());
|
2019-09-13 21:13:52 +08:00
|
|
|
if (!args.hasArg(OPT_lldignoreenv))
|
|
|
|
addLINK(expandedArgv);
|
2022-01-21 03:53:18 +08:00
|
|
|
cl::ExpandResponseFiles(saver(), getQuotingStyle(args), expandedArgv);
|
2020-05-03 05:53:59 +08:00
|
|
|
args = optTable.ParseArgs(makeArrayRef(expandedArgv).drop_front(),
|
|
|
|
missingIndex, missingCount);
|
2015-08-26 15:12:08 +08:00
|
|
|
|
|
|
|
// Print the real command line if response files are expanded.
|
2018-07-21 06:34:20 +08:00
|
|
|
if (args.hasArg(OPT_verbose) && argv.size() != expandedArgv.size()) {
|
2017-02-22 07:22:56 +08:00
|
|
|
std::string msg = "Command line:";
|
2018-07-21 06:34:20 +08:00
|
|
|
for (const char *s : expandedArgv)
|
2017-02-22 07:22:56 +08:00
|
|
|
msg += " " + std::string(s);
|
|
|
|
message(msg);
|
2015-08-26 15:12:08 +08:00
|
|
|
}
|
|
|
|
|
2018-07-21 06:34:20 +08:00
|
|
|
// Save the command line after response file expansion so we can write it to
|
|
|
|
// the PDB if necessary.
|
|
|
|
config->argv = {expandedArgv.begin(), expandedArgv.end()};
|
|
|
|
|
2017-10-25 05:19:22 +08:00
|
|
|
// Handle /WX early since it converts missing argument warnings to errors.
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
errorHandler().fatalWarnings = args.hasFlag(OPT_WX, OPT_WX_no, false);
|
2017-10-25 05:19:22 +08:00
|
|
|
|
2015-08-06 22:58:50 +08:00
|
|
|
if (missingCount)
|
2016-11-29 12:17:31 +08:00
|
|
|
fatal(Twine(args.getArgString(missingIndex)) + ": missing argument");
|
2018-05-11 02:19:02 +08:00
|
|
|
|
|
|
|
handleColorDiagnostics(args);
|
|
|
|
|
2020-11-23 23:51:56 +08:00
|
|
|
for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
|
2019-05-07 21:48:30 +08:00
|
|
|
std::string nearest;
|
2020-05-03 05:53:59 +08:00
|
|
|
if (optTable.findNearest(arg->getAsString(args), nearest) > 1)
|
2019-07-05 20:31:32 +08:00
|
|
|
warn("ignoring unknown argument '" + arg->getAsString(args) + "'");
|
2019-05-07 21:48:30 +08:00
|
|
|
else
|
2019-07-05 20:31:32 +08:00
|
|
|
warn("ignoring unknown argument '" + arg->getAsString(args) +
|
2019-05-07 21:48:30 +08:00
|
|
|
"', did you mean '" + nearest + "'");
|
|
|
|
}
|
2018-07-14 12:07:51 +08:00
|
|
|
|
|
|
|
if (args.hasArg(OPT_lib))
|
|
|
|
warn("ignoring /lib since it's not the first argument");
|
|
|
|
|
2015-08-06 22:58:50 +08:00
|
|
|
return args;
|
2015-05-29 04:30:06 +08:00
|
|
|
}
|
|
|
|
|
2017-12-27 14:08:10 +08:00
|
|
|
// Tokenizes and parses a given string as command line in .drective section.
|
[COFF] Add a fastpath for /INCLUDE: in .drective sections
This speeds up linking chrome.dll with PGO instrumentation by 13%
(154271ms -> 134033ms).
LLVM's Option library is very slow. In particular, it allocates at least
one large-ish heap object (Arg) for every argument. When PGO
instrumentation is enabled, all the __profd_* symbols are added to the
@llvm.used list, which compiles down to these /INCLUDE: directives. This
means we have O(#symbols) directives to parse in the section, so we end
up allocating an Arg for every function symbol in the object file. This
is unnecessary.
To address the issue and speed up the link, extend the fast path that we
already have for /EXPORT:, which has similar scaling issues.
I promise that I took a hard look at optimizing the Option library, but
its data structures are very general and would need a lot of cleanup. We
have accumulated lots of optional features (option groups, aliases,
multiple values) over the years, and these are now properties of every
parsed argument, when the vast majority of arguments do not use these
features.
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D78845
2020-04-25 08:26:17 +08:00
|
|
|
ParsedDirectives ArgParser::parseDirectives(StringRef s) {
|
|
|
|
ParsedDirectives result;
|
2018-01-10 04:36:42 +08:00
|
|
|
SmallVector<const char *, 16> rest;
|
|
|
|
|
2020-05-01 22:34:12 +08:00
|
|
|
// Handle /EXPORT and /INCLUDE in a fast path. These directives can appear for
|
|
|
|
// potentially every symbol in the object, so they must be handled quickly.
|
|
|
|
SmallVector<StringRef, 16> tokens;
|
2022-01-21 03:53:18 +08:00
|
|
|
cl::TokenizeWindowsCommandLineNoCopy(s, saver(), tokens);
|
2020-05-01 22:34:12 +08:00
|
|
|
for (StringRef tok : tokens) {
|
2021-06-24 16:06:35 +08:00
|
|
|
if (tok.startswith_insensitive("/export:") ||
|
|
|
|
tok.startswith_insensitive("-export:"))
|
[COFF] Add a fastpath for /INCLUDE: in .drective sections
This speeds up linking chrome.dll with PGO instrumentation by 13%
(154271ms -> 134033ms).
LLVM's Option library is very slow. In particular, it allocates at least
one large-ish heap object (Arg) for every argument. When PGO
instrumentation is enabled, all the __profd_* symbols are added to the
@llvm.used list, which compiles down to these /INCLUDE: directives. This
means we have O(#symbols) directives to parse in the section, so we end
up allocating an Arg for every function symbol in the object file. This
is unnecessary.
To address the issue and speed up the link, extend the fast path that we
already have for /EXPORT:, which has similar scaling issues.
I promise that I took a hard look at optimizing the Option library, but
its data structures are very general and would need a lot of cleanup. We
have accumulated lots of optional features (option groups, aliases,
multiple values) over the years, and these are now properties of every
parsed argument, when the vast majority of arguments do not use these
features.
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D78845
2020-04-25 08:26:17 +08:00
|
|
|
result.exports.push_back(tok.substr(strlen("/export:")));
|
2021-06-24 16:06:35 +08:00
|
|
|
else if (tok.startswith_insensitive("/include:") ||
|
|
|
|
tok.startswith_insensitive("-include:"))
|
[COFF] Add a fastpath for /INCLUDE: in .drective sections
This speeds up linking chrome.dll with PGO instrumentation by 13%
(154271ms -> 134033ms).
LLVM's Option library is very slow. In particular, it allocates at least
one large-ish heap object (Arg) for every argument. When PGO
instrumentation is enabled, all the __profd_* symbols are added to the
@llvm.used list, which compiles down to these /INCLUDE: directives. This
means we have O(#symbols) directives to parse in the section, so we end
up allocating an Arg for every function symbol in the object file. This
is unnecessary.
To address the issue and speed up the link, extend the fast path that we
already have for /EXPORT:, which has similar scaling issues.
I promise that I took a hard look at optimizing the Option library, but
its data structures are very general and would need a lot of cleanup. We
have accumulated lots of optional features (option groups, aliases,
multiple values) over the years, and these are now properties of every
parsed argument, when the vast majority of arguments do not use these
features.
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D78845
2020-04-25 08:26:17 +08:00
|
|
|
result.includes.push_back(tok.substr(strlen("/include:")));
|
2020-05-01 22:34:12 +08:00
|
|
|
else {
|
2020-12-10 05:30:22 +08:00
|
|
|
// Copy substrings that are not valid C strings. The tokenizer may have
|
|
|
|
// already copied quoted arguments for us, so those do not need to be
|
|
|
|
// copied again.
|
|
|
|
bool HasNul = tok.end() != s.end() && tok.data()[tok.size()] == '\0';
|
2022-01-21 03:53:18 +08:00
|
|
|
rest.push_back(HasNul ? tok.data() : saver().save(tok).data());
|
2020-05-01 22:34:12 +08:00
|
|
|
}
|
2018-01-10 04:36:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make InputArgList from unparsed string vectors.
|
2017-12-27 14:08:10 +08:00
|
|
|
unsigned missingIndex;
|
|
|
|
unsigned missingCount;
|
|
|
|
|
2020-05-03 05:53:59 +08:00
|
|
|
result.args = optTable.ParseArgs(rest, missingIndex, missingCount);
|
2017-12-27 14:08:10 +08:00
|
|
|
|
|
|
|
if (missingCount)
|
[COFF] Add a fastpath for /INCLUDE: in .drective sections
This speeds up linking chrome.dll with PGO instrumentation by 13%
(154271ms -> 134033ms).
LLVM's Option library is very slow. In particular, it allocates at least
one large-ish heap object (Arg) for every argument. When PGO
instrumentation is enabled, all the __profd_* symbols are added to the
@llvm.used list, which compiles down to these /INCLUDE: directives. This
means we have O(#symbols) directives to parse in the section, so we end
up allocating an Arg for every function symbol in the object file. This
is unnecessary.
To address the issue and speed up the link, extend the fast path that we
already have for /EXPORT:, which has similar scaling issues.
I promise that I took a hard look at optimizing the Option library, but
its data structures are very general and would need a lot of cleanup. We
have accumulated lots of optional features (option groups, aliases,
multiple values) over the years, and these are now properties of every
parsed argument, when the vast majority of arguments do not use these
features.
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D78845
2020-04-25 08:26:17 +08:00
|
|
|
fatal(Twine(result.args.getArgString(missingIndex)) + ": missing argument");
|
|
|
|
for (auto *arg : result.args.filtered(OPT_UNKNOWN))
|
|
|
|
warn("ignoring unknown argument: " + arg->getAsString(result.args));
|
|
|
|
return result;
|
2017-12-27 14:08:10 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 06:20:03 +08:00
|
|
|
// link.exe has an interesting feature. If LINK or _LINK_ environment
|
|
|
|
// variables exist, their contents are handled as command line strings.
|
|
|
|
// So you can pass extra arguments using them.
|
2019-09-13 21:13:52 +08:00
|
|
|
void ArgParser::addLINK(SmallVector<const char *, 256> &argv) {
|
2016-11-29 12:17:30 +08:00
|
|
|
// Concatenate LINK env and command line arguments, and then parse them.
|
2017-04-25 06:20:03 +08:00
|
|
|
if (Optional<std::string> s = Process::GetEnv("LINK")) {
|
|
|
|
std::vector<const char *> v = tokenize(*s);
|
2018-07-21 06:34:20 +08:00
|
|
|
argv.insert(std::next(argv.begin()), v.begin(), v.end());
|
2017-04-25 06:20:03 +08:00
|
|
|
}
|
|
|
|
if (Optional<std::string> s = Process::GetEnv("_LINK_")) {
|
|
|
|
std::vector<const char *> v = tokenize(*s);
|
2018-07-21 06:34:20 +08:00
|
|
|
argv.insert(std::next(argv.begin()), v.begin(), v.end());
|
2017-04-25 06:20:03 +08:00
|
|
|
}
|
2015-06-28 10:35:31 +08:00
|
|
|
}
|
|
|
|
|
2015-06-07 10:55:19 +08:00
|
|
|
std::vector<const char *> ArgParser::tokenize(StringRef s) {
|
|
|
|
SmallVector<const char *, 16> tokens;
|
2022-01-21 03:53:18 +08:00
|
|
|
cl::TokenizeWindowsCommandLine(s, saver(), tokens);
|
2015-06-08 07:02:50 +08:00
|
|
|
return std::vector<const char *>(tokens.begin(), tokens.end());
|
2015-06-07 10:55:19 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 00:11:52 +08:00
|
|
|
void printHelp(const char *argv0) {
|
2021-06-25 05:47:03 +08:00
|
|
|
optTable.printHelp(lld::outs(),
|
2020-05-03 05:53:59 +08:00
|
|
|
(std::string(argv0) + " [options] file...").c_str(),
|
|
|
|
"LLVM Linker", false);
|
2015-05-30 00:11:52 +08:00
|
|
|
}
|
|
|
|
|
2015-05-29 04:30:06 +08:00
|
|
|
} // namespace coff
|
|
|
|
} // namespace lld
|