diff options
-rw-r--r-- | lld/include/lld/Core/Error.h | 13 | ||||
-rw-r--r-- | lld/include/lld/Core/File.h | 7 | ||||
-rw-r--r-- | lld/include/lld/Driver/GnuLdInputGraph.h | 72 | ||||
-rw-r--r-- | lld/include/lld/ReaderWriter/ELFLinkingContext.h | 11 | ||||
-rw-r--r-- | lld/include/lld/ReaderWriter/ReaderLinkerScript.h | 34 | ||||
-rw-r--r-- | lld/lib/Core/Error.cpp | 26 | ||||
-rw-r--r-- | lld/lib/Core/Resolver.cpp | 2 | ||||
-rw-r--r-- | lld/lib/Driver/GnuLdDriver.cpp | 66 | ||||
-rw-r--r-- | lld/lib/Driver/GnuLdInputGraph.cpp | 55 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp | 2 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ReaderLinkerScript.cpp | 98 | ||||
-rw-r--r-- | lld/unittests/DriverTests/GnuLdDriverTest.cpp | 20 |
13 files changed, 237 insertions, 170 deletions
diff --git a/lld/include/lld/Core/Error.h b/lld/include/lld/Core/Error.h index bda6b27aca4..7f42296645f 100644 --- a/lld/include/lld/Core/Error.h +++ b/lld/include/lld/Core/Error.h @@ -70,6 +70,18 @@ inline llvm::error_code make_error_code(InputGraphError e) { return llvm::error_code(static_cast<int>(e), InputGraphErrorCategory()); } +/// \brief Errors returned by Reader. +const llvm::error_category &ReaderErrorCategory(); + +enum class ReaderError { + success = 0, + unknown_file_format = 1 +}; + +inline llvm::error_code make_error_code(ReaderError e) { + return llvm::error_code(static_cast<int>(e), ReaderErrorCategory()); +} + } // end namespace lld namespace llvm { @@ -79,6 +91,7 @@ template <> struct is_error_code_enum<lld::YamlReaderError> : true_type {}; template <> struct is_error_code_enum<lld::LinkerScriptReaderError> : true_type {}; template <> struct is_error_code_enum<lld::InputGraphError> : true_type {}; +template <> struct is_error_code_enum<lld::ReaderError> : true_type {}; } // end namespace llvm #endif diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h index 26345c76aed..3a48c4320eb 100644 --- a/lld/include/lld/Core/File.h +++ b/lld/include/lld/Core/File.h @@ -44,10 +44,9 @@ public: /// \brief Kinds of files that are supported. enum Kind { - kindObject, ///< object file (.o) - kindSharedLibrary, ///< shared library (.so) - kindArchiveLibrary, ///< archive (.a) - kindLinkerScript, ///< linker script + kindObject, ///< object file (.o) + kindSharedLibrary, ///< shared library (.so) + kindArchiveLibrary ///< archive (.a) }; /// \brief Returns file kind. Need for dyn_cast<> on File objects. diff --git a/lld/include/lld/Driver/GnuLdInputGraph.h b/lld/include/lld/Driver/GnuLdInputGraph.h index 798828f848e..ea99d167aac 100644 --- a/lld/include/lld/Driver/GnuLdInputGraph.h +++ b/lld/include/lld/Driver/GnuLdInputGraph.h @@ -21,6 +21,7 @@ #include "lld/Core/Resolver.h" #include "lld/ReaderWriter/ELFLinkingContext.h" #include "lld/ReaderWriter/FileArchive.h" +#include "lld/ReaderWriter/LinkerScript.h" namespace lld { @@ -137,6 +138,77 @@ private: const ELFLinkingContext &_elfLinkingContext; }; +/// \brief Parse GNU Linker scripts. +class GNULdScript : public FileNode { +public: + GNULdScript(ELFLinkingContext &ctx, StringRef userPath, int64_t ordinal) + : FileNode(userPath, ordinal), _elfLinkingContext(ctx), + _linkerScript(nullptr) + {} + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::File; + } + + /// \brief Is this node part of resolution ? + virtual bool isHidden() const { return true; } + + /// \brief Validate the options + virtual bool validate() { + (void)_elfLinkingContext; + return true; + } + + /// \brief Dump the Linker script. + virtual bool dump(raw_ostream &) { return true; } + + /// \brief Parse the linker script. + virtual error_code parse(const LinkingContext &, raw_ostream &); + +protected: + ELFLinkingContext &_elfLinkingContext; + std::unique_ptr<script::Parser> _parser; + std::unique_ptr<script::Lexer> _lexer; + script::LinkerScript *_linkerScript; +}; + +/// \brief Handle ELF style with GNU Linker scripts. +class ELFGNULdScript : public GNULdScript { +public: + ELFGNULdScript(ELFLinkingContext &ctx, StringRef userPath, int64_t ordinal) + : GNULdScript(ctx, userPath, ordinal) {} + + virtual error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics); + + virtual ExpandType expandType() const { + return InputElement::ExpandType::ExpandOnly; + } + + /// Unused functions for ELFGNULdScript Nodes. + virtual ErrorOr<File &> getNextFile() { + return make_error_code(InputGraphError::no_more_files); + } + + /// Return the elements that we would want to expand with. + range<InputGraph::InputElementIterT> expandElements() { + return make_range(_expandElements.begin(), _expandElements.end()); + } + + virtual void setResolveState(uint32_t) { + llvm_unreachable("cannot use this function: setResolveState"); + } + + virtual uint32_t getResolveState() const { + llvm_unreachable("cannot use this function: getResolveState"); + } + + // Do nothing here. + virtual void resetNextIndex() {} + +private: + InputGraph::InputElementVectorT _expandElements; +}; + } // namespace lld #endif diff --git a/lld/include/lld/ReaderWriter/ELFLinkingContext.h b/lld/include/lld/ReaderWriter/ELFLinkingContext.h index 96109ddb839..0747c03b459 100644 --- a/lld/include/lld/ReaderWriter/ELFLinkingContext.h +++ b/lld/include/lld/ReaderWriter/ELFLinkingContext.h @@ -117,8 +117,6 @@ public: virtual Reader &getDefaultReader() const { return *_elfReader; } - virtual Reader &getLinkerScriptReader() const { return *_linkerScriptReader; } - /// \brief Does the output have dynamic sections. virtual bool isDynamic() const; @@ -214,6 +212,14 @@ public: return true; } + /// \brief Helper function to allocate strings. + StringRef allocateString(StringRef ref) const { + char *x = _allocator.Allocate<char>(ref.size() + 1); + memcpy(x, ref.data(), ref.size()); + x[ref.size()] = '\0'; + return x; + } + private: ELFLinkingContext() LLVM_DELETED_FUNCTION; @@ -240,7 +246,6 @@ protected: StringRefVector _inputSearchPaths; std::unique_ptr<Reader> _elfReader; std::unique_ptr<Writer> _writer; - std::unique_ptr<Reader> _linkerScriptReader; StringRef _dynamicLinkerPath; StringRefVector _initFunctions; StringRefVector _finiFunctions; diff --git a/lld/include/lld/ReaderWriter/ReaderLinkerScript.h b/lld/include/lld/ReaderWriter/ReaderLinkerScript.h deleted file mode 100644 index 0a1e3def300..00000000000 --- a/lld/include/lld/ReaderWriter/ReaderLinkerScript.h +++ /dev/null @@ -1,34 +0,0 @@ -//===- lld/ReaderWriter/ReaderLinkerScript.h ------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_READER_LINKER_SCRIPT_H -#define LLD_READER_WRITER_READER_LINKER_SCRIPT_H - -#include "lld/Core/LLVM.h" -#include "lld/ReaderWriter/Reader.h" - -namespace lld { -class File; -class LinkingContext; - -/// \brief ReaderLinkerScript is a class for reading linker scripts -class ReaderLinkerScript : public Reader { -public: - explicit ReaderLinkerScript(const LinkingContext &context) - : Reader(context) {} - - /// \brief Returns a vector of Files that are contained in the archive file - /// pointed to by the Memorybuffer - error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const; -}; - -} // end namespace lld - -#endif diff --git a/lld/lib/Core/Error.cpp b/lld/lib/Core/Error.cpp index 34c785dc70e..8cea6bbedfe 100644 --- a/lld/lib/Core/Error.cpp +++ b/lld/lib/Core/Error.cpp @@ -127,3 +127,29 @@ const llvm::error_category &lld::InputGraphErrorCategory() { static _InputGraphErrorCategory i; return i; } + +class _ReaderErrorCategory : public llvm::_do_message { +public: + virtual const char *name() const { return "lld.inputGraph.parse"; } + + virtual std::string message(int ev) const { + if (ReaderError(ev) == ReaderError::success) + return "Success"; + else if (ReaderError(ev) == ReaderError::unknown_file_format) + return "File format for the input file is not recognized by this flavor"; + + llvm_unreachable("An enumerator of ReaderError does not have a " + "message defined."); + } + + virtual llvm::error_condition default_error_condition(int ev) const { + if (ReaderError(ev) == ReaderError::success) + return llvm::errc::success; + return llvm::errc::invalid_argument; + } +}; + +const llvm::error_category &lld::ReaderErrorCategory() { + static _ReaderErrorCategory i; + return i; +} diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index 566c98c7c87..f0675681527 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -293,8 +293,6 @@ bool Resolver::resolveUndefines() { file->setOrdinal(_context.getNextOrdinalAndIncrement()); handleSharedLibrary(*file); break; - case File::kindLinkerScript: - llvm_unreachable("linker script should not be returned by nextFile()"); } } } diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index c2c77778594..bb422b5f72c 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -67,6 +67,25 @@ public: GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; +// Get the Input file magic for creating appropriate InputGraph nodes. +error_code getFileMagic(ELFLinkingContext &ctx, StringRef path, + std::vector<StringRef> &searchPaths, + llvm::sys::fs::file_magic &magic) { + error_code ec = llvm::sys::fs::identify_magic(path, magic); + if (ec) + return ec; + switch (magic) { + case llvm::sys::fs::file_magic::archive: + case llvm::sys::fs::file_magic::elf_relocatable: + case llvm::sys::fs::file_magic::elf_shared_object: + case llvm::sys::fs::file_magic::unknown: + return error_code::success(); + default: + break; + } + return make_error_code(ReaderError::unknown_file_format); +} + } // namespace llvm::ErrorOr<StringRef> ELFFileNode::getPath(const LinkingContext &) const { @@ -268,9 +287,47 @@ bool GnuLdDriver::parse(int argc, const char *argv[], case OPT_INPUT: case OPT_l: { - std::unique_ptr<InputElement> inputFile(new ELFFileNode( - *ctx, inputArg->getValue(), searchPath, index++, isWholeArchive, - asNeeded, inputArg->getOption().getID() == OPT_l)); + bool isDashlPrefix = (inputArg->getOption().getID() == OPT_l); + bool isELFFileNode = true; + StringRef userPath = inputArg->getValue(); + std::string resolvedInputPath = userPath; + + // If the path was referred to by using a -l argument, lets search + // for the file in the search path. + if (isDashlPrefix) { + ErrorOr<StringRef> resolvedPath = + ctx->searchLibrary(userPath, searchPath); + if (!resolvedPath) { + diagnostics << " Unable to find library -l" << userPath << "\n"; + return false; + } + resolvedInputPath = resolvedPath->str(); + } + llvm::sys::fs::file_magic magic = llvm::sys::fs::file_magic::unknown; + error_code ec = getFileMagic(*ctx, resolvedInputPath, searchPath, magic); + if (ec) { + diagnostics << "lld: unknown input file format for file " << userPath + << "\n"; + return false; + } + if ((!userPath.endswith(".objtxt")) && + (magic == llvm::sys::fs::file_magic::unknown)) + isELFFileNode = false; + + FileNode *inputNode = nullptr; + if (isELFFileNode) + inputNode = new ELFFileNode(*ctx, userPath, searchPath, index++, + isWholeArchive, asNeeded, isDashlPrefix); + else { + inputNode = new ELFGNULdScript(*ctx, resolvedInputPath, index++); + ec = inputNode->parse(*ctx, diagnostics); + if (ec) { + diagnostics << userPath << ": Error parsing linker script" + << "\n"; + return false; + } + } + std::unique_ptr<InputElement> inputFile(inputNode); if (controlNodeStack.empty()) inputGraph->addInputElement(std::move(inputFile)); else @@ -336,6 +393,9 @@ bool GnuLdDriver::parse(int argc, const char *argv[], if (!ctx->validate(diagnostics)) return false; + // Normalize the InputGraph. + inputGraph->normalize(); + ctx->setInputGraph(std::move(inputGraph)); context.swap(ctx); diff --git a/lld/lib/Driver/GnuLdInputGraph.cpp b/lld/lib/Driver/GnuLdInputGraph.cpp index 775be0140c7..745dd82cea5 100644 --- a/lld/lib/Driver/GnuLdInputGraph.cpp +++ b/lld/lib/Driver/GnuLdInputGraph.cpp @@ -52,10 +52,59 @@ error_code ELFFileNode::parse(const LinkingContext &ctx, } return ec; } + default: - // Process Linker script - return _elfLinkingContext.getLinkerScriptReader().parseFile(_buffer, - _files); break; } + return error_code::success(); +} + +/// \brief Parse the GnuLD Script +error_code GNULdScript::parse(const LinkingContext &ctx, + raw_ostream &diagnostics) { + ErrorOr<StringRef> filePath = getPath(ctx); + if (!filePath) + return error_code(filePath); + + if (error_code ec = getBuffer(*filePath)) + return ec; + + if (ctx.logInputFiles()) + diagnostics << *filePath << "\n"; + + _lexer.reset(new script::Lexer(std::move(_buffer))); + _parser.reset(new script::Parser(*_lexer.get())); + + _linkerScript = _parser->parse(); + + if (!_linkerScript) + return LinkerScriptReaderError::parse_error; + + return error_code::success(); +} + +/// \brief Handle GnuLD script for ELF. +error_code ELFGNULdScript::parse(const LinkingContext &ctx, + raw_ostream &diagnostics) { + int64_t index = 0; + std::vector<StringRef> searchPath; + if (error_code ec = GNULdScript::parse(ctx, diagnostics)) + return ec; + for (const auto &c : _linkerScript->_commands) { + if (auto group = dyn_cast<script::Group>(c)) { + std::unique_ptr<InputElement> controlStart( + new ELFGroup(_elfLinkingContext, index++)); + for (auto &path : group->getPaths()) { + // TODO : Propagate SearchPath, Set WholeArchive/dashlPrefix + auto inputNode = new ELFFileNode( + _elfLinkingContext, _elfLinkingContext.allocateString(path._path), + searchPath, index++, false, path._asNeeded, false); + std::unique_ptr<InputElement> inputFile(inputNode); + dyn_cast<ControlNode>(controlStart.get()) + ->processInputElement(std::move(inputFile)); + } + _expandElements.push_back(std::move(controlStart)); + } + } + return error_code::success(); } diff --git a/lld/lib/ReaderWriter/CMakeLists.txt b/lld/lib/ReaderWriter/CMakeLists.txt index fb11c2bbf20..7182af6ebb8 100644 --- a/lld/lib/ReaderWriter/CMakeLists.txt +++ b/lld/lib/ReaderWriter/CMakeLists.txt @@ -9,7 +9,6 @@ add_lld_library(lldReaderWriter CoreLinkingContext.cpp LinkerScript.cpp Reader.cpp - ReaderLinkerScript.cpp Writer.cpp ) diff --git a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp index 10f91380467..1a3965073bd 100644 --- a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -18,7 +18,6 @@ #include "lld/Passes/LayoutPass.h" #include "lld/Passes/RoundTripNativePass.h" #include "lld/Passes/RoundTripYAMLPass.h" -#include "lld/ReaderWriter/ReaderLinkerScript.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ELF.h" @@ -83,7 +82,6 @@ StringRef ELFLinkingContext::entrySymbolName() const { bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) { _elfReader = createReaderELF(*this); - _linkerScriptReader.reset(new ReaderLinkerScript(*this)); switch (outputFileType()) { case LinkingContext::OutputFileType::YAML: _writer = createWriterYAML(*this); diff --git a/lld/lib/ReaderWriter/ReaderLinkerScript.cpp b/lld/lib/ReaderWriter/ReaderLinkerScript.cpp deleted file mode 100644 index b091ff9149b..00000000000 --- a/lld/lib/ReaderWriter/ReaderLinkerScript.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===- lib/ReaderWriter/ReaderLinkerScript.cpp ----------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/ReaderWriter/ReaderLinkerScript.h" - -#include "lld/Core/Error.h" -#include "lld/Core/File.h" -#include "lld/ReaderWriter/LinkerScript.h" - -using namespace lld; -using namespace script; - -namespace { -class LinkerScriptFile : public File { -public: - static ErrorOr<std::unique_ptr<LinkerScriptFile> > - create(const LinkingContext &context, - std::unique_ptr<MemoryBuffer> mb) { - std::unique_ptr<LinkerScriptFile> file( - new LinkerScriptFile(context, std::move(mb))); - file->_script = file->_parser.parse(); - if (!file->_script) - return LinkerScriptReaderError::parse_error; - return std::move(file); - } - - static inline bool classof(const File *f) { - return f->kind() == kindLinkerScript; - } - - virtual const LinkingContext &getLinkingContext() const { return _context; } - - virtual const atom_collection<DefinedAtom> &defined() const { - return _definedAtoms; - } - - virtual const atom_collection<UndefinedAtom> &undefined() const { - return _undefinedAtoms; - } - - virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const { - return _sharedLibraryAtoms; - } - - virtual const atom_collection<AbsoluteAtom> &absolute() const { - return _absoluteAtoms; - } - - const LinkerScript *getScript() { return _script; } - -private: - LinkerScriptFile(const LinkingContext &context, - std::unique_ptr<MemoryBuffer> mb) - : File(mb->getBufferIdentifier(), kindLinkerScript), _context(context), - _lexer(std::move(mb)), _parser(_lexer), _script(nullptr) {} - - const LinkingContext &_context; - atom_collection_vector<DefinedAtom> _definedAtoms; - atom_collection_vector<UndefinedAtom> _undefinedAtoms; - atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms; - atom_collection_vector<AbsoluteAtom> _absoluteAtoms; - Lexer _lexer; - Parser _parser; - const LinkerScript *_script; -}; -} // end anon namespace - -namespace lld { -error_code ReaderLinkerScript::parseFile( - std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const { - auto lsf = LinkerScriptFile::create(_context, std::move(mb)); - if (!lsf) - return lsf; - const LinkerScript *ls = (*lsf)->getScript(); - result.push_back(std::move(*lsf)); - for (const auto &c : ls->_commands) { - if (auto group = dyn_cast<lld::script::Group>(c)) - for (const auto &path : group->getPaths()) { - OwningPtr<MemoryBuffer> opmb; - if (error_code ec = - MemoryBuffer::getFileOrSTDIN(path._path, opmb)) - return ec; - std::unique_ptr<MemoryBuffer> eachMB(opmb.take()); - if (error_code ec = - _context.getDefaultReader().parseFile(eachMB, result)) - return ec; - } - } - return error_code::success(); -} -} // end namespace lld diff --git a/lld/unittests/DriverTests/GnuLdDriverTest.cpp b/lld/unittests/DriverTests/GnuLdDriverTest.cpp index 3313fd9f1bd..bc5cecbc315 100644 --- a/lld/unittests/DriverTests/GnuLdDriverTest.cpp +++ b/lld/unittests/DriverTests/GnuLdDriverTest.cpp @@ -33,24 +33,4 @@ TEST_F(GnuLdParserTest, Empty) { EXPECT_EQ("No input files\n", errorMessage()); } -TEST_F(GnuLdParserTest, Basic) { - EXPECT_TRUE(parse("ld", "infile.o", nullptr)); - EXPECT_NE(linkingContext(), nullptr); - EXPECT_EQ("a.out", linkingContext()->outputPath()); - EXPECT_EQ(1, inputFileCount()); - EXPECT_EQ("infile.o", inputFile(0)); - EXPECT_FALSE(_context->outputFileType() == - LinkingContext::OutputFileType::YAML); -} - -TEST_F(GnuLdParserTest, ManyOptions) { - EXPECT_TRUE(parse("ld", "-entry", "_start", "-o", "outfile", - "--output-filetype=yaml", "infile.o", nullptr)); - EXPECT_NE(linkingContext(), nullptr); - EXPECT_EQ("outfile", linkingContext()->outputPath()); - EXPECT_EQ("_start", linkingContext()->entrySymbolName()); - EXPECT_TRUE(_context->outputFileType() == - LinkingContext::OutputFileType::YAML); -} - } // end anonymous namespace |