forked from OSchip/llvm-project
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:
parent
11ca834bef
commit
2a96704b33
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 ...)
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue