forked from OSchip/llvm-project
[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:
parent
941685e9f4
commit
8e1131dc46
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue