Index: include/lld/Core/ArchiveLibraryFile.h =================================================================== --- include/lld/Core/ArchiveLibraryFile.h +++ include/lld/Core/ArchiveLibraryFile.h @@ -35,7 +35,7 @@ virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0; virtual std::error_code - parseAllMembers(std::vector> &result) const = 0; + parseAllMembers(std::vector> &result) = 0; /// Returns a set of all defined symbols in the archive, i.e. all /// resolvable symbol using this file. Index: include/lld/Core/File.h =================================================================== --- include/lld/Core/File.h +++ include/lld/Core/File.h @@ -274,7 +274,8 @@ /// can do unit testing a driver using non-existing file paths. class ErrorFile : public File { public: - ErrorFile(StringRef p, std::error_code ec) : File(p, kindObject), _ec(ec) {} + ErrorFile(StringRef path, std::error_code ec) + : File(path, kindObject), _ec(ec) {} std::error_code doParse() override { return _ec; } Index: include/lld/Driver/DarwinInputGraph.h =================================================================== --- include/lld/Driver/DarwinInputGraph.h +++ /dev/null @@ -1,56 +0,0 @@ -//===- lld/Driver/DarwinInputGraph.h - Input Graph Node for Mach-O linker -===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Handles Options for MachO linking and provides InputElements -/// for MachO linker -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_DRIVER_DARWIN_INPUT_GRAPH_H -#define LLD_DRIVER_DARWIN_INPUT_GRAPH_H - -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/InputGraph.h" -#include "lld/ReaderWriter/MachOLinkingContext.h" - -namespace lld { - -/// \brief Represents a MachO File -class MachOFileNode : public FileNode { -public: - MachOFileNode(StringRef path, MachOLinkingContext &ctx) - : FileNode(path), _context(ctx), _isWholeArchive(false), - _upwardDylib(false) {} - - /// \brief Parse the input file to lld::File. - std::error_code parse(const LinkingContext &ctx, - raw_ostream &diagnostics) override; - - void setLoadWholeArchive(bool value=true) { - _isWholeArchive = value; - } - - void setUpwardDylib(bool value=true) { - _upwardDylib = value; - } - -private: - void narrowFatBuffer(std::unique_ptr &mb, StringRef filePath); - - MachOLinkingContext &_context; - std::unique_ptr _archiveFile; - bool _isWholeArchive; - bool _upwardDylib; -}; - -} // namespace lld - -#endif Index: include/lld/Driver/GnuLdInputGraph.h =================================================================== --- include/lld/Driver/GnuLdInputGraph.h +++ /dev/null @@ -1,85 +0,0 @@ -//===- lld/Driver/GnuLdInputGraph.h - Input Graph Node for ELF linker------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Handles Options for the GNU style linker for ELF and provides InputElements -/// for the GNU style linker for ELF -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_DRIVER_GNU_LD_INPUT_GRAPH_H -#define LLD_DRIVER_GNU_LD_INPUT_GRAPH_H - -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/InputGraph.h" -#include "lld/Core/Resolver.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { - -/// \brief Represents a ELF File -class ELFFileNode : public FileNode { -public: - /// \brief The attributes class provides a way for a input file to look into - /// all the positional attributes that were specified in the command line. - /// There are few positional operators and the number of arguments to the - /// ELFFileNode class keeps growing. This achieves code to be clean as well. - class Attributes { - public: - Attributes() - : _isWholeArchive(false), _asNeeded(false), _isDashlPrefix(false), - _isSysRooted(false) {} - void setWholeArchive(bool isWholeArchive) { - _isWholeArchive = isWholeArchive; - } - void setAsNeeded(bool asNeeded) { _asNeeded = asNeeded; } - void setDashlPrefix(bool isDashlPrefix) { _isDashlPrefix = isDashlPrefix; } - void setSysRooted(bool isSysRooted) { _isSysRooted = isSysRooted; } - - public: - bool _isWholeArchive; - bool _asNeeded; - bool _isDashlPrefix; - bool _isSysRooted; - }; - - ELFFileNode(ELFLinkingContext &ctx, StringRef path, Attributes &attributes) - : FileNode(path), _elfLinkingContext(ctx), _attributes(attributes) {} - - ErrorOr getPath(const LinkingContext &ctx) const override; - - /// \brief create an error string for printing purposes - std::string errStr(std::error_code) override; - - /// \brief Dump the Input Element - bool dump(raw_ostream &diagnostics) override { - diagnostics << "Name : " << *getPath(_elfLinkingContext) << "\n" - << "Type : ELF File\n" - << "Attributes :\n" - << " - wholeArchive : " - << ((_attributes._isWholeArchive) ? "true" : "false") << "\n" - << " - asNeeded : " - << ((_attributes._asNeeded) ? "true" : "false") << "\n"; - return true; - } - - /// \brief Parse the input file to lld::File. - std::error_code parse(const LinkingContext &, raw_ostream &) override; - -private: - llvm::BumpPtrAllocator _alloc; - const ELFLinkingContext &_elfLinkingContext; - std::unique_ptr _archiveFile; - const Attributes _attributes; -}; - -} // namespace lld - -#endif Index: include/lld/Driver/WinLinkInputGraph.h =================================================================== --- include/lld/Driver/WinLinkInputGraph.h +++ /dev/null @@ -1,45 +0,0 @@ -//===- lld/Driver/WinLinkInputGraph.h - Input Graph Node for COFF linker --===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Handles Options for PECOFF linking and provides InputElements -/// for PECOFF linker -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H -#define LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H - -#include "lld/Core/InputGraph.h" -#include "lld/ReaderWriter/PECOFFLinkingContext.h" -#include - -namespace lld { - -/// \brief Represents a PECOFF File -class PECOFFFileNode : public FileNode { -public: - PECOFFFileNode(PECOFFLinkingContext &ctx, StringRef path) - : FileNode(path), _ctx(ctx), _parsed(false) {} - - /// \brief Parse the input file to lld::File. - std::error_code parse(const LinkingContext &ctx, - raw_ostream &diagnostics) override; - -protected: - const PECOFFLinkingContext &_ctx; - -private: - bool _parsed; -}; - -} // namespace lld - -#endif Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -290,6 +290,28 @@ bool alignSegments() const { return _alignSegments; } void setAlignSegments(bool align) { _alignSegments = align; } + /// \brief The attributes class provides a way for a input file to look into + /// all the positional attributes that were specified in the command line. + /// There are few positional operators and the number of arguments to the + /// ELFFileNode class keeps growing. This achieves code to be clean as well. + class Attributes { + public: + Attributes() + : _isWholeArchive(false), _asNeeded(false), _isDashlPrefix(false), + _isSysRooted(false) {} + void setWholeArchive(bool isWholeArchive) { + _isWholeArchive = isWholeArchive; + } + void setAsNeeded(bool asNeeded) { _asNeeded = asNeeded; } + void setDashlPrefix(bool isDashlPrefix) { _isDashlPrefix = isDashlPrefix; } + void setSysRooted(bool isSysRooted) { _isSysRooted = isSysRooted; } + + bool _isWholeArchive; + bool _asNeeded; + bool _isDashlPrefix; + bool _isSysRooted; + }; + private: ELFLinkingContext() LLVM_DELETED_FUNCTION; Index: include/lld/ReaderWriter/MachOLinkingContext.h =================================================================== --- include/lld/ReaderWriter/MachOLinkingContext.h +++ include/lld/ReaderWriter/MachOLinkingContext.h @@ -350,7 +350,7 @@ mutable llvm::StringMap _pathToDylibMap; mutable std::set _allDylibs; mutable std::set _upwardDylibs; - mutable std::vector> _indirectDylibs; + mutable std::vector> _indirectDylibs; ExportMode _exportMode; llvm::StringSet<> _exportedSymbols; DebugInfoMode _debugInfoMode; Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -12,14 +12,11 @@ add_lld_library(lldDriver CoreDriver.cpp - DarwinInputGraph.cpp DarwinLdDriver.cpp Driver.cpp GnuLdDriver.cpp - GnuLdInputGraph.cpp UniversalDriver.cpp WinLinkDriver.cpp - WinLinkInputGraph.cpp WinLinkModuleDef.cpp ) Index: lib/Driver/DarwinInputGraph.cpp =================================================================== --- lib/Driver/DarwinInputGraph.cpp +++ /dev/null @@ -1,83 +0,0 @@ -//===- lib/ReaderWriter/MachO/DarwinInputGraph.cpp ------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Driver/DarwinInputGraph.h" -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/Reference.h" -#include "lld/Core/SharedLibraryFile.h" - -namespace lld { - - -/// \brief Parse the input file to lld::File. -std::error_code MachOFileNode::parse(const LinkingContext &ctx, - raw_ostream &diagnostics) { - ErrorOr filePath = getPath(ctx); - if (std::error_code ec = filePath.getError()) - return ec; - ErrorOr> mbOrErr = - MemoryBuffer::getFileOrSTDIN(*filePath); - if (std::error_code ec = mbOrErr.getError()) - return ec; - std::unique_ptr mb = std::move(mbOrErr.get()); - - _context.addInputFileDependency(*filePath); - if (ctx.logInputFiles()) - diagnostics << *filePath << "\n"; - - narrowFatBuffer(mb, *filePath); - - std::vector> parsedFiles; - if (std::error_code ec = ctx.registry().parseFile(std::move(mb), parsedFiles)) - return ec; - for (std::unique_ptr &pf : parsedFiles) { - // If file is a dylib, inform LinkingContext about it. - if (SharedLibraryFile *shl = dyn_cast(pf.get())) { - _context.registerDylib(reinterpret_cast(shl), - _upwardDylib); - } - // If file is an archive and -all_load, then add all members. - if (ArchiveLibraryFile *archive = dyn_cast(pf.get())) { - if (_isWholeArchive) { - // Have this node own the FileArchive object. - _archiveFile.reset(archive); - pf.release(); - // Add all members to _files vector - return archive->parseAllMembers(_files); - } - } - _files.push_back(std::move(pf)); - } - return std::error_code(); -} - - -/// If buffer contains a fat file, find required arch in fat buffer and -/// switch buffer to point to just that required slice. -void MachOFileNode::narrowFatBuffer(std::unique_ptr &mb, - StringRef filePath) { - // Check if buffer is a "fat" file that contains needed arch. - uint32_t offset; - uint32_t size; - if (!_context.sliceFromFatFile(*mb, offset, size)) { - return; - } - // Create new buffer containing just the needed slice. - auto subuf = MemoryBuffer::getFileSlice(filePath, size, offset); - if (subuf.getError()) - return; - // The assignment to mb will release previous buffer. - mb = std::move(subuf.get()); -} - - -} // end namesapce lld Index: lib/Driver/DarwinLdDriver.cpp =================================================================== --- lib/Driver/DarwinLdDriver.cpp +++ lib/Driver/DarwinLdDriver.cpp @@ -13,8 +13,11 @@ /// //===----------------------------------------------------------------------===// +#include "lld/Core/File.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/SharedLibraryFile.h" #include "lld/Driver/Driver.h" -#include "lld/Driver/DarwinInputGraph.h" +#include "lld/Driver/WrapperInputGraph.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -22,6 +25,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" @@ -68,6 +72,50 @@ DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; +std::vector> +parseFiles(MachOLinkingContext &ctx, StringRef path, + raw_ostream &diag, bool wholeArchive, bool upwardDylib) { + ErrorOr> mbOrErr = + MemoryBuffer::getFileOrSTDIN(path); + if (std::error_code ec = mbOrErr.getError()) + return makeErrorFile(path, ec); + std::unique_ptr mb = std::move(mbOrErr.get()); + + ctx.addInputFileDependency(path); + if (ctx.logInputFiles()) + diag << path << "\n"; + + // If buffer contains a fat file, find required arch in fat buffer + // and switch buffer to point to just that required slice. + // Check if buffer is a "fat" file that contains needed arch. + uint32_t offset; + uint32_t size; + if (ctx.sliceFromFatFile(*mb, offset, size)) { + // Create new buffer containing just the needed slice. + auto subuf = MemoryBuffer::getFileSlice(path, size, offset); + if (std::error_code ec = subuf.getError()) + return makeErrorFile(path, ec); + // The assignment to mb will release previous buffer. + mb = std::move(subuf.get()); + } + + std::vector> files; + if (std::error_code ec = ctx.registry().parseFile(std::move(mb), files)) + return makeErrorFile(path, ec); + for (std::unique_ptr &pf : files) { + // If file is a dylib, inform LinkingContext about it. + if (SharedLibraryFile *shl = dyn_cast(pf.get())) { + if (std::error_code ec = shl->parse()) + return makeErrorFile(path, ec); + ctx.registerDylib(reinterpret_cast(shl), + upwardDylib); + } + } + if (wholeArchive) + return parseMemberFiles(files); + return files; +} + } // anonymous namespace // Test may be running on Windows. Canonicalize the path @@ -85,13 +133,12 @@ static void addFile(StringRef path, std::unique_ptr &inputGraph, MachOLinkingContext &ctx, bool loadWholeArchive, - bool upwardDylib) { - auto node = llvm::make_unique(path, ctx); - if (loadWholeArchive) - node->setLoadWholeArchive(); - if (upwardDylib) - node->setUpwardDylib(); - inputGraph->addInputElement(std::move(node)); + bool upwardDylib, raw_ostream &diag) { + std::vector> files = + parseFiles(ctx, path, diag, loadWholeArchive, upwardDylib); + for (std::unique_ptr &file : files) + inputGraph->addInputElement( + llvm::make_unique(std::move(file))); } // Export lists are one symbol per line. Blank lines are ignored. @@ -222,7 +269,7 @@ if (ctx.testingFileUsage()) { diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; } - addFile(path, inputGraph, ctx, forceLoad, false); + addFile(path, inputGraph, ctx, forceLoad, false, diagnostics); buffer = lineAndRest.second; } return std::error_code(); @@ -244,13 +291,6 @@ return false; if (ctx.doNothing()) return true; - - // Register possible input file parsers. - ctx.registry().addSupportMachOObjects(ctx); - ctx.registry().addSupportArchives(ctx.logInputFiles()); - ctx.registry().addSupportNativeObjects(); - ctx.registry().addSupportYamlFiles(); - return link(ctx, diagnostics); } @@ -310,15 +350,15 @@ } } // If no -arch specified, scan input files to find first non-fat .o file. - if ((arch == MachOLinkingContext::arch_unknown) - && !parsedArgs->getLastArg(OPT_test_file_usage)) { + if (arch == MachOLinkingContext::arch_unknown) { for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) { // This is expensive because it opens and maps the file. But that is // ok because no -arch is rare. if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch)) break; } - if (arch == MachOLinkingContext::arch_unknown) { + if (arch == MachOLinkingContext::arch_unknown + && !parsedArgs->getLastArg(OPT_test_file_usage)) { // If no -arch and no options at all, print usage message. if (parsedArgs->size() == 0) table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false); @@ -521,6 +561,13 @@ } } + // Register possible input file parsers. + if (!ctx.doNothing()) { + ctx.registry().addSupportMachOObjects(ctx); + ctx.registry().addSupportArchives(ctx.logInputFiles()); + ctx.registry().addSupportNativeObjects(); + ctx.registry().addSupportYamlFiles(); + } std::unique_ptr inputGraph(new InputGraph()); // Now construct the set of library search directories, following ld64's @@ -745,13 +792,13 @@ default: continue; case OPT_INPUT: - addFile(arg->getValue(), inputGraph, ctx, globalWholeArchive, false); + addFile(arg->getValue(), inputGraph, ctx, globalWholeArchive, false, diagnostics); break; case OPT_upward_library: - addFile(arg->getValue(), inputGraph, ctx, false, true); + addFile(arg->getValue(), inputGraph, ctx, false, true, diagnostics); break; case OPT_force_load: - addFile(arg->getValue(), inputGraph, ctx, true, false); + addFile(arg->getValue(), inputGraph, ctx, true, false, diagnostics); break; case OPT_l: case OPT_upward_l: @@ -765,7 +812,7 @@ diagnostics << "Found " << (upward ? "upward " : " ") << "library " << canonicalizePath(resolvedPath.get()) << '\n'; } - addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward); + addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward, diagnostics); break; case OPT_framework: case OPT_upward_framework: @@ -779,7 +826,7 @@ diagnostics << "Found " << (upward ? "upward " : " ") << "framework " << canonicalizePath(resolvedPath.get()) << '\n'; } - addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward); + addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward, diagnostics); break; case OPT_filelist: if (std::error_code ec = parseFileList(arg->getValue(), inputGraph, Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -14,7 +14,8 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" -#include "lld/Driver/GnuLdInputGraph.h" +#include "lld/Driver/WrapperInputGraph.h" +#include "lld/ReaderWriter/ELFLinkingContext.h" #include "lld/ReaderWriter/LinkerScript.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" @@ -172,16 +173,6 @@ return false; if (!options) return true; - - // Register possible input file parsers. - options->registry().addSupportELFObjects(options->mergeCommonStrings(), - options->targetHandler()); - options->registry().addSupportArchives(options->logInputFiles()); - options->registry().addSupportYamlFiles(); - options->registry().addSupportNativeObjects(); - if (options->allowLinkWithDynamicLibraries()) - options->registry().addSupportELFDynamicSharedObjects( - options->useShlibUndefines(), options->targetHandler()); return link(*options, diagnostics); } @@ -218,6 +209,23 @@ return magic == llvm::sys::fs::file_magic::unknown; } +static ErrorOr +findFile(ELFLinkingContext &ctx, StringRef path, bool dashL) { + // If the path was referred to by using a -l argument, let's search + // for the file in the search path. + if (dashL) { + ErrorOr pathOrErr = ctx.searchLibrary(path); + if (std::error_code ec = pathOrErr.getError()) + return make_dynamic_error_code( + Twine("Unable to find library -l") + path + ": " + ec.message()); + path = pathOrErr->str(); + } + if (!llvm::sys::fs::exists(path)) + return make_dynamic_error_code( + Twine("lld: cannot find file ") + path); + return path; +} + static bool isPathUnderSysroot(StringRef sysroot, StringRef path) { if (sysroot.empty()) return false; @@ -234,8 +242,6 @@ MemoryBuffer::getFileOrSTDIN(path); if (std::error_code ec = mb.getError()) return ec; - if (ctx.logInputFiles()) - diag << path << "\n"; auto lexer = llvm::make_unique(std::move(mb.get())); auto parser = llvm::make_unique(*lexer); script::LinkerScript *script = parser->parse(); @@ -253,13 +259,26 @@ int numfiles = 0; for (const script::Path &path : group->getPaths()) { // TODO : Propagate Set WholeArchive/dashlPrefix - ELFFileNode::Attributes attr; + ELFLinkingContext::Attributes attr; attr.setSysRooted(sysroot); attr.setAsNeeded(path._asNeeded); attr.setDashlPrefix(path._isDashlPrefix); - ++numfiles; - inputGraph->addInputElement(llvm::make_unique( - ctx, ctx.allocateString(path._path), attr)); + + ErrorOr pathOrErr = path._isDashlPrefix + ? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot); + if (std::error_code ec = pathOrErr.getError()) + return make_dynamic_error_code( + Twine("Unable to find file ") + path._path + ": " + ec.message()); + + std::vector> files + = parseFile(ctx, pathOrErr.get(), false); + for (std::unique_ptr &file : files) { + if (ctx.logInputFiles()) + diag << file->path() << "\n"; + inputGraph->addInputElement( + std::unique_ptr(new WrapperNode(std::move(file)))); + ++numfiles; + } } inputGraph->addInputElement(llvm::make_unique(numfiles)); } @@ -341,7 +360,7 @@ std::stack groupStack; int numfiles = 0; - ELFFileNode::Attributes attributes; + ELFLinkingContext::Attributes attributes; bool _outputOptionSet = false; @@ -379,7 +398,6 @@ ctx->setPrintRemainingUndefines(false); ctx->setAllowRemainingUndefines(true); break; - case OPT_static: ctx->setOutputELFType(llvm::ELF::ET_EXEC); ctx->setIsStaticExecutable(true); @@ -415,6 +433,37 @@ } } + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_merge_strings: + ctx->setMergeCommonStrings(true); + break; + case OPT_t: + ctx->setLogInputFiles(true); + break; + case OPT_use_shlib_undefs: + ctx->setUseShlibUndefines(true); + break; + case OPT_no_allow_shlib_undefs: + ctx->setAllowShlibUndefines(false); + break; + case OPT_allow_shlib_undefs: + ctx->setAllowShlibUndefines(true); + break; + } + } + + // Register possible input file parsers. + ctx->registry().addSupportELFObjects( + ctx->mergeCommonStrings(), + ctx->targetHandler()); + ctx->registry().addSupportArchives(ctx->logInputFiles()); + ctx->registry().addSupportYamlFiles(); + ctx->registry().addSupportNativeObjects(); + if (ctx->allowLinkWithDynamicLibraries()) + ctx->registry().addSupportELFDynamicSharedObjects( + ctx->useShlibUndefines(), ctx->targetHandler()); + // Process all the arguments and create Input Elements for (auto inputArg : *parsedArgs) { switch (inputArg->getOption().getID()) { @@ -438,26 +487,6 @@ ctx->setExportDynamic(true); break; - case OPT_merge_strings: - ctx->setMergeCommonStrings(true); - break; - - case OPT_t: - ctx->setLogInputFiles(true); - break; - - case OPT_no_allow_shlib_undefs: - ctx->setAllowShlibUndefines(false); - break; - - case OPT_allow_shlib_undefs: - ctx->setAllowShlibUndefines(true); - break; - - case OPT_use_shlib_undefs: - ctx->setUseShlibUndefines(true); - break; - case OPT_allow_multiple_definition: ctx->setAllowDuplicates(true); break; @@ -560,25 +589,19 @@ bool dashL = (inputArg->getOption().getID() == OPT_l); attributes.setDashlPrefix(dashL); StringRef path = inputArg->getValue(); - std::string realpath = path; - - // If the path was referred to by using a -l argument, let's search - // for the file in the search path. - if (dashL) { - ErrorOr pathOrErr = ctx->searchLibrary(path); - if (!pathOrErr) { - diagnostics << " Unable to find library -l" << path << "\n"; - return false; - } - realpath = pathOrErr->str(); - } - if (!llvm::sys::fs::exists(realpath)) { - diagnostics << "lld: cannot find file " << path << "\n"; + + ErrorOr pathOrErr = findFile(*ctx, path, dashL); + if (std::error_code ec = pathOrErr.getError()) { + diagnostics << ec.message() << "\n"; return false; } + std::string realpath = pathOrErr.get(); + bool isScript = (!path.endswith(".objtxt") && isLinkerScript(realpath, diagnostics)); if (isScript) { + if (ctx->logInputFiles()) + diagnostics << path << "\n"; std::error_code ec = evaluateLinkerScript( *ctx, inputGraph.get(), realpath, diagnostics); if (ec) { @@ -588,9 +611,15 @@ } break; } - ++numfiles; - inputGraph->addInputElement( - llvm::make_unique(*ctx, path, attributes)); + std::vector> files + = parseFile(*ctx, realpath, attributes._isWholeArchive); + for (std::unique_ptr &file : files) { + if (ctx->logInputFiles()) + diagnostics << file->path() << "\n"; + inputGraph->addInputElement( + std::unique_ptr(new WrapperNode(std::move(file)))); + } + numfiles += files.size(); break; } Index: lib/Driver/GnuLdInputGraph.cpp =================================================================== --- lib/Driver/GnuLdInputGraph.cpp +++ /dev/null @@ -1,65 +0,0 @@ -//===- lib/Driver/GnuLdInputGraph.cpp -------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Driver/GnuLdInputGraph.h" -#include "lld/ReaderWriter/LinkerScript.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" - -using namespace lld; - -llvm::ErrorOr ELFFileNode::getPath(const LinkingContext &) const { - if (_attributes._isDashlPrefix) - return _elfLinkingContext.searchLibrary(_path); - return _elfLinkingContext.searchFile(_path, _attributes._isSysRooted); -} - -std::string ELFFileNode::errStr(std::error_code errc) { - if (errc == llvm::errc::no_such_file_or_directory) { - if (_attributes._isDashlPrefix) - return (Twine("Unable to find library -l") + _path).str(); - return (Twine("Unable to find file ") + _path).str(); - } - return FileNode::errStr(errc); -} - -/// \brief Parse the input file to lld::File. -std::error_code ELFFileNode::parse(const LinkingContext &ctx, - raw_ostream &diagnostics) { - ErrorOr filePath = getPath(ctx); - if (std::error_code ec = filePath.getError()) - return ec; - ErrorOr> mb = - MemoryBuffer::getFileOrSTDIN(*filePath); - if (std::error_code ec = mb.getError()) - return ec; - if (ctx.logInputFiles()) - diagnostics << *filePath << "\n"; - - if (_attributes._isWholeArchive) { - std::vector> parsedFiles; - if (std::error_code ec = ctx.registry().parseFile( - std::move(mb.get()), parsedFiles)) - return ec; - assert(parsedFiles.size() == 1); - std::unique_ptr f(parsedFiles[0].release()); - if (const auto *archive = dyn_cast(f.get())) { - // Have this node own the FileArchive object. - _archiveFile.reset(archive); - f.release(); - // Add all members to _files vector - return archive->parseAllMembers(_files); - } - // if --whole-archive is around non-archive, just use it as normal. - _files.push_back(std::move(f)); - return std::error_code(); - } - return ctx.registry().parseFile(std::move(mb.get()), _files); -} Index: lib/Driver/WinLinkDriver.cpp =================================================================== --- lib/Driver/WinLinkDriver.cpp +++ lib/Driver/WinLinkDriver.cpp @@ -14,8 +14,8 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" -#include "lld/Driver/WinLinkInputGraph.h" #include "lld/Driver/WinLinkModuleDef.h" +#include "lld/Driver/WrapperInputGraph.h" #include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" @@ -800,13 +800,11 @@ // Returns true if the given file node has already been added to the input // graph. -static bool hasLibrary(const PECOFFLinkingContext &ctx, FileNode *fileNode) { - ErrorOr path = fileNode->getPath(ctx); - if (!path) - return false; +static bool hasLibrary(const PECOFFLinkingContext &ctx, File *file) { + StringRef path = file->path(); for (std::unique_ptr &p : ctx.getInputGraph().inputElements()) if (auto *f = dyn_cast(p.get())) - if (*path == *f->getPath(ctx)) + if (*f->getPath(ctx) == path) return true; return false; } @@ -838,6 +836,16 @@ return true; } +/// \brief Parse the input file to lld::File. +void addFiles(PECOFFLinkingContext &ctx, StringRef path, raw_ostream &diag, + std::vector> &files) { + for (std::unique_ptr &file : parseFile(ctx, path, false)) { + if (ctx.logInputFiles()) + diag << file->path() << "\n"; + files.push_back(std::move(file)); + } +} + // // Main driver // @@ -847,6 +855,12 @@ return true; PECOFFLinkingContext ctx; + ctx.registry().addSupportCOFFObjects(ctx); + ctx.registry().addSupportCOFFImportLibraries(ctx); + ctx.registry().addSupportArchives(ctx.logInputFiles()); + ctx.registry().addSupportNativeObjects(); + ctx.registry().addSupportYamlFiles(); + std::vector newargv = processLinkEnv(ctx, argc, argv); processLibEnv(ctx); if (!parse(newargv.size() - 1, &newargv[0], ctx, diag)) @@ -857,13 +871,6 @@ if (!createSideBySideManifestFile(ctx, diag)) return false; - // Register possible input file parsers. - ctx.registry().addSupportCOFFObjects(ctx); - ctx.registry().addSupportCOFFImportLibraries(ctx); - ctx.registry().addSupportArchives(ctx.logInputFiles()); - ctx.registry().addSupportNativeObjects(); - ctx.registry().addSupportYamlFiles(); - return link(ctx, diag); } @@ -884,8 +891,8 @@ return false; // The list of input files. - std::vector > files; - std::vector > libraries; + std::vector> files; + std::vector> libraries; // Handle /help if (parsedArgs->getLastArg(OPT_help)) { @@ -1363,11 +1370,9 @@ for (StringRef path : inputFiles) { path = ctx.allocate(path); if (isLibraryFile(path)) { - libraries.push_back(std::unique_ptr( - new PECOFFFileNode(ctx, getLibraryPath(ctx, path)))); + addFiles(ctx, getLibraryPath(ctx, path), diag, libraries); } else { - files.push_back(std::unique_ptr( - new PECOFFFileNode(ctx, getObjectPath(ctx, path)))); + addFiles(ctx, getObjectPath(ctx, path), diag, files); } } @@ -1389,8 +1394,7 @@ if (!ctx.getNoDefaultLibAll()) for (const StringRef path : defaultLibs) if (!ctx.hasNoDefaultLib(path)) - libraries.push_back(std::unique_ptr( - new PECOFFFileNode(ctx, getLibraryPath(ctx, path.lower())))); + addFiles(ctx, getLibraryPath(ctx, path.lower()), diag, libraries); if (files.empty() && !isReadingDirectiveSection) { diag << "No input files\n"; @@ -1401,18 +1405,19 @@ // constructed by replacing an extension of the first input file // with ".exe". if (ctx.outputPath().empty()) { - StringRef path = *cast(&*files[0])->getPath(ctx); + StringRef path = files[0]->path(); ctx.setOutputPath(replaceExtension(ctx, path, ".exe")); } // Add the input files to the input graph. if (!ctx.hasInputGraph()) ctx.setInputGraph(std::unique_ptr(new InputGraph())); - for (std::unique_ptr &file : files) { + for (std::unique_ptr &file : files) { if (isReadingDirectiveSection) - if (file->parse(ctx, diag)) + if (file->parse()) return false; - ctx.getInputGraph().addInputElement(std::move(file)); + ctx.getInputGraph().addInputElement( + std::unique_ptr(new WrapperNode(std::move(file)))); } // Add the library group to the input graph. @@ -1427,12 +1432,13 @@ } // Add the library files to the library group. - for (std::unique_ptr &lib : libraries) { - if (!hasLibrary(ctx, lib.get())) { + for (std::unique_ptr &file : libraries) { + if (!hasLibrary(ctx, file.get())) { if (isReadingDirectiveSection) - if (lib->parse(ctx, diag)) + if (file->parse()) return false; - ctx.addLibraryFile(std::move(lib)); + ctx.addLibraryFile( + std::unique_ptr(new WrapperNode(std::move(file)))); } } Index: lib/Driver/WinLinkInputGraph.cpp =================================================================== --- lib/Driver/WinLinkInputGraph.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===- lib/Driver/WinLinkInputGraph.cpp -----------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Driver/WinLinkInputGraph.h" - -namespace lld { - -/// \brief Parse the input file to lld::File. -std::error_code PECOFFFileNode::parse(const LinkingContext &ctx, - raw_ostream &diagnostics) { - if (_parsed) - return std::error_code(); - _parsed = true; - ErrorOr filePath = getPath(ctx); - if (std::error_code ec = filePath.getError()) { - diagnostics << "File not found: " << _path << "\n"; - return ec; - } - - ErrorOr> mb = - MemoryBuffer::getFileOrSTDIN(*filePath); - if (std::error_code ec = mb.getError()) { - diagnostics << "Cannot open file: " << *filePath << "\n"; - return ec; - } - - if (ctx.logInputFiles()) - diagnostics << *filePath << "\n"; - - return ctx.registry().parseFile(std::move(mb.get()), _files); -} - -} // end anonymous namespace Index: lib/Passes/RoundTripNativePass.cpp =================================================================== --- lib/Passes/RoundTripNativePass.cpp +++ lib/Passes/RoundTripNativePass.cpp @@ -47,6 +47,8 @@ llvm_unreachable("native reader not registered or read error"); } File *objFile = _nativeFile[0].get(); + if (objFile->parse()) + llvm_unreachable("native reader parse error"); mergedFile.reset(new SimpleFileWrapper(_context, *objFile)); llvm::sys::fs::remove(tmpNativeFile.str()); Index: lib/Passes/RoundTripYAMLPass.cpp =================================================================== --- lib/Passes/RoundTripYAMLPass.cpp +++ lib/Passes/RoundTripYAMLPass.cpp @@ -47,6 +47,8 @@ llvm_unreachable("yaml reader not registered or read error"); } File *objFile = _yamlFile[0].get(); + if (objFile->parse()) + llvm_unreachable("native reader parse error"); mergedFile.reset(new SimpleFileWrapper(_context, *objFile)); llvm::sys::fs::remove(tmpYAMLFile.str()); } Index: lib/ReaderWriter/FileArchive.cpp =================================================================== --- lib/ReaderWriter/FileArchive.cpp +++ lib/ReaderWriter/FileArchive.cpp @@ -67,7 +67,9 @@ /// \brief parse each member std::error_code - parseAllMembers(std::vector> &result) const override { + parseAllMembers(std::vector> &result) override { + if (std::error_code ec = parse()) + return ec; for (auto mf = _archive->child_begin(), me = _archive->child_end(); mf != me; ++mf) { std::unique_ptr file; @@ -152,9 +154,12 @@ mb.getBuffer(), memberPath, false)); std::vector> files; - _registry.parseFile(std::move(memberMB), files); + if (std::error_code ec = _registry.parseFile(std::move(memberMB), files)) + return ec; assert(files.size() == 1); result = std::move(files[0]); + if (std::error_code ec = result->parse()) + return ec; // The memory buffer is co-owned by the archive file and the children, // so that the bufffer is deallocated when all the members are destructed. Index: lib/ReaderWriter/MachO/ExecutableAtoms.hpp =================================================================== --- lib/ReaderWriter/MachO/ExecutableAtoms.hpp +++ lib/ReaderWriter/MachO/ExecutableAtoms.hpp @@ -91,7 +91,7 @@ } std::error_code - parseAllMembers(std::vector> &result) const override { + parseAllMembers(std::vector> &result) override { return std::error_code(); } Index: lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -12,8 +12,8 @@ #include "File.h" #include "MachONormalizedFile.h" #include "MachOPasses.h" +#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/PassManager.h" -#include "lld/Driver/DarwinInputGraph.h" #include "lld/Passes/LayoutPass.h" #include "lld/Passes/RoundTripYAMLPass.h" #include "lld/ReaderWriter/Reader.h" @@ -605,20 +605,18 @@ } MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) { - std::unique_ptr node(new MachOFileNode(path, *this)); - std::error_code ec = node->parse(*this, llvm::errs()); - if (ec) + ErrorOr> mbOrErr + = MemoryBuffer::getFileOrSTDIN(path); + if (mbOrErr.getError()) return nullptr; - assert(node->files().size() == 1 && "expected one file in dylib"); - // lld::File object is owned by MachOFileNode object. This method returns - // an unowned pointer to the lld::File object. - MachODylibFile* result = reinterpret_cast( - node->files().front().get()); - + std::vector> files; + if (registry().parseFile(std::move(mbOrErr.get()), files)) + return nullptr; + assert(files.size() == 1 && "expected one file in dylib"); + MachODylibFile* result = reinterpret_cast(files[0].get()); // Node object now owned by _indirectDylibs vector. - _indirectDylibs.push_back(std::move(node)); - + _indirectDylibs.push_back(std::move(files[0])); return result; } Index: lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h =================================================================== --- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h +++ lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h @@ -88,7 +88,7 @@ } std::error_code - parseAllMembers(std::vector> &result) const override { + parseAllMembers(std::vector> &result) override { return std::error_code(); } Index: lib/ReaderWriter/Reader.cpp =================================================================== --- lib/ReaderWriter/Reader.cpp +++ lib/ReaderWriter/Reader.cpp @@ -44,9 +44,6 @@ continue; if (std::error_code ec = reader->parseFile(std::move(mb), *this, result)) return ec; - for (std::unique_ptr &file : result) - if (std::error_code ec = file->parse()) - return ec; return std::error_code(); } Index: lib/ReaderWriter/YAML/ReaderWriterYAML.cpp =================================================================== --- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -648,7 +648,7 @@ } virtual std::error_code - parseAllMembers(std::vector> &result) const override { + parseAllMembers(std::vector> &result) override { return std::error_code(); } Index: test/Driver/libsearch-inputGraph.test =================================================================== --- test/Driver/libsearch-inputGraph.test +++ /dev/null @@ -1,39 +0,0 @@ -RUN: lld -flavor gnu -target x86_64-linux -L%p/../elf/Inputs -lfnarchive \ -RUN: --output-filetype=yaml --noinhibit-exec 2> %t.err -RUN: FileCheck %s < %t.err - -RUN: lld -flavor gnu -target x86_64-linux -L%p/../elf/Inputs --whole-archive \ -RUN: -lfnarchive --output-filetype=yaml --noinhibit-exec 2> %t1.err -RUN: FileCheck %s -check-prefix="WHOLEARCHIVE" < %t1.err - -RUN: lld -flavor gnu -target x86_64-linux -L%p/../elf/Inputs --whole-archive \ -RUN: --as-needed -lfnarchive --output-filetype=yaml --noinhibit-exec 2> %t2.err -RUN: FileCheck %s -check-prefix="ASNEEDED" < %t2.err - -RUN: lld -flavor gnu -target x86_64-linux --sysroot=%p/../elf -L=/Inputs \ -RUN: -lfnarchive --output-filetype=yaml --noinhibit-exec 2> %t3.err -RUN: FileCheck -check-prefix="SYSROOT" %s < %t3.err - -CHECK: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a -CHECK: Type : ELF File -CHECK: Attributes : -CHECK: - wholeArchive : false -CHECK: - asNeeded : false - -WHOLEARCHIVE: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a -WHOLEARCHIVE: Type : ELF File -WHOLEARCHIVE: Attributes : -WHOLEARCHIVE: - wholeArchive : true -WHOLEARCHIVE: - asNeeded : false - -ASNEEDED: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a -ASNEEDED: Type : ELF File -ASNEEDED: Attributes : -ASNEEDED: - wholeArchive : true -ASNEEDED: - asNeeded : true - -SYSROOT: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a -SYSROOT: Type : ELF File -SYSROOT: Attributes : -SYSROOT: - wholeArchive : false -SYSROOT: - asNeeded : false Index: test/pecoff/hello64.test =================================================================== --- test/pecoff/hello64.test +++ test/pecoff/hello64.test @@ -12,9 +12,9 @@ CHECK: 601f: e8 0a 00 00 00 callq 10 CHECK: 6024: b9 00 00 00 00 movl $0, %ecx CHECK: 6029: e8 08 00 00 00 callq 8 -CHECK: 602e: ff 25 d4 cf ff ff jmpq *-12332(%rip) +CHECK: 602e: ff 25 d2 cf ff ff jmpq *-12334(%rip) CHECK: 6034: cc int3 CHECK: 6035: cc int3 -CHECK: 6036: ff 25 c4 cf ff ff jmpq *-12348(%rip) +CHECK: 6036: ff 25 c2 cf ff ff jmpq *-12350(%rip) CHECK: 603c: cc int3 CHECK: 603d: cc int3 Index: unittests/DriverTests/WinLinkDriverTest.cpp =================================================================== --- unittests/DriverTests/WinLinkDriverTest.cpp +++ unittests/DriverTests/WinLinkDriverTest.cpp @@ -698,10 +698,9 @@ // compatibility with link.exe. EXPECT_TRUE(parse("link.exe", "/nologo", "/errorreport:prompt", "/incremental", "/incremental:no", "/delay:unload", - "/disallowlib:foo", "/pdbaltpath:bar", "/verbose", - "/verbose:icf", "/wx", "/wx:no", "/tlbid:1", - "/tlbout:foo", "/idlout:foo", "/ignore:4000", - "/ignoreidl", "/implib:foo", "/safeseh", + "/disallowlib:foo", "/pdbaltpath:bar", + "/wx", "/wx:no", "/tlbid:1", "/tlbout:foo", "/idlout:foo", + "/ignore:4000", "/ignoreidl", "/implib:foo", "/safeseh", "/safeseh:no", "/functionpadmin", "/maxilksize:1024", "a.obj", nullptr)); EXPECT_EQ("", errorMessage());