[ELF] Support for wildcard in version scripts.

Example:

VERSION_1.0 {
  global: foo*;
  local: *; }

now correctly matches all the symbols which name starts with
`foo`.

Differential Revision:  http://reviews.llvm.org/D21732

llvm-svn: 274091
This commit is contained in:
Davide Italiano 2016-06-29 02:46:51 +00:00
parent 941685e9f4
commit 8e1131dc46
5 changed files with 97 additions and 14 deletions

View File

@ -35,8 +35,6 @@ using namespace lld::elf;
ScriptConfiguration *elf::ScriptConfig;
static bool matchStr(StringRef S, StringRef T);
// This is an operator-precedence parser to parse and evaluate
// a linker script expression. For each linker script arithmetic
// expression (e.g. ". = . + 0x1000"), a new instance of ExprParser
@ -291,7 +289,7 @@ int LinkerScript<ELFT>::compareSections(StringRef A, StringRef B) {
// Returns true if S matches T. S can contain glob meta-characters.
// The asterisk ('*') matches zero or more characters, and the question
// mark ('?') matches one character.
static bool matchStr(StringRef S, StringRef T) {
bool elf::matchStr(StringRef S, StringRef T) {
for (;;) {
if (S.empty())
return T.empty();

View File

@ -19,6 +19,8 @@
namespace lld {
namespace elf {
bool matchStr(StringRef S, StringRef T);
// Parses a linker script. Calling this function updates
// Config and ScriptConfig.
void readLinkerScript(MemoryBufferRef MB);

View File

@ -17,6 +17,7 @@
#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "LinkerScript.h"
#include "Symbols.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/StringSaver.h"
@ -456,6 +457,21 @@ template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
return SymVector[It->second]->body();
}
template <class ELFT>
std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(StringRef Pattern) {
// Fast-path. Fallback to find() if Pattern doesn't contain any wildcard
// characters.
bool HasWildcards = (Pattern.find_first_of("?*") != StringRef::npos);
if (!HasWildcards)
return {find(Pattern)};
std::vector<SymbolBody *> Result;
for (auto &It : Symtab)
if (matchStr(Pattern, It.first.Val))
Result.push_back(SymVector[It.second]->body());
return Result;
}
template <class ELFT>
void SymbolTable<ELFT>::addLazyArchive(
ArchiveFile *F, const llvm::object::Archive::Symbol Sym) {
@ -556,18 +572,19 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
size_t I = 2;
for (Version &V : Config->SymbolVersions) {
for (StringRef Name : V.Globals) {
SymbolBody *B = find(Name);
if (!B || B->isUndefined()) {
if (Config->NoUndefinedVersion)
error("version script assignment of " + V.Name + " to symbol " +
Name + " failed: symbol not defined");
continue;
}
for (SymbolBody *B : findAll(Name)) {
if (!B || B->isUndefined()) {
if (Config->NoUndefinedVersion)
error("version script assignment of " + V.Name + " to symbol " +
Name + " failed: symbol not defined");
continue;
}
if (B->symbol()->VersionId != VER_NDX_GLOBAL &&
B->symbol()->VersionId != VER_NDX_LOCAL)
warning("duplicate symbol " + Name + " in version script");
B->symbol()->VersionId = I;
if (B->symbol()->VersionId != VER_NDX_GLOBAL &&
B->symbol()->VersionId != VER_NDX_LOCAL)
warning("duplicate symbol " + Name + " in version script");
B->symbol()->VersionId = I;
}
}
++I;
}

View File

@ -88,6 +88,7 @@ public:
void wrap(StringRef Name);
private:
std::vector<SymbolBody *> findAll(StringRef Pattern);
std::pair<Symbol *, bool> insert(StringRef Name);
std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
uint8_t Visibility, bool CanOmitFromDynSym,

View File

@ -0,0 +1,65 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: echo "VERSION_1.0{ \
# RUN: global: foo*; \
# RUN: local: *; };" > %t.script
# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: @
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local
# CHECK-NEXT: Type: None
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: foo1@@VERSION_1.0
# CHECK-NEXT: Value: 0x1000
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: None
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: .text
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: foo2@@VERSION_1.0
# CHECK-NEXT: Value: 0x1001
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: None
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: .text
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: foo3@@VERSION_1.0
# CHECK-NEXT: Value: 0x1007
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: None
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: .text
# CHECK-NEXT: }
# CHECK-NEXT: ]
.globl foo1
foo1:
ret
.globl foo2
foo2:
call foo1@PLT
ret
.globl foo3
foo3:
call foo2@PLT
ret
.globl _start
_start:
ret