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;
|
ScriptConfiguration *elf::ScriptConfig;
|
||||||
|
|
||||||
static bool matchStr(StringRef S, StringRef T);
|
|
||||||
|
|
||||||
// This is an operator-precedence parser to parse and evaluate
|
// This is an operator-precedence parser to parse and evaluate
|
||||||
// a linker script expression. For each linker script arithmetic
|
// a linker script expression. For each linker script arithmetic
|
||||||
// expression (e.g. ". = . + 0x1000"), a new instance of ExprParser
|
// 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.
|
// Returns true if S matches T. S can contain glob meta-characters.
|
||||||
// The asterisk ('*') matches zero or more characters, and the question
|
// The asterisk ('*') matches zero or more characters, and the question
|
||||||
// mark ('?') matches one character.
|
// mark ('?') matches one character.
|
||||||
static bool matchStr(StringRef S, StringRef T) {
|
bool elf::matchStr(StringRef S, StringRef T) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (S.empty())
|
if (S.empty())
|
||||||
return T.empty();
|
return T.empty();
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
namespace lld {
|
namespace lld {
|
||||||
namespace elf {
|
namespace elf {
|
||||||
|
|
||||||
|
bool matchStr(StringRef S, StringRef T);
|
||||||
|
|
||||||
// Parses a linker script. Calling this function updates
|
// Parses a linker script. Calling this function updates
|
||||||
// Config and ScriptConfig.
|
// Config and ScriptConfig.
|
||||||
void readLinkerScript(MemoryBufferRef MB);
|
void readLinkerScript(MemoryBufferRef MB);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Error.h"
|
#include "Error.h"
|
||||||
|
#include "LinkerScript.h"
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "llvm/Bitcode/ReaderWriter.h"
|
#include "llvm/Bitcode/ReaderWriter.h"
|
||||||
#include "llvm/Support/StringSaver.h"
|
#include "llvm/Support/StringSaver.h"
|
||||||
|
@ -456,6 +457,21 @@ template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
|
||||||
return SymVector[It->second]->body();
|
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>
|
template <class ELFT>
|
||||||
void SymbolTable<ELFT>::addLazyArchive(
|
void SymbolTable<ELFT>::addLazyArchive(
|
||||||
ArchiveFile *F, const llvm::object::Archive::Symbol Sym) {
|
ArchiveFile *F, const llvm::object::Archive::Symbol Sym) {
|
||||||
|
@ -556,18 +572,19 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
|
||||||
size_t I = 2;
|
size_t I = 2;
|
||||||
for (Version &V : Config->SymbolVersions) {
|
for (Version &V : Config->SymbolVersions) {
|
||||||
for (StringRef Name : V.Globals) {
|
for (StringRef Name : V.Globals) {
|
||||||
SymbolBody *B = find(Name);
|
for (SymbolBody *B : findAll(Name)) {
|
||||||
if (!B || B->isUndefined()) {
|
if (!B || B->isUndefined()) {
|
||||||
if (Config->NoUndefinedVersion)
|
if (Config->NoUndefinedVersion)
|
||||||
error("version script assignment of " + V.Name + " to symbol " +
|
error("version script assignment of " + V.Name + " to symbol " +
|
||||||
Name + " failed: symbol not defined");
|
Name + " failed: symbol not defined");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (B->symbol()->VersionId != VER_NDX_GLOBAL &&
|
if (B->symbol()->VersionId != VER_NDX_GLOBAL &&
|
||||||
B->symbol()->VersionId != VER_NDX_LOCAL)
|
B->symbol()->VersionId != VER_NDX_LOCAL)
|
||||||
warning("duplicate symbol " + Name + " in version script");
|
warning("duplicate symbol " + Name + " in version script");
|
||||||
B->symbol()->VersionId = I;
|
B->symbol()->VersionId = I;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++I;
|
++I;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ public:
|
||||||
void wrap(StringRef Name);
|
void wrap(StringRef Name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<SymbolBody *> findAll(StringRef Pattern);
|
||||||
std::pair<Symbol *, bool> insert(StringRef Name);
|
std::pair<Symbol *, bool> insert(StringRef Name);
|
||||||
std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
|
std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
|
||||||
uint8_t Visibility, bool CanOmitFromDynSym,
|
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