[ELF] Remove {ELF,}GNULinkerScript.
Instead of representing a linker script file as an "InputElement", parse and evaluate scripts in the driver as we see them. Linker scripts are not regular input files (regular file is one of object, archive, or shared library file). They are more like extended command line options. Linker script handling was needlessly complicated because of that inappropriate abstraction (besides excessive class hierarchy -- there is no such thing like ELF linker script but we had two classes there for some reason.) LinkerScript was one of a few remaining InputElement subclasses that can be expanded to multiple files. With this patch, we are one step closer to retire InputElement. http://reviews.llvm.org/D6648 llvm-svn: 225330
This commit is contained in:
parent
5310c1e954
commit
5a25fd5962
|
@ -21,7 +21,6 @@
|
|||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/Core/Resolver.h"
|
||||
#include "lld/ReaderWriter/ELFLinkingContext.h"
|
||||
#include "lld/ReaderWriter/LinkerScript.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
|
@ -81,41 +80,6 @@ private:
|
|||
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
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#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"
|
||||
|
@ -217,6 +218,54 @@ static bool isLinkerScript(StringRef path, raw_ostream &diag) {
|
|||
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) {
|
||||
|
@ -529,19 +578,19 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,68 +63,3 @@ std::error_code ELFFileNode::parse(const LinkingContext &ctx,
|
|||
}
|
||||
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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue