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

llvm-svn: 228060
This commit is contained in:
Rui Ueyama 2015-02-03 23:00:19 +00:00
parent 11ca834bef
commit 2a96704b33
4 changed files with 60 additions and 26 deletions

View File

@ -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.

View File

@ -240,18 +240,17 @@ static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
}
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(ELFLinkingContext &ctx, StringRef path,
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(ELFLinkingContext &ctx,
// 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))

View File

@ -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 ...)

View File

@ -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();