Index: include/lld/ReaderWriter/LinkerScript.h =================================================================== --- include/lld/ReaderWriter/LinkerScript.h +++ include/lld/ReaderWriter/LinkerScript.h @@ -74,6 +74,7 @@ kw_exclude_file, kw_group, kw_hidden, + kw_input, kw_keep, kw_provide, kw_provide_hidden, @@ -150,6 +151,7 @@ enum class Kind { Entry, Group, + Input, InputSectionsCmd, Output, OutputArch, @@ -250,16 +252,18 @@ : _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {} }; -class Group : public Command { +template +class PathList : public Command { public: - template explicit Group(RangeT range) : Command(Kind::Group) { + template 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 @@ const std::vector &getPaths() const { return _paths; } private: + StringRef _name; std::vector _paths; }; +class Group : public PathList { +public: + template Group(RangeT range) + : PathList("GROUP", std::move(range)) {} +}; + +class Input : public PathList { +public: + template Input(RangeT range) + : PathList("INPUT", std::move(range)) {} +}; + class Entry : public Command { public: explicit Entry(StringRef entryName) @@ -886,7 +903,7 @@ /// 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 @@ /// AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) /// -lm -l:libgcc.a ) /// - Group *parseGroup(); + template T *parsePathList(); bool parseAsNeeded(std::vector &paths); /// Parse the ENTRY linker script command. Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -240,18 +240,17 @@ } static std::error_code -evaluateLinkerScriptGroup(ELFLinkingContext &ctx, StringRef path, - const script::Group *group, raw_ostream &diag) { +addFilesFromLinkerScript(ELFLinkingContext &ctx, StringRef scriptPath, + const std::vector &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 pathOrErr = path._isDashlPrefix ? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot); if (std::error_code ec = pathOrErr.getError()) { auto file = llvm::make_unique(path._path, ec); ctx.getNodes().push_back(llvm::make_unique(std::move(file))); - ++numfiles; continue; } @@ -261,10 +260,8 @@ if (ctx.logInputFiles()) diag << file->path() << "\n"; ctx.getNodes().push_back(llvm::make_unique(std::move(file))); - ++numfiles; } } - ctx.getNodes().push_back(llvm::make_unique(numfiles)); return std::error_code(); } @@ -283,9 +280,18 @@ // 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(c)) - if (std::error_code ec = evaluateLinkerScriptGroup(ctx, path, group, diag)) + if (auto *input = dyn_cast(c)) + if (std::error_code ec = addFilesFromLinkerScript( + ctx, path, input->getPaths(), diag)) + return ec; + if (auto *group = dyn_cast(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(groupSize)); + } if (auto *searchDir = dyn_cast(c)) ctx.addSearchPath(searchDir->getSearchPath()); if (auto *entry = dyn_cast(c)) Index: lib/ReaderWriter/LinkerScript.cpp =================================================================== --- lib/ReaderWriter/LinkerScript.cpp +++ lib/ReaderWriter/LinkerScript.cpp @@ -64,6 +64,7 @@ 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 @@ .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 @@ _script._commands.push_back(outputArch); break; } + case Token::kw_input: { + Input *input = parsePathList(); + if (!input) + return LinkerScriptReaderError::parse_error; + _script._commands.push_back(input); + break; + } case Token::kw_group: { - auto group = parseGroup(); + Group *group = parsePathList(); if (!group) return LinkerScriptReaderError::parse_error; _script._commands.push_back(group); @@ -1295,15 +1304,13 @@ return ret; } -// Parse GROUP(file ...) -Group *Parser::parseGroup() { - assert(_tok._kind == Token::kw_group && "Expected GROUP!"); +// Parse file list for INPUT or GROUP +template T *Parser::parsePathList() { consumeToken(); if (!expectAndConsume(Token::l_paren, "expected (")) return nullptr; std::vector paths; - while (_tok._kind == Token::identifier || _tok._kind == Token::libname || _tok._kind == Token::kw_as_needed) { switch (_tok._kind) { @@ -1323,13 +1330,9 @@ 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 ...) Index: unittests/DriverTests/GnuLdDriverTest.cpp =================================================================== --- unittests/DriverTests/GnuLdDriverTest.cpp +++ unittests/DriverTests/GnuLdDriverTest.cpp @@ -181,6 +181,14 @@ // Linker script +TEST_F(LinkerScriptTest, Input) { + parse("INPUT(/x /y)"); + std::vector> &nodes = _ctx->getNodes(); + EXPECT_EQ((size_t)2, nodes.size()); + EXPECT_EQ("/x", cast(nodes[0].get())->getFile()->path()); + EXPECT_EQ("/y", cast(nodes[1].get())->getFile()->path()); +} + TEST_F(LinkerScriptTest, Group) { parse("GROUP(/x /y)"); std::vector> &nodes = _ctx->getNodes();