forked from OSchip/llvm-project
[ELF] - Add support for locals list in version script.
Previously we did not support anything except "local: *", patch changes that. Actually GNU rules of proccessing wildcards are more complex than that (http://www.airs.com/blog/archives/300): There are 2 iteration for wildcards, at first iteration "*" wildcards are ignored and handled at second iteration. Since we previously decided not to implement such complex rules, I suggest solution that is implemented in this patch. So for "local: *" case nothing changes, but if we have wildcarded locals, they are processed before wildcarded globals. This should fix several FreeBSD ports, one of them is jpeg-turbo-1.5.1 and currently blocks about 5k of ports. Differential revision: https://reviews.llvm.org/D26395 llvm-svn: 286713
This commit is contained in:
parent
117c933304
commit
bb6c01e7c3
|
@ -62,6 +62,7 @@ struct VersionDefinition {
|
|||
llvm::StringRef Name;
|
||||
size_t Id;
|
||||
std::vector<SymbolVersion> Globals;
|
||||
std::vector<SymbolVersion> Locals;
|
||||
size_t NameOff; // Offset in string table.
|
||||
};
|
||||
|
||||
|
|
|
@ -968,7 +968,7 @@ private:
|
|||
void readExtern(std::vector<SymbolVersion> *Globals);
|
||||
void readVersionDeclaration(StringRef VerStr);
|
||||
void readGlobal(StringRef VerStr);
|
||||
void readLocal();
|
||||
void readLocal(StringRef VerStr);
|
||||
|
||||
ScriptConfiguration &Opt = *ScriptConfig;
|
||||
bool IsUnderSysroot;
|
||||
|
@ -1778,7 +1778,7 @@ void ScriptParser::readVersionDeclaration(StringRef VerStr) {
|
|||
if (consume("global:") || peek() != "local:")
|
||||
readGlobal(VerStr);
|
||||
if (consume("local:"))
|
||||
readLocal();
|
||||
readLocal(VerStr);
|
||||
expect("}");
|
||||
|
||||
// Each version may have a parent version. For example, "Ver2" defined as
|
||||
|
@ -1790,10 +1790,22 @@ void ScriptParser::readVersionDeclaration(StringRef VerStr) {
|
|||
expect(";");
|
||||
}
|
||||
|
||||
void ScriptParser::readLocal() {
|
||||
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
|
||||
expect("*");
|
||||
expect(";");
|
||||
void ScriptParser::readLocal(StringRef VerStr) {
|
||||
if (consume("*")) {
|
||||
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
|
||||
expect(";");
|
||||
return;
|
||||
}
|
||||
|
||||
if (VerStr.empty())
|
||||
setError("locals list for anonymous version is not supported");
|
||||
|
||||
std::vector<SymbolVersion> &Locals = Config->VersionDefinitions.back().Locals;
|
||||
while (!Error && peek() != "}") {
|
||||
StringRef Tok = next();
|
||||
Locals.push_back({unquote(Tok), false, hasWildcard(Tok)});
|
||||
expect(";");
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptParser::readExtern(std::vector<SymbolVersion> *Globals) {
|
||||
|
|
|
@ -700,28 +700,37 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
|
|||
}
|
||||
setVersionId(find(N), V.Name, N, V.Id);
|
||||
}
|
||||
for (SymbolVersion Sym : V.Locals) {
|
||||
if (Sym.HasWildcards)
|
||||
continue;
|
||||
setVersionId(find(Sym.Name), V.Name, Sym.Name, VER_NDX_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
// Next, we assign versions to fuzzy matching symbols,
|
||||
// i.e. version definitions containing glob meta-characters.
|
||||
// Note that because the last match takes precedence over previous matches,
|
||||
// we iterate over the definitions in the reverse order.
|
||||
auto assignFuzzyVersion = [&](SymbolVersion &Sym, size_t Version) {
|
||||
if (!Sym.HasWildcards)
|
||||
return;
|
||||
StringMatcher M({Sym.Name});
|
||||
std::vector<SymbolBody *> Syms =
|
||||
Sym.IsExternCpp ? findAllDemangled(Demangled, M) : findAll(M);
|
||||
// Exact matching takes precendence over fuzzy matching,
|
||||
// so we set a version to a symbol only if no version has been assigned
|
||||
// to the symbol. This behavior is compatible with GNU.
|
||||
for (SymbolBody *B : Syms)
|
||||
if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
|
||||
B->symbol()->VersionId = Version;
|
||||
};
|
||||
|
||||
for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
|
||||
VersionDefinition &V = Config->VersionDefinitions[I];
|
||||
for (SymbolVersion &Sym : V.Globals) {
|
||||
if (!Sym.HasWildcards)
|
||||
continue;
|
||||
StringMatcher M({Sym.Name});
|
||||
std::vector<SymbolBody *> Syms =
|
||||
Sym.IsExternCpp ? findAllDemangled(Demangled, M) : findAll(M);
|
||||
|
||||
// Exact matching takes precendence over fuzzy matching,
|
||||
// so we set a version to a symbol only if no version has been assigned
|
||||
// to the symbol. This behavior is compatible with GNU.
|
||||
for (SymbolBody *B : Syms)
|
||||
if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
|
||||
B->symbol()->VersionId = V.Id;
|
||||
}
|
||||
for (SymbolVersion &Sym : V.Locals)
|
||||
assignFuzzyVersion(Sym, VER_NDX_LOCAL);
|
||||
for (SymbolVersion &Sym : V.Globals)
|
||||
assignFuzzyVersion(Sym, V.Id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
|
||||
# RUN: echo "VERSION_1.0 { local: foo1; };" > %t.script
|
||||
# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
|
||||
# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=EXACT %s
|
||||
# EXACT: DynamicSymbols [
|
||||
# EXACT: _start
|
||||
# EXACT-NOT: foo1
|
||||
# EXACT: foo2
|
||||
# EXACT: foo3
|
||||
|
||||
# RUN: echo "VERSION_1.0 { local: foo*; };" > %t.script
|
||||
# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
|
||||
# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=WC %s
|
||||
# WC: DynamicSymbols [
|
||||
# WC: _start
|
||||
# WC-NOT: foo1
|
||||
# WC-NOT: foo2
|
||||
# WC-NOT: foo3
|
||||
|
||||
# RUN: echo "VERSION_1.0 { global: *; local: foo*; };" > %t.script
|
||||
# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
|
||||
# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=MIX %s
|
||||
# MIX: DynamicSymbols [
|
||||
# MIX: _start@@VERSION_1.0
|
||||
# MIX-NOT: foo1
|
||||
# MIX-NOT: foo2
|
||||
# MIX-NOT: foo3
|
||||
|
||||
# RUN: echo "VERSION_1.0 { global: *; local: extern \"C++\" { foo*; } };" > %t.script
|
||||
# RUN: not ld.lld --version-script %t.script -shared %t.o -o %t.so 2>&1 \
|
||||
# RUN: | FileCheck --check-prefix=EXTERNERR %s
|
||||
# EXTERNERR: ; expected, but got "C++"
|
||||
|
||||
.globl foo1
|
||||
foo1:
|
||||
ret
|
||||
|
||||
.globl foo2
|
||||
foo2:
|
||||
ret
|
||||
|
||||
.globl foo3
|
||||
foo3:
|
||||
ret
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
ret
|
Loading…
Reference in New Issue