aboutsummaryrefslogtreecommitdiff
path: root/COFF/DriverUtils.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:12:21 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:12:21 +0000
commiteb1ff93d02b5f17b6b409e83c6d9be585f4a04b3 (patch)
tree7490b4a8943293f251ad733465936e6ec302b3e9 /COFF/DriverUtils.cpp
parentbafea25f368c63f0b39789906adfed6e39219e64 (diff)
downloadsrc-eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3.tar.gz
src-eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3.zip
Vendor import of lld trunk r321017:vendor/lld/lld-trunk-r321017
Notes
Notes: svn path=/vendor/lld/dist/; revision=326947 svn path=/vendor/lld/lld-trunk-r321017/; revision=326948; tag=vendor/lld/lld-trunk-r321017
Diffstat (limited to 'COFF/DriverUtils.cpp')
-rw-r--r--COFF/DriverUtils.cpp216
1 files changed, 133 insertions, 83 deletions
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index 39d582469640..07783b51c519 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -15,9 +15,9 @@
#include "Config.h"
#include "Driver.h"
-#include "Error.h"
-#include "Memory.h"
#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/BinaryFormat/COFF.h"
@@ -32,12 +32,11 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/WindowsManifest/WindowsManifestMerger.h"
#include <memory>
using namespace llvm::COFF;
using namespace llvm;
-using llvm::cl::ExpandResponseFiles;
-using llvm::cl::TokenizeWindowsCommandLine;
using llvm::sys::Process;
namespace lld {
@@ -58,7 +57,7 @@ public:
void run() {
ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog);
if (auto EC = ExeOrErr.getError())
- fatal(EC, "unable to find " + Prog + " in PATH: ");
+ fatal("unable to find " + Prog + " in PATH: " + EC.message());
StringRef Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
@@ -221,6 +220,22 @@ void parseSection(StringRef S) {
Config->Section[Name] = parseSectionAttributes(Attrs);
}
+// 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);
+}
+
// Parses a string in the form of "EMBED[,=<integer>]|NO".
// Results are directly written to Config.
void parseManifest(StringRef Arg) {
@@ -273,14 +288,14 @@ public:
TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
SmallString<128> S;
if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
- fatal(EC, "cannot create a temporary file");
+ fatal("cannot create a temporary file: " + EC.message());
Path = S.str();
if (!Contents.empty()) {
std::error_code EC;
raw_fd_ostream OS(Path, EC, sys::fs::F_None);
if (EC)
- fatal(EC, "failed to open " + Path);
+ fatal("failed to open " + Path + ": " + EC.message());
OS << Contents;
}
}
@@ -302,7 +317,7 @@ public:
// is called (you cannot remove an opened file on Windows.)
std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
// IsVolatileSize=true forces MemoryBuffer to not use mmap().
- return check(MemoryBuffer::getFile(Path, /*FileSize=*/-1,
+ return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1,
/*RequiresNullTerminator=*/false,
/*IsVolatileSize=*/true),
"could not open " + Path);
@@ -312,16 +327,9 @@ public:
};
}
-// Create the default manifest file as a temporary file.
-TemporaryFile createDefaultXml() {
- // Create a temporary file.
- TemporaryFile File("defaultxml", "manifest");
-
- // Open the temporary file for writing.
- std::error_code EC;
- raw_fd_ostream OS(File.Path, EC, sys::fs::F_Text);
- if (EC)
- fatal(EC, "failed to open " + File.Path);
+static std::string createDefaultXml() {
+ std::string Ret;
+ raw_string_ostream OS(Ret);
// Emit the XML. Note that we do *not* verify that the XML attributes are
// syntactically correct. This is intentional for link.exe compatibility.
@@ -337,46 +345,77 @@ TemporaryFile createDefaultXml() {
<< " </requestedPrivileges>\n"
<< " </security>\n"
<< " </trustInfo>\n";
- if (!Config->ManifestDependency.empty()) {
- OS << " <dependency>\n"
- << " <dependentAssembly>\n"
- << " <assemblyIdentity " << Config->ManifestDependency << " />\n"
- << " </dependentAssembly>\n"
- << " </dependency>\n";
- }
+ }
+ if (!Config->ManifestDependency.empty()) {
+ OS << " <dependency>\n"
+ << " <dependentAssembly>\n"
+ << " <assemblyIdentity " << Config->ManifestDependency << " />\n"
+ << " </dependentAssembly>\n"
+ << " </dependency>\n";
}
OS << "</assembly>\n";
- OS.close();
- return File;
+ return OS.str();
}
-static std::string readFile(StringRef Path) {
- std::unique_ptr<MemoryBuffer> MB =
- check(MemoryBuffer::getFile(Path), "could not open " + Path);
- return MB->getBuffer();
+static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) {
+ std::unique_ptr<MemoryBuffer> DefaultXmlCopy =
+ MemoryBuffer::getMemBufferCopy(DefaultXml);
+
+ windows_manifest::WindowsManifestMerger Merger;
+ if (auto E = Merger.merge(*DefaultXmlCopy.get()))
+ fatal("internal manifest tool failed on default xml: " +
+ toString(std::move(E)));
+
+ for (StringRef Filename : Config->ManifestInput) {
+ std::unique_ptr<MemoryBuffer> Manifest =
+ check(MemoryBuffer::getFile(Filename));
+ if (auto E = Merger.merge(*Manifest.get()))
+ fatal("internal manifest tool failed on file " + Filename + ": " +
+ toString(std::move(E)));
+ }
+
+ return Merger.getMergedManifest().get()->getBuffer();
}
-static std::string createManifestXml() {
- // Create the default manifest file.
- TemporaryFile File1 = createDefaultXml();
- if (Config->ManifestInput.empty())
- return readFile(File1.Path);
+static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) {
+ // 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)
+ fatal("failed to open " + Default.Path + ": " + EC.message());
+ OS << DefaultXml;
+ OS.close();
- // If manifest files are supplied by the user using /MANIFESTINPUT
- // option, we need to merge them with the default manifest.
- TemporaryFile File2("user", "manifest");
+ // 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");
Executor E("mt.exe");
E.add("/manifest");
- E.add(File1.Path);
+ E.add(Default.Path);
for (StringRef Filename : Config->ManifestInput) {
E.add("/manifest");
E.add(Filename);
}
E.add("/nologo");
- E.add("/out:" + StringRef(File2.Path));
+ E.add("/out:" + StringRef(User.Path));
E.run();
- return readFile(File2.Path);
+
+ return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path)
+ .get()
+ ->getBuffer();
+}
+
+static std::string createManifestXml() {
+ std::string DefaultXml = createDefaultXml();
+ if (Config->ManifestInput.empty())
+ return DefaultXml;
+
+ if (windows_manifest::isAvailable())
+ return createManifestXmlWithInternalMt(DefaultXml);
+
+ return createManifestXmlWithExternalMt(DefaultXml);
}
static std::unique_ptr<MemoryBuffer>
@@ -386,7 +425,8 @@ createMemoryBufferForManifestRes(size_t ManifestSize) {
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
sizeof(object::WinResHeaderSuffix) + ManifestSize,
object::WIN_RES_DATA_ALIGNMENT);
- return MemoryBuffer::getNewMemBuffer(ResSize);
+ return MemoryBuffer::getNewMemBuffer(ResSize,
+ Config->OutputFile + ".manifest.res");
}
static void writeResFileHeader(char *&Buf) {
@@ -444,7 +484,7 @@ void createSideBySideManifest() {
std::error_code EC;
raw_fd_ostream Out(Path, EC, sys::fs::F_Text);
if (EC)
- fatal(EC, "failed to create manifest");
+ fatal("failed to create manifest: " + EC.message());
Out << createManifestXml();
}
@@ -459,12 +499,12 @@ Export parseExport(StringRef Arg) {
if (E.Name.empty())
goto err;
- if (E.Name.find('=') != StringRef::npos) {
+ if (E.Name.contains('=')) {
StringRef X, Y;
std::tie(X, Y) = E.Name.split("=");
// If "<name>=<dllname>.<name>".
- if (Y.find(".") != StringRef::npos) {
+ if (Y.contains(".")) {
E.Name = X;
E.ForwardTo = Y;
return E;
@@ -534,7 +574,7 @@ void fixupExports() {
}
for (Export &E : Config->Exports) {
- SymbolBody *Sym = E.Sym;
+ Symbol *Sym = E.Sym;
if (!E.ForwardTo.empty() || !Sym) {
E.SymbolName = E.Name;
} else {
@@ -554,7 +594,7 @@ void fixupExports() {
}
// Uniquefy by name.
- std::map<StringRef, Export *> Map;
+ DenseMap<StringRef, Export *> Map(Config->Exports.size());
std::vector<Export> V;
for (Export &E : Config->Exports) {
auto Pair = Map.insert(std::make_pair(E.ExportName, &E));
@@ -601,10 +641,8 @@ void checkFailIfMismatch(StringRef Arg) {
Config->MustMatch[K] = V;
}
-// Convert Windows resource files (.res files) to a .obj file
-// using cvtres.exe.
-std::unique_ptr<MemoryBuffer>
-convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
+// Convert Windows resource files (.res files) to a .obj file.
+MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) {
object::WindowsResourceParser Parser;
for (MemoryBufferRef MB : MBs) {
@@ -613,14 +651,17 @@ convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
if (!RF)
fatal("cannot compile non-resource file as resource");
if (auto EC = Parser.parse(RF))
- fatal(EC, "failed to parse .res file");
+ fatal("failed to parse .res file: " + toString(std::move(EC)));
}
Expected<std::unique_ptr<MemoryBuffer>> E =
llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser);
if (!E)
- fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF");
- return std::move(E.get());
+ fatal("failed to write .res to COFF: " + toString(E.takeError()));
+
+ MemoryBufferRef MBRef = **E;
+ make<std::unique_ptr<MemoryBuffer>>(std::move(*E)); // take ownership
+ return MBRef;
}
// Run MSVC link.exe for given in-memory object files.
@@ -651,7 +692,7 @@ void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects) {
#undef PREFIX
// Create table mapping all options defined in Options.td
-static const llvm::opt::OptTable::Info infoTable[] = {
+static const llvm::opt::OptTable::Info InfoTable[] = {
#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},
@@ -659,30 +700,49 @@ static const llvm::opt::OptTable::Info infoTable[] = {
#undef OPTION
};
-class COFFOptTable : public llvm::opt::OptTable {
-public:
- COFFOptTable() : OptTable(infoTable, true) {}
-};
+COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {}
-// Parses a given list of options.
-opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
- // First, replace respnose files (@<file>-style options).
- std::vector<const char *> Argv = replaceResponseFiles(ArgsArr);
+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;
+}
+// Parses a given list of options.
+opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
- COFFOptTable Table;
unsigned MissingIndex;
unsigned MissingCount;
- opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
+ SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
+
+ // 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.
+ opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+
+ // Expand response files (arguments in the form of @<filename>)
+ // and then parse the argument again.
+ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+ Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
// Print the real command line if response files are expanded.
- if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) {
+ if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) {
std::string Msg = "Command line:";
- for (const char *S : Argv)
+ for (const char *S : Vec)
Msg += " " + std::string(S);
message(Msg);
}
+ // Handle /WX early since it converts missing argument warnings to errors.
+ errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false);
+
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
@@ -693,17 +753,17 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
// 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.
-opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Args) {
+opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) {
// Concatenate LINK env and command line arguments, and then parse them.
if (Optional<std::string> S = Process::GetEnv("LINK")) {
std::vector<const char *> V = tokenize(*S);
- Args.insert(Args.begin(), V.begin(), V.end());
+ Argv.insert(Argv.begin(), V.begin(), V.end());
}
if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
std::vector<const char *> V = tokenize(*S);
- Args.insert(Args.begin(), V.begin(), V.end());
+ Argv.insert(Argv.begin(), V.begin(), V.end());
}
- return parse(Args);
+ return parse(Argv);
}
std::vector<const char *> ArgParser::tokenize(StringRef S) {
@@ -712,18 +772,8 @@ std::vector<const char *> ArgParser::tokenize(StringRef S) {
return std::vector<const char *>(Tokens.begin(), Tokens.end());
}
-// Creates a new command line by replacing options starting with '@'
-// character. '@<filename>' is replaced by the file's contents.
-std::vector<const char *>
-ArgParser::replaceResponseFiles(std::vector<const char *> Argv) {
- SmallVector<const char *, 256> Tokens(Argv.data(), Argv.data() + Argv.size());
- ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens);
- return std::vector<const char *>(Tokens.begin(), Tokens.end());
-}
-
void printHelp(const char *Argv0) {
- COFFOptTable Table;
- Table.PrintHelp(outs(), Argv0, "LLVM Linker", false);
+ COFFOptTable().PrintHelp(outs(), Argv0, "LLVM Linker", false);
}
} // namespace coff