Index: include/lld/ReaderWriter/LinkerScript.h =================================================================== --- include/lld/ReaderWriter/LinkerScript.h +++ include/lld/ReaderWriter/LinkerScript.h @@ -34,6 +34,7 @@ unknown, eof, identifier, + libname, comma, l_paren, r_paren, @@ -145,10 +146,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 +171,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 archiveName = + 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, archiveName); 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(libname) CASE(kw_as_needed) CASE(kw_entry) CASE(kw_group) @@ -118,6 +119,24 @@ _buffer = _buffer.drop_front(quotedStringEnd + 1); return; } + // -l + if (_buffer.startswith("-l")) { + _buffer = _buffer.drop_front(2); + StringRef::size_type start = 0; + if (_buffer[start] == ':') + ++start; + if (!canStartName(_buffer[start])) + // Create 'unknown' token. + break; + auto libNameEnd = + std::find_if(_buffer.begin() + start + 1, _buffer.end(), + [=](char c) { return !canContinueName(c); }); + StringRef::size_type libNameLen = + std::distance(_buffer.begin(), libNameEnd); + tok = Token(_buffer.substr(0, libNameLen), Token::libname); + _buffer = _buffer.drop_front(libNameLen); + return; + } /// keyword or identifer. if (!canStartName(_buffer[0])) break; @@ -295,12 +314,17 @@ std::vector paths; - while (_tok._kind == Token::identifier || _tok._kind == Token::kw_as_needed) { + while (_tok._kind == Token::identifier || _tok._kind == Token::libname || + _tok._kind == Token::kw_as_needed) { switch (_tok._kind) { case Token::identifier: paths.push_back(Path(_tok._range)); consumeToken(); break; + case Token::libname: + paths.push_back(Path(_tok._range, false, true)); + consumeToken(); + break; case Token::kw_as_needed: if (!parseAsNeeded(paths)) return nullptr; @@ -325,9 +349,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::libname) { + switch (_tok._kind) { + case Token::identifier: + paths.push_back(Path(_tok._range, true, false)); + consumeToken(); + break; + case Token::libname: + paths.push_back(Path(_tok._range, true, true)); + consumeToken(); + break; + default: + llvm_unreachable("Invalid token."); + } } if (!expectAndConsume(Token::r_paren, "expected )")) Index: test/LinkerScript/libname-err-1.test =================================================================== --- /dev/null +++ test/LinkerScript/libname-err-1.test @@ -0,0 +1,11 @@ +/* RUN: linker-script-test %s 2>&1 | FileCheck %s +*/ + +OUTPUT_ARCH(i386:x86_64) +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +GROUP( -l### ) +ENTRY(init) + +/* +CHECK: test/LinkerScript/libname-err-1.test:6:10: error: expected ) +*/ Index: test/LinkerScript/libname-err-2.test =================================================================== --- /dev/null +++ test/LinkerScript/libname-err-2.test @@ -0,0 +1,11 @@ +/* RUN: linker-script-test %s 2>&1 | FileCheck %s +*/ + +OUTPUT_ARCH(i386:x86_64) +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +GROUP( -l ) +ENTRY(init) + +/* +CHECK: test/LinkerScript/libname-err-2.test:6:10: error: 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: libname: m +CHECK: libname: :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.