[ELF] Implement parsing `-l` prefixed items in the `GROUP` linker script command.

There are two forms of `-l` prefixed expression:

* -l<libname>
* -l:<filename>

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 `<filename>` as is and search this file through library
search directories.

The patch reviewed by Shankar Easwaran.

llvm-svn: 213077
This commit is contained in:
Simon Atanasyan 2014-07-15 17:17:30 +00:00
parent bc94c94be4
commit 64c0ac2b35
9 changed files with 93 additions and 11 deletions

View File

@ -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 << ")";

View File

@ -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);

View File

@ -163,18 +163,23 @@ static void buildSearchPath(SmallString<128> &path, StringRef dir,
}
ErrorOr<StringRef> 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()));
}

View File

@ -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<lib name>
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<Path> 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<Path> &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 )"))

View File

@ -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 )
*/

View File

@ -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 )
*/

View File

@ -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)
*/

View File

@ -0,0 +1 @@
GROUP ( -l:shared.so-x86-64 -lfnarchive )

View File

@ -100,6 +100,19 @@ RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
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:<path> form and should be found by iterating through
lib dirs and searching the 'path' name exactly. The second element
has a -l<lib name> form and should be found by constructing a full
library name lib<lib name>.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