#include "lld/Core/InputGraph.h"
#include "lld/Core/Resolver.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "lld/ReaderWriter/LinkerScript.h"
namespace lld {
const Attributes _attributes;
};
-/// \brief Parse GNU Linker scripts.
-class GNULdScript : public FileNode {
-public:
- GNULdScript(ELFLinkingContext &ctx, StringRef userPath)
- : FileNode(userPath), _elfLinkingContext(ctx), _linkerScript(nullptr) {}
-
- /// \brief Parse the linker script.
- std::error_code parse(const LinkingContext &, raw_ostream &) override;
-
-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)
- : GNULdScript(ctx, userPath) {}
-
- std::error_code parse(const LinkingContext &ctx,
- raw_ostream &diagnostics) override;
-
- bool getReplacements(InputGraph::InputElementVectorT &result) override {
- for (std::unique_ptr<InputElement> &elt : _expandElements)
- result.push_back(std::move(elt));
- return true;
- }
-
-private:
- InputGraph::InputElementVectorT _expandElements;
-};
-
} // namespace lld
#endif
#include "lld/Driver/Driver.h"
#include "lld/Driver/GnuLdInputGraph.h"
+#include "lld/ReaderWriter/LinkerScript.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
return magic == llvm::sys::fs::file_magic::unknown;
}
+static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
+ if (sysroot.empty())
+ return false;
+ while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path))
+ path = llvm::sys::path::parent_path(path);
+ return !path.empty();
+}
+
+static std::error_code
+evaluateLinkerScript(ELFLinkingContext &ctx, InputGraph *inputGraph,
+ StringRef path, raw_ostream &diag) {
+ // Read the script file from disk and parse.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(path);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ if (ctx.logInputFiles())
+ diag << path << "\n";
+ auto lexer = llvm::make_unique<script::Lexer>(std::move(mb.get()));
+ auto parser = llvm::make_unique<script::Parser>(*lexer);
+ script::LinkerScript *script = parser->parse();
+ if (!script)
+ return LinkerScriptReaderError::parse_error;
+
+ // Evaluate script commands.
+ // Currently we only recognize GROUP() command.
+ bool sysroot = (!ctx.getSysroot().empty()
+ && isPathUnderSysroot(ctx.getSysroot(), path));
+ for (const script::Command *c : script->_commands) {
+ auto *group = dyn_cast<script::Group>(c);
+ if (!group)
+ continue;
+ int numfiles = 0;
+ for (const script::Path &path : group->getPaths()) {
+ // TODO : Propagate Set WholeArchive/dashlPrefix
+ ELFFileNode::Attributes attr;
+ attr.setSysRooted(sysroot);
+ attr.setAsNeeded(path._asNeeded);
+ attr.setDashlPrefix(path._isDashlPrefix);
+ ++numfiles;
+ inputGraph->addInputElement(llvm::make_unique<ELFFileNode>(
+ ctx, ctx.allocateString(path._path), attr));
+ }
+ inputGraph->addInputElement(llvm::make_unique<GroupEnd>(numfiles));
+ }
+ return std::error_code();
+}
+
bool GnuLdDriver::applyEmulation(llvm::Triple &triple,
llvm::opt::InputArgList &args,
raw_ostream &diagnostics) {
}
bool isScript =
(!path.endswith(".objtxt") && isLinkerScript(realpath, diagnostics));
- FileNode *inputNode = nullptr;
if (isScript) {
- inputNode = new ELFGNULdScript(*ctx, realpath);
- if (inputNode->parse(*ctx, diagnostics)) {
- diagnostics << path << ": Error parsing linker script\n";
+ std::error_code ec = evaluateLinkerScript(
+ *ctx, inputGraph.get(), realpath, diagnostics);
+ if (ec) {
+ diagnostics << path << ": Error parsing linker script: "
+ << ec.message() << "\n";
return false;
}
- } else {
- inputNode = new ELFFileNode(*ctx, path, attributes);
+ break;
}
- std::unique_ptr<InputElement> inputFile(inputNode);
++numfiles;
- inputGraph->addInputElement(std::move(inputFile));
+ inputGraph->addInputElement(
+ llvm::make_unique<ELFFileNode>(*ctx, path, attributes));
break;
}
}
return ctx.registry().parseFile(std::move(mb.get()), _files);
}
-
-/// \brief Parse the GnuLD Script
-std::error_code GNULdScript::parse(const LinkingContext &ctx,
- raw_ostream &diagnostics) {
- ErrorOr<StringRef> filePath = getPath(ctx);
- if (std::error_code ec = filePath.getError())
- return ec;
- ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
- MemoryBuffer::getFileOrSTDIN(*filePath);
- if (std::error_code ec = mb.getError())
- return ec;
-
- if (ctx.logInputFiles())
- diagnostics << *filePath << "\n";
-
- _lexer.reset(new script::Lexer(std::move(mb.get())));
- _parser.reset(new script::Parser(*_lexer.get()));
-
- _linkerScript = _parser->parse();
-
- if (!_linkerScript)
- return LinkerScriptReaderError::parse_error;
-
- return std::error_code();
-}
-
-static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
- if (sysroot.empty())
- return false;
-
- while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path))
- path = llvm::sys::path::parent_path(path);
-
- return !path.empty();
-}
-
-/// \brief Handle GnuLD script for ELF.
-std::error_code ELFGNULdScript::parse(const LinkingContext &ctx,
- raw_ostream &diagnostics) {
- ELFFileNode::Attributes attributes;
- if (std::error_code ec = GNULdScript::parse(ctx, diagnostics))
- return ec;
- StringRef sysRoot = _elfLinkingContext.getSysroot();
- if (!sysRoot.empty() && isPathUnderSysroot(sysRoot, *getPath(ctx)))
- attributes.setSysRooted(true);
- for (const script::Command *c : _linkerScript->_commands) {
- auto *group = dyn_cast<script::Group>(c);
- if (!group)
- continue;
- size_t numfiles = 0;
- for (const script::Path &path : group->getPaths()) {
- // TODO : Propagate Set WholeArchive/dashlPrefix
- attributes.setAsNeeded(path._asNeeded);
- attributes.setDashlPrefix(path._isDashlPrefix);
- auto inputNode = new ELFFileNode(
- _elfLinkingContext, _elfLinkingContext.allocateString(path._path),
- attributes);
- std::unique_ptr<InputElement> inputFile(inputNode);
- _expandElements.push_back(std::move(inputFile));
- ++numfiles;
- }
- _expandElements.push_back(llvm::make_unique<GroupEnd>(numfiles));
- }
- return std::error_code();
-}