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"
|
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:
|
2017-05-19 01:03:49 +08:00
|
|
|
explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
|
2017-02-22 07:22:56 +08:00
|
|
|
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());
|
2017-02-22 07:22:56 +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:06:00 +08:00
|
|
|
// Returns /machine's value.
|
2015-08-06 22:58:50 +08:00
|
|
|
MachineTypes getMachineType(StringRef S) {
|
2015-07-09 02:14:51 +08:00
|
|
|
MachineTypes MT = StringSwitch<MachineTypes>(S.lower())
|
2016-10-01 06:01:25 +08:00
|
|
|
.Cases("x64", "amd64", AMD64)
|
|
|
|
.Cases("x86", "i386", I386)
|
2015-07-26 05:54:50 +08:00
|
|
|
.Case("arm", ARMNT)
|
2017-07-02 04:29:27 +08:00
|
|
|
.Case("arm64", ARM64)
|
2015-07-09 02:14:51 +08:00
|
|
|
.Default(IMAGE_FILE_MACHINE_UNKNOWN);
|
|
|
|
if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
|
2015-05-30 00:06:00 +08:00
|
|
|
return MT;
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("unknown /machine argument: " + S);
|
2015-05-30 00:06:00 +08:00
|
|
|
}
|
|
|
|
|
2015-07-26 05:54:50 +08:00
|
|
|
StringRef machineToStr(MachineTypes MT) {
|
2015-07-08 07:39:18 +08:00
|
|
|
switch (MT) {
|
2015-07-26 05:54:50 +08:00
|
|
|
case ARMNT:
|
2015-07-08 07:39:18 +08:00
|
|
|
return "arm";
|
2017-07-02 04:29:27 +08:00
|
|
|
case ARM64:
|
|
|
|
return "arm64";
|
2015-07-26 05:54:50 +08:00
|
|
|
case AMD64:
|
2015-07-08 07:39:18 +08:00
|
|
|
return "x64";
|
2015-07-26 05:54:50 +08:00
|
|
|
case I386:
|
2015-07-08 07:39:18 +08:00
|
|
|
return "x86";
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unknown machine type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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('.');
|
2015-08-06 22:58:50 +08:00
|
|
|
if (S1.getAsInteger(0, *Major))
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("invalid number: " + S1);
|
2015-05-30 00:28:29 +08:00
|
|
|
*Minor = 0;
|
2015-08-06 22:58:50 +08:00
|
|
|
if (!S2.empty() && S2.getAsInteger(0, *Minor))
|
2016-07-15 07:43:36 +08:00
|
|
|
fatal("invalid number: " + S2);
|
2015-05-30 00:28:29 +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) {
|
|
|
|
if (Arg.equals_lower("no"))
|
|
|
|
Config->GuardCF = GuardCFLevel::Off;
|
|
|
|
else if (Arg.equals_lower("nolongjmp"))
|
|
|
|
Config->GuardCF = GuardCFLevel::NoLongJmp;
|
|
|
|
else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp"))
|
|
|
|
Config->GuardCF = GuardCFLevel::Full;
|
|
|
|
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,
|
|
|
|
uint32_t *Minor) {
|
2015-05-30 00:34:31 +08:00
|
|
|
StringRef SysStr, Ver;
|
|
|
|
std::tie(SysStr, Ver) = Arg.split(',');
|
|
|
|
*Sys = StringSwitch<WindowsSubsystem>(SysStr.lower())
|
|
|
|
.Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
|
|
|
|
.Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
|
|
|
|
.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);
|
2015-08-06 22:58:50 +08:00
|
|
|
if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
|
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);
|
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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V);
|
|
|
|
}
|
|
|
|
|
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) {
|
2015-06-18 08:12:42 +08:00
|
|
|
if (Arg.equals_lower("no")) {
|
|
|
|
Config->Manifest = Configuration::No;
|
2015-08-06 22:58:50 +08:00
|
|
|
return;
|
2015-06-18 08:12:42 +08:00
|
|
|
}
|
|
|
|
if (!Arg.startswith_lower("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;
|
2015-06-18 08:12:42 +08:00
|
|
|
if (!Arg.startswith_lower(",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) {
|
2015-06-18 08:12:42 +08:00
|
|
|
if (Arg.equals_lower("no")) {
|
|
|
|
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;
|
2015-06-18 08:12:42 +08:00
|
|
|
if (Arg.startswith_lower("level=")) {
|
|
|
|
Arg = Arg.substr(strlen("level="));
|
|
|
|
std::tie(Config->ManifestLevel, Arg) = Arg.split(" ");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (Arg.startswith_lower("uiaccess=")) {
|
|
|
|
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(',');
|
|
|
|
if (Swaprun.equals_lower("cd"))
|
|
|
|
Config->SwaprunCD = true;
|
|
|
|
else if (Swaprun.equals_lower("net"))
|
|
|
|
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());
|
2016-09-03 01:34:17 +08:00
|
|
|
Path = S.str();
|
2017-02-07 04:47:55 +08:00
|
|
|
|
|
|
|
if (!Contents.empty()) {
|
|
|
|
std::error_code EC;
|
|
|
|
raw_fd_ostream OS(Path, EC, sys::fs::F_None);
|
|
|
|
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() {
|
|
|
|
// IsVolatileSize=true forces MemoryBuffer to not use mmap().
|
2017-12-07 06:08:17 +08:00
|
|
|
return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1,
|
2016-09-03 01:34:17 +08:00
|
|
|
/*RequiresNullTerminator=*/false,
|
|
|
|
/*IsVolatileSize=*/true),
|
|
|
|
"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
|
|
|
}
|
|
|
|
if (!Config->ManifestDependency.empty()) {
|
|
|
|
OS << " <dependency>\n"
|
|
|
|
<< " <dependentAssembly>\n"
|
|
|
|
<< " <assemblyIdentity " << Config->ManifestDependency << " />\n"
|
|
|
|
<< " </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));
|
2017-09-06 09:50:36 +08:00
|
|
|
if (auto E = Merger.merge(*Manifest.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 file " + Filename + ": " +
|
|
|
|
toString(std::move(E)));
|
2017-08-22 11:15:28 +08:00
|
|
|
}
|
|
|
|
|
2017-09-06 09:50:36 +08:00
|
|
|
return 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;
|
|
|
|
raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
2017-12-07 06:08:17 +08:00
|
|
|
return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path)
|
2017-09-06 09:50:36 +08:00
|
|
|
.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() {
|
2015-06-18 08:12:42 +08:00
|
|
|
std::string Path = Config->ManifestFile;
|
|
|
|
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;
|
2016-12-09 04:50:47 +08:00
|
|
|
raw_fd_ostream Out(Path, EC, sys::fs::F_Text);
|
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(",");
|
|
|
|
if (Tok.equals_lower("noname")) {
|
|
|
|
if (E.Ordinal == 0)
|
|
|
|
goto err;
|
|
|
|
E.Noname = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (Tok.equals_lower("data")) {
|
|
|
|
E.Data = true;
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-22 02:05:46 +08:00
|
|
|
if (Tok.equals_lower("constant")) {
|
|
|
|
E.Constant = true;
|
|
|
|
continue;
|
|
|
|
}
|
2015-06-17 08:16:33 +08:00
|
|
|
if (Tok.equals_lower("private")) {
|
|
|
|
E.Private = 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("_"))
|
|
|
|
return Saver.save("_" + Sym);
|
|
|
|
return Sym;
|
|
|
|
}
|
|
|
|
// For fastcall, remove the leading @ and replace it with an
|
|
|
|
// underscore, if prefixes are used.
|
|
|
|
Sym = Sym.substr(1);
|
|
|
|
if (Prefix)
|
|
|
|
Sym = Saver.save("_" + Sym);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-07-16 06:21:08 +08:00
|
|
|
for (Export &E : Config->Exports) {
|
2017-11-04 05:21:47 +08:00
|
|
|
Symbol *Sym = E.Sym;
|
2017-06-16 04:39:58 +08:00
|
|
|
if (!E.ForwardTo.empty() || !Sym) {
|
2016-01-09 09:22:00 +08:00
|
|
|
E.SymbolName = E.Name;
|
2016-12-10 07:34:49 +08:00
|
|
|
} else {
|
|
|
|
if (auto *U = dyn_cast<Undefined>(Sym))
|
|
|
|
if (U->WeakAlias)
|
|
|
|
Sym = U->WeakAlias;
|
|
|
|
E.SymbolName = Sym->getName();
|
|
|
|
}
|
2015-07-16 06:21:08 +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).
|
|
|
|
uint16_t Max = 0;
|
|
|
|
for (Export &E : Config->Exports)
|
|
|
|
Max = std::max(Max, E.Ordinal);
|
|
|
|
for (Export &E : Config->Exports)
|
|
|
|
if (E.Ordinal == 0)
|
|
|
|
E.Ordinal = ++Max;
|
|
|
|
}
|
|
|
|
|
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.
|
2017-12-08 09:09:21 +08:00
|
|
|
MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) {
|
2017-07-08 11:06:10 +08:00
|
|
|
object::WindowsResourceParser Parser;
|
2015-06-15 05:50:50 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
std::vector<std::string> Duplicates;
|
|
|
|
if (auto EC = Parser.parse(RF, Duplicates))
|
2019-05-02 09:52:24 +08:00
|
|
|
fatal(toString(std::move(EC)));
|
2019-05-03 05:21:55 +08:00
|
|
|
|
|
|
|
for (const auto &DupeDiag : Duplicates)
|
|
|
|
if (Config->ForceMultipleRes)
|
|
|
|
warn(DupeDiag);
|
|
|
|
else
|
|
|
|
error(DupeDiag);
|
2016-11-16 05:25:20 +08:00
|
|
|
}
|
|
|
|
|
2017-07-08 11:06:10 +08:00
|
|
|
Expected<std::unique_ptr<MemoryBuffer>> E =
|
|
|
|
llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser);
|
|
|
|
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
|
|
|
|
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) {
|
|
|
|
errorHandler().ColorDiagnostics = true;
|
|
|
|
} else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
|
|
|
|
errorHandler().ColorDiagnostics = false;
|
|
|
|
} else {
|
|
|
|
StringRef S = Arg->getValue();
|
|
|
|
if (S == "always")
|
|
|
|
errorHandler().ColorDiagnostics = true;
|
|
|
|
else if (S == "never")
|
|
|
|
errorHandler().ColorDiagnostics = false;
|
|
|
|
else if (S != "auto")
|
|
|
|
error("unknown option: --color-diagnostics=" + S);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
// --rsp-quoting.
|
2018-07-21 06:34:20 +08:00
|
|
|
opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
|
2017-09-06 07:46:45 +08:00
|
|
|
|
|
|
|
// Expand response files (arguments in the form of @<filename>)
|
|
|
|
// and then parse the argument again.
|
2018-07-21 06:34:20 +08:00
|
|
|
SmallVector<const char *, 256> ExpandedArgv(Argv.data(), Argv.data() + Argv.size());
|
|
|
|
cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv);
|
|
|
|
Args = Table.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);
|
|
|
|
|
2019-05-07 21:48:30 +08:00
|
|
|
for (auto *Arg : Args.filtered(OPT_UNKNOWN)) {
|
|
|
|
std::string Nearest;
|
|
|
|
if (Table.findNearest(Arg->getAsString(Args), Nearest) > 1)
|
|
|
|
warn("ignoring unknown argument '" + Arg->getSpelling() + "'");
|
|
|
|
else
|
|
|
|
warn("ignoring unknown argument '" + Arg->getSpelling() +
|
|
|
|
"', 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.
|
2018-01-10 04:36:42 +08:00
|
|
|
// /EXPORT options are processed in fastpath.
|
|
|
|
std::pair<opt::InputArgList, std::vector<StringRef>>
|
|
|
|
ArgParser::parseDirectives(StringRef S) {
|
|
|
|
std::vector<StringRef> Exports;
|
|
|
|
SmallVector<const char *, 16> Rest;
|
|
|
|
|
|
|
|
for (StringRef Tok : tokenize(S)) {
|
|
|
|
if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:"))
|
|
|
|
Exports.push_back(Tok.substr(strlen("/export:")));
|
|
|
|
else
|
|
|
|
Rest.push_back(Tok.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make InputArgList from unparsed string vectors.
|
2017-12-27 14:08:10 +08:00
|
|
|
unsigned MissingIndex;
|
|
|
|
unsigned MissingCount;
|
|
|
|
|
2018-01-10 04:36:42 +08:00
|
|
|
opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount);
|
2017-12-27 14:08:10 +08:00
|
|
|
|
|
|
|
if (MissingCount)
|
|
|
|
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
|
|
|
|
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
|
|
|
|
warn("ignoring unknown argument: " + Arg->getSpelling());
|
2018-01-10 04:36:42 +08:00
|
|
|
return {std::move(Args), std::move(Exports)};
|
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.
|
2017-09-06 07:46:45 +08:00
|
|
|
opt::InputArgList ArgParser::parseLINK(std::vector<const char *> 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
|
|
|
}
|
2017-09-06 07:46:45 +08:00
|
|
|
return parse(Argv);
|
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;
|
2016-12-09 04:50:47 +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) {
|
2018-10-11 08:58:00 +08:00
|
|
|
COFFOptTable().PrintHelp(outs(),
|
|
|
|
(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
|