[lld] r228060 - ELF: Support INPUT linker script directive
Rui Ueyama
ruiu at google.com
Tue Feb 3 15:00:20 PST 2015
Author: ruiu
Date: Tue Feb 3 17:00:19 2015
New Revision: 228060
URL: http://llvm.org/viewvc/llvm-project?rev=228060&view=rev
Log:
ELF: Support INPUT linker script directive
INPUT directive is a variant of GROUP in the sense that that specifies
a list of input files. The only difference is whether the entire file
list is wrapped with a --start-group/--end-group or not.
http://reviews.llvm.org/D7390
Modified:
lld/trunk/include/lld/ReaderWriter/LinkerScript.h
lld/trunk/lib/Driver/GnuLdDriver.cpp
lld/trunk/lib/ReaderWriter/LinkerScript.cpp
lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp
Modified: lld/trunk/include/lld/ReaderWriter/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/LinkerScript.h?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/LinkerScript.h (original)
+++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h Tue Feb 3 17:00:19 2015
@@ -74,6 +74,7 @@ public:
kw_exclude_file,
kw_group,
kw_hidden,
+ kw_input,
kw_keep,
kw_provide,
kw_provide_hidden,
@@ -150,6 +151,7 @@ public:
enum class Kind {
Entry,
Group,
+ Input,
InputSectionsCmd,
Output,
OutputArch,
@@ -250,16 +252,18 @@ struct Path {
: _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {}
};
-class Group : public Command {
+template<Command::Kind K>
+class PathList : public Command {
public:
- template <class RangeT> explicit Group(RangeT range) : Command(Kind::Group) {
+ template <class RangeT> PathList(StringRef name, RangeT range)
+ : Command(K), _name(name) {
std::copy(std::begin(range), std::end(range), std::back_inserter(_paths));
}
- static bool classof(const Command *c) { return c->getKind() == Kind::Group; }
+ static bool classof(const Command *c) { return c->getKind() == K; }
void dump(raw_ostream &os) const override {
- os << "GROUP(";
+ os << _name << "(";
bool first = true;
for (const Path &path : getPaths()) {
if (!first)
@@ -279,9 +283,22 @@ public:
const std::vector<Path> &getPaths() const { return _paths; }
private:
+ StringRef _name;
std::vector<Path> _paths;
};
+class Group : public PathList<Command::Kind::Group> {
+public:
+ template <class RangeT> Group(RangeT range)
+ : PathList("GROUP", std::move(range)) {}
+};
+
+class Input : public PathList<Command::Kind::Input> {
+public:
+ template <class RangeT> Input(RangeT range)
+ : PathList("INPUT", std::move(range)) {}
+};
+
class Entry : public Command {
public:
explicit Entry(StringRef entryName)
@@ -886,7 +903,7 @@ private:
///
OutputArch *parseOutputArch();
- /// Parse the GROUP linker script command.
+ /// Parse the INPUT or GROUP linker script command.
/// Example:
///
/// GROUP ( /lib/x86_64-linux-gnu/libc.so.6
@@ -894,7 +911,7 @@ private:
/// AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 )
/// -lm -l:libgcc.a )
///
- Group *parseGroup();
+ template<class T> T *parsePathList();
bool parseAsNeeded(std::vector<Path> &paths);
/// Parse the ENTRY linker script command.
Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Tue Feb 3 17:00:19 2015
@@ -240,18 +240,17 @@ static bool isPathUnderSysroot(StringRef
}
static std::error_code
-evaluateLinkerScriptGroup(ELFLinkingContext &ctx, StringRef path,
- const script::Group *group, raw_ostream &diag) {
+addFilesFromLinkerScript(ELFLinkingContext &ctx, StringRef scriptPath,
+ const std::vector<script::Path> &inputPaths,
+ raw_ostream &diag) {
bool sysroot = (!ctx.getSysroot().empty()
- && isPathUnderSysroot(ctx.getSysroot(), path));
- int numfiles = 0;
- for (const script::Path &path : group->getPaths()) {
+ && isPathUnderSysroot(ctx.getSysroot(), scriptPath));
+ for (const script::Path &path : inputPaths) {
ErrorOr<StringRef> pathOrErr = path._isDashlPrefix
? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot);
if (std::error_code ec = pathOrErr.getError()) {
auto file = llvm::make_unique<ErrorFile>(path._path, ec);
ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
- ++numfiles;
continue;
}
@@ -261,10 +260,8 @@ evaluateLinkerScriptGroup(ELFLinkingCont
if (ctx.logInputFiles())
diag << file->path() << "\n";
ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
- ++numfiles;
}
}
- ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(numfiles));
return std::error_code();
}
@@ -283,9 +280,18 @@ GnuLdDriver::evalLinkerScript(ELFLinking
// Evaluate script commands.
// Currently we only recognize this subset of linker script commands.
for (const script::Command *c : script->_commands) {
- if (auto *group = dyn_cast<script::Group>(c))
- if (std::error_code ec = evaluateLinkerScriptGroup(ctx, path, group, diag))
+ if (auto *input = dyn_cast<script::Input>(c))
+ if (std::error_code ec = addFilesFromLinkerScript(
+ ctx, path, input->getPaths(), diag))
return ec;
+ if (auto *group = dyn_cast<script::Group>(c)) {
+ int origSize = ctx.getNodes().size();
+ if (std::error_code ec = addFilesFromLinkerScript(
+ ctx, path, group->getPaths(), diag))
+ return ec;
+ size_t groupSize = ctx.getNodes().size() - origSize;
+ ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(groupSize));
+ }
if (auto *searchDir = dyn_cast<script::SearchDir>(c))
ctx.addSearchPath(searchDir->getSearchPath());
if (auto *entry = dyn_cast<script::Entry>(c))
Modified: lld/trunk/lib/ReaderWriter/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/LinkerScript.cpp?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/LinkerScript.cpp (original)
+++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp Tue Feb 3 17:00:19 2015
@@ -64,6 +64,7 @@ void Token::dump(raw_ostream &os) const
CASE(kw_exclude_file)
CASE(kw_group)
CASE(kw_hidden)
+ CASE(kw_input)
CASE(kw_keep)
CASE(kw_provide)
CASE(kw_provide_hidden)
@@ -513,6 +514,7 @@ void Lexer::lex(Token &tok) {
.Case("EXCLUDE_FILE", Token::kw_exclude_file)
.Case("GROUP", Token::kw_group)
.Case("HIDDEN", Token::kw_hidden)
+ .Case("INPUT", Token::kw_input)
.Case("KEEP", Token::kw_keep)
.Case("ONLY_IF_RO", Token::kw_only_if_ro)
.Case("ONLY_IF_RW", Token::kw_only_if_rw)
@@ -924,8 +926,15 @@ std::error_code Parser::parse() {
_script._commands.push_back(outputArch);
break;
}
+ case Token::kw_input: {
+ Input *input = parsePathList<Input>();
+ if (!input)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(input);
+ break;
+ }
case Token::kw_group: {
- auto group = parseGroup();
+ Group *group = parsePathList<Group>();
if (!group)
return LinkerScriptReaderError::parse_error;
_script._commands.push_back(group);
@@ -1295,15 +1304,13 @@ OutputArch *Parser::parseOutputArch() {
return ret;
}
-// Parse GROUP(file ...)
-Group *Parser::parseGroup() {
- assert(_tok._kind == Token::kw_group && "Expected GROUP!");
+// Parse file list for INPUT or GROUP
+template<class T> T *Parser::parsePathList() {
consumeToken();
if (!expectAndConsume(Token::l_paren, "expected ("))
return nullptr;
std::vector<Path> paths;
-
while (_tok._kind == Token::identifier || _tok._kind == Token::libname ||
_tok._kind == Token::kw_as_needed) {
switch (_tok._kind) {
@@ -1323,13 +1330,9 @@ Group *Parser::parseGroup() {
llvm_unreachable("Invalid token.");
}
}
-
- auto ret = new (_alloc) Group(paths);
-
if (!expectAndConsume(Token::r_paren, "expected )"))
return nullptr;
-
- return ret;
+ return new (_alloc) T(paths);
}
// Parse AS_NEEDED(file ...)
Modified: lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp (original)
+++ lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp Tue Feb 3 17:00:19 2015
@@ -181,6 +181,14 @@ TEST_F(GnuLdParserTest, AsNeeded) {
// Linker script
+TEST_F(LinkerScriptTest, Input) {
+ parse("INPUT(/x /y)");
+ std::vector<std::unique_ptr<Node>> &nodes = _ctx->getNodes();
+ EXPECT_EQ((size_t)2, nodes.size());
+ EXPECT_EQ("/x", cast<FileNode>(nodes[0].get())->getFile()->path());
+ EXPECT_EQ("/y", cast<FileNode>(nodes[1].get())->getFile()->path());
+}
+
TEST_F(LinkerScriptTest, Group) {
parse("GROUP(/x /y)");
std::vector<std::unique_ptr<Node>> &nodes = _ctx->getNodes();
More information about the llvm-commits
mailing list