diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:12:21 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:12:21 +0000 |
commit | eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3 (patch) | |
tree | 7490b4a8943293f251ad733465936e6ec302b3e9 /COFF/DriverUtils.cpp | |
parent | bafea25f368c63f0b39789906adfed6e39219e64 (diff) | |
download | src-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.cpp | 216 |
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 |