Index: include/lld/ReaderWriter/LinkerScript.h =================================================================== --- include/lld/ReaderWriter/LinkerScript.h +++ include/lld/ReaderWriter/LinkerScript.h @@ -34,6 +34,7 @@ unknown, eof, identifier, + libnamespace, comma, l_paren, r_paren, @@ -69,6 +70,11 @@ bool canContinueName(char c) const; void skipWhitespace(); + /// Calculate a length of the 'lib name' argument in the + /// following expression -l. Returns 'npos' to + /// indicate an error. + StringRef::size_type sizeOfLibName(); + Token _current; /// \brief The current buffer state. StringRef _buffer; @@ -145,10 +151,11 @@ struct Path { StringRef _path; bool _asNeeded; + bool _isDashlPrefix; - Path() : _asNeeded(false) {} - explicit Path(StringRef path, bool asNeeded = false) - : _path(path), _asNeeded(asNeeded) {} + Path() : _asNeeded(false), _isDashlPrefix(false) {} + explicit Path(StringRef path, bool asNeeded = false, bool isLib = false) + : _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {} }; class Group : public Command { @@ -169,6 +176,8 @@ first = false; if (path._asNeeded) os << "AS_NEEDED("; + if (path._isDashlPrefix) + os << "-l"; os << path._path; if (path._asNeeded) os << ")"; Index: lib/Driver/GnuLdInputGraph.cpp =================================================================== --- lib/Driver/GnuLdInputGraph.cpp +++ lib/Driver/GnuLdInputGraph.cpp @@ -96,6 +96,7 @@ 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); Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -163,18 +163,23 @@ } ErrorOr ELFLinkingContext::searchLibrary(StringRef libName) const { + bool hasColonPrefix = libName[0] == ':'; + Twine soName = + hasColonPrefix ? libName.drop_front() : Twine("lib", libName) + ".so"; + Twine aName = + hasColonPrefix ? libName.drop_front() : Twine("lib", libName) + ".a"; SmallString<128> path; for (StringRef dir : _inputSearchPaths) { // Search for dynamic library if (!_isStaticExecutable) { buildSearchPath(path, dir, _sysrootPath); - llvm::sys::path::append(path, Twine("lib") + libName + ".so"); + llvm::sys::path::append(path, soName); if (llvm::sys::fs::exists(path.str())) return StringRef(*new (_allocator) std::string(path.str())); } // Search for static libraries too buildSearchPath(path, dir, _sysrootPath); - llvm::sys::path::append(path, Twine("lib") + libName + ".a"); + llvm::sys::path::append(path, aName); if (llvm::sys::fs::exists(path.str())) return StringRef(*new (_allocator) std::string(path.str())); } Index: lib/ReaderWriter/LinkerScript.cpp =================================================================== --- lib/ReaderWriter/LinkerScript.cpp +++ lib/ReaderWriter/LinkerScript.cpp @@ -24,6 +24,7 @@ break; CASE(eof) CASE(identifier) + CASE(libnamespace) CASE(kw_as_needed) CASE(kw_entry) CASE(kw_group) @@ -118,6 +119,17 @@ _buffer = _buffer.drop_front(quotedStringEnd + 1); return; } + // -l + if (_buffer.startswith("-l")) { + _buffer = _buffer.drop_front(2); + StringRef::size_type end = sizeOfLibName(); + if (end == StringRef::npos || end == 0) + break; + StringRef word = _buffer.substr(0, end); + tok = Token(word, Token::libnamespace); + _buffer = _buffer.drop_front(end); + return; + } /// keyword or identifer. if (!canStartName(_buffer[0])) break; @@ -183,6 +195,22 @@ } } +StringRef::size_type Lexer::sizeOfLibName() { + StringRef::size_type start = 0; + if (_buffer[start] == ':') + ++start; + + if (!canStartName(_buffer[start++])) + return StringRef::npos; + + auto endIter = std::find_if(_buffer.begin() + start, _buffer.end(), + [=](char c) { return !canContinueName(c); }); + if (endIter == _buffer.end()) + return StringRef::npos; + + return std::distance(_buffer.begin(), endIter); +} + LinkerScript *Parser::parse() { // Get the first token. _lex.lex(_tok); @@ -295,12 +323,17 @@ std::vector paths; - while (_tok._kind == Token::identifier || _tok._kind == Token::kw_as_needed) { + while (_tok._kind == Token::identifier || _tok._kind == Token::libnamespace || + _tok._kind == Token::kw_as_needed) { switch (_tok._kind) { case Token::identifier: paths.push_back(Path(_tok._range)); consumeToken(); break; + case Token::libnamespace: + paths.push_back(Path(_tok._range, false, true)); + consumeToken(); + break; case Token::kw_as_needed: if (!parseAsNeeded(paths)) return nullptr; @@ -325,9 +358,19 @@ if (!expectAndConsume(Token::l_paren, "expected (")) return false; - while (_tok._kind == Token::identifier) { - paths.push_back(Path(_tok._range, true)); - consumeToken(); + while (_tok._kind == Token::identifier || _tok._kind == Token::libnamespace) { + switch (_tok._kind) { + case Token::identifier: + paths.push_back(Path(_tok._range, true, false)); + consumeToken(); + break; + case Token::libnamespace: + paths.push_back(Path(_tok._range, true, true)); + consumeToken(); + break; + default: + llvm_unreachable("Invalid token."); + } } if (!expectAndConsume(Token::r_paren, "expected )")) Index: test/LinkerScript/linker-script.test =================================================================== --- test/LinkerScript/linker-script.test +++ test/LinkerScript/linker-script.test @@ -3,7 +3,7 @@ OUTPUT_ARCH(i386:x86_64) OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) ) +GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) -lm -l:libgcc.a ) ENTRY(init) /* @@ -27,6 +27,8 @@ CHECK: l_paren: ( CHECK: identifier: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 CHECK: r_paren: ) +CHECK: libnamespace: m +CHECK: libnamespace: :libgcc.a CHECK: r_paren: ) CHECK: kw_entry: ENTRY CHECK: l_paren: ( @@ -34,6 +36,6 @@ CHECK: r_paren: ) CHECK: eof: CHECK: OUTPUT_FORMAT(elf64-x86-64,elf64-x86-64,elf64-x86-64) -CHECK: GROUP(/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED(/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)) +CHECK: GROUP(/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED(/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2) -lm -l:libgcc.a) CHECK: ENTRY(init) */ Index: test/elf/Inputs/group-cmd-search-3.ls =================================================================== --- /dev/null +++ test/elf/Inputs/group-cmd-search-3.ls @@ -0,0 +1 @@ +GROUP ( -l:shared.so-x86-64 -lfnarchive ) Index: test/elf/group-cmd-search.test =================================================================== --- test/elf/group-cmd-search.test +++ test/elf/group-cmd-search.test @@ -101,6 +101,19 @@ */ /* + This link should finish successfully. The group-cmd-search-3.ls + script contains GROUP command with two elements. The first one + has a -l: form and should be found by iterating through + lib dirs and searching the 'path' name exactly. The second element + has a -l form and should be found by constructing a full + library name lib.a and iterating through lib dirs. + +RUN: lld -flavor gnu -target x86_64 -shared \ +RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \ +RUN: %p/Inputs/group-cmd-search-3.ls -o %t8 +*/ + +/* This link should fail with unknown input file format error. The linker script from this file contains GROUP with an absolute path which can be found under provided sysroot directory.