summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/include/lld/Core/Error.h13
-rw-r--r--lld/include/lld/Core/File.h7
-rw-r--r--lld/include/lld/Driver/GnuLdInputGraph.h72
-rw-r--r--lld/include/lld/ReaderWriter/ELFLinkingContext.h11
-rw-r--r--lld/include/lld/ReaderWriter/ReaderLinkerScript.h34
-rw-r--r--lld/lib/Core/Error.cpp26
-rw-r--r--lld/lib/Core/Resolver.cpp2
-rw-r--r--lld/lib/Driver/GnuLdDriver.cpp66
-rw-r--r--lld/lib/Driver/GnuLdInputGraph.cpp55
-rw-r--r--lld/lib/ReaderWriter/CMakeLists.txt1
-rw-r--r--lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp2
-rw-r--r--lld/lib/ReaderWriter/ReaderLinkerScript.cpp98
-rw-r--r--lld/unittests/DriverTests/GnuLdDriverTest.cpp20
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
OpenPOWER on IntegriCloud