From: Simon Atanasyan Date: Tue, 15 Jul 2014 17:17:30 +0000 (+0000) Subject: [ELF] Implement parsing `-l` prefixed items in the `GROUP` linker script command. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=64c0ac2b35df65e38c966089f9a7ab9075bf7f58;p=platform%2Fupstream%2Fllvm.git [ELF] Implement parsing `-l` prefixed items in the `GROUP` linker script command. There are two forms of `-l` prefixed expression: * -l * -l: In the first case a linker should construct a full library name `lib + libname + .[so|a]` and search this library as usual. In the second case a linker should use the `` as is and search this file through library search directories. The patch reviewed by Shankar Easwaran. llvm-svn: 213077 --- diff --git a/lld/include/lld/ReaderWriter/LinkerScript.h b/lld/include/lld/ReaderWriter/LinkerScript.h index 7d52f59..ede0e35 100644 --- a/lld/include/lld/ReaderWriter/LinkerScript.h +++ b/lld/include/lld/ReaderWriter/LinkerScript.h @@ -34,6 +34,7 @@ public: unknown, eof, identifier, + libname, comma, l_paren, r_paren, @@ -145,10 +146,11 @@ private: 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 @@ public: first = false; if (path._asNeeded) os << "AS_NEEDED("; + if (path._isDashlPrefix) + os << "-l"; os << path._path; if (path._asNeeded) os << ")"; diff --git a/lld/lib/Driver/GnuLdInputGraph.cpp b/lld/lib/Driver/GnuLdInputGraph.cpp index f634c2e..ac85565 100644 --- a/lld/lib/Driver/GnuLdInputGraph.cpp +++ b/lld/lib/Driver/GnuLdInputGraph.cpp @@ -96,6 +96,7 @@ std::error_code ELFGNULdScript::parse(const LinkingContext &ctx, 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); diff --git a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp index 23036bc..fe33d40 100644 --- a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -163,18 +163,23 @@ static void buildSearchPath(SmallString<128> &path, StringRef dir, } 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())); } diff --git a/lld/lib/ReaderWriter/LinkerScript.cpp b/lld/lib/ReaderWriter/LinkerScript.cpp index 796fa24..8ba5f47 100644 --- a/lld/lib/ReaderWriter/LinkerScript.cpp +++ b/lld/lib/ReaderWriter/LinkerScript.cpp @@ -24,6 +24,7 @@ void Token::dump(raw_ostream &os) const { break; CASE(eof) CASE(identifier) + CASE(libname) CASE(kw_as_needed) CASE(kw_entry) CASE(kw_group) @@ -118,6 +119,24 @@ void Lexer::lex(Token &tok) { _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 @@ Group *Parser::parseGroup() { 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 @@ bool Parser::parseAsNeeded(std::vector &paths) { 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 )")) diff --git a/lld/test/LinkerScript/libname-err-1.test b/lld/test/LinkerScript/libname-err-1.test new file mode 100644 index 0000000..a31b35e --- /dev/null +++ b/lld/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 ) +*/ diff --git a/lld/test/LinkerScript/libname-err-2.test b/lld/test/LinkerScript/libname-err-2.test new file mode 100644 index 0000000..1e30094 --- /dev/null +++ b/lld/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 ) +*/ diff --git a/lld/test/LinkerScript/linker-script.test b/lld/test/LinkerScript/linker-script.test index a050c56..4c66435 100644 --- a/lld/test/LinkerScript/linker-script.test +++ b/lld/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: kw_as_needed: AS_NEEDED 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: identifier: init 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) */ diff --git a/lld/test/elf/Inputs/group-cmd-search-3.ls b/lld/test/elf/Inputs/group-cmd-search-3.ls new file mode 100644 index 0000000..83ce0ca --- /dev/null +++ b/lld/test/elf/Inputs/group-cmd-search-3.ls @@ -0,0 +1 @@ +GROUP ( -l:shared.so-x86-64 -lfnarchive ) diff --git a/lld/test/elf/group-cmd-search.test b/lld/test/elf/group-cmd-search.test index 01af279..2f5c0f4 100644 --- a/lld/test/elf/group-cmd-search.test +++ b/lld/test/elf/group-cmd-search.test @@ -101,6 +101,19 @@ RUN: %p/Inputs/group-cmd-search-2.ls -o %t6 */ /* + 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.