summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Rimar <grimar@accesssoftek.com>2016-07-07 07:45:27 +0000
committerGeorge Rimar <grimar@accesssoftek.com>2016-07-07 07:45:27 +0000
commitf73a25812f68e1dbe59a5b6589044d7a0e63e66f (patch)
tree5c18eedcb370281b6ddd7b94db3f13b276257f95
parent7afb46d3c80f521b43266d42af41a7816d949a13 (diff)
downloadbcm5719-llvm-f73a25812f68e1dbe59a5b6589044d7a0e63e66f.tar.gz
bcm5719-llvm-f73a25812f68e1dbe59a5b6589044d7a0e63e66f.zip
[ELF] - Fixed incorrect logic of version assignments when mixing wildcards with values matching.
Previously we had incorrect logic here. Imagine we would have the next script: LIBSAMPLE_1.0 { global: a_2; local: *; }; LIBSAMPLE_2.0 { global: a*; }; According to previous logic it would assign version 1 to a_2 and then would try to reassign it to version 2 because of applying wildcard a*. And show a warning about that. Generally Ian Lance Tailor wrote about next rules that should be applied: (http://www.airs.com/blog/archives/300) Here are the current rules for gold: "If there is an exact match for the mangled name, we use it. If there is more than one exact match, we give a warning, and we use the first tag in the script which matches. If a symbol has an exact match as both global and local for the same version tag, we give an error. Otherwise, we look for an extern C++ or an extern Java exact match. If we find an exact match, we use it. If there is more than one exact match, we give a warning, and we use the first tag in the script which matches. If a symbol has an exact match as both global and local for the same version tag, we give an error. Otherwise, we look through the wildcard patterns, ignoring “*” patterns. We look through the version tags in reverse order. For each version tag, we look through the global patterns and then the local patterns. We use the first match we find (i.e., the last matching version tag in the file). Otherwise, we use the “*” pattern if there is one. We give a warning if there are multiple “*” patterns." Patch makes wildcard matching to be in revered order and to follow after the regular naming matching. Differential revision: http://reviews.llvm.org/D21894 llvm-svn: 274739
-rw-r--r--lld/ELF/SymbolTable.cpp56
-rw-r--r--lld/test/ELF/version-wildcard.test49
2 files changed, 85 insertions, 20 deletions
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index ab5ff8b7870..2feb1a9b12f 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -460,15 +460,6 @@ template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
// Returns a list of defined symbols that match with a given glob pattern.
template <class ELFT>
std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(StringRef Pattern) {
- // Fast-path. Fallback to find() if Pattern doesn't contain any wildcard
- // characters.
- if (Pattern.find_first_of("?*") == StringRef::npos) {
- if (SymbolBody *B = find(Pattern))
- if (!B->isUndefined())
- return {B};
- return {};
- }
-
std::vector<SymbolBody *> Res;
for (auto &It : Symtab) {
StringRef Name = It.first.Val;
@@ -561,6 +552,10 @@ template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
B->symbol()->ExportDynamic = true;
}
+static bool hasWildcard(StringRef S) {
+ return S.find_first_of("?*") != StringRef::npos;
+}
+
// This function processes the --version-script option by marking all global
// symbols with the VersionScriptGlobal flag, which acts as a filter on the
// dynamic symbol table.
@@ -574,27 +569,48 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
return;
}
+ if (Config->SymbolVersions.empty())
+ return;
+
// If we have symbols version declarations, we should
// assign version references for each symbol.
- size_t I = 2;
- for (Version &V : Config->SymbolVersions) {
+ // Current rules are:
+ // * If there is an exact match for the mangled name, we use it.
+ // * Otherwise, we look through the wildcard patterns. We look through the
+ // version tags in reverse order. We use the first match we find (the last
+ // matching version tag in the file).
+ for (size_t I = 0, E = Config->SymbolVersions.size(); I < E; ++I) {
+ Version &V = Config->SymbolVersions[I];
for (StringRef Name : V.Globals) {
- std::vector<SymbolBody *> Syms = findAll(Name);
- if (Syms.empty()) {
+ if (hasWildcard(Name))
+ continue;
+
+ 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 : Syms) {
- 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 + 2;
+ }
+ }
+
+ for (size_t I = Config->SymbolVersions.size() - 1; I != (size_t)-1; --I) {
+ Version &V = Config->SymbolVersions[I];
+ for (StringRef Name : V.Globals) {
+ if (!hasWildcard(Name))
+ continue;
+
+ for (SymbolBody *B : findAll(Name))
+ if (B->symbol()->VersionId == VER_NDX_GLOBAL ||
+ B->symbol()->VersionId == VER_NDX_LOCAL)
+ B->symbol()->VersionId = I + 2;
}
- ++I;
}
}
diff --git a/lld/test/ELF/version-wildcard.test b/lld/test/ELF/version-wildcard.test
index 209b868ff82..80cb9cadf15 100644
--- a/lld/test/ELF/version-wildcard.test
+++ b/lld/test/ELF/version-wildcard.test
@@ -46,6 +46,55 @@
# CHECK-NEXT: }
# CHECK-NEXT: ]
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "VERSION_1.0{ \
+# RUN: global: foo2; \
+# RUN: local: *; }; \
+# RUN: VERSION_2.0{ \
+# RUN: global: foo*; \
+# RUN: }; " > %t2.script
+# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so
+# RUN: llvm-readobj -dyn-symbols %t2.so | FileCheck --check-prefix=MIX %s
+
+# MIX: DynamicSymbols [
+# MIX-NEXT: Symbol {
+# MIX-NEXT: Name: @
+# MIX-NEXT: Value: 0x0
+# MIX-NEXT: Size: 0
+# MIX-NEXT: Binding: Local
+# MIX-NEXT: Type: None
+# MIX-NEXT: Other: 0
+# MIX-NEXT: Section: Undefined
+# MIX-NEXT: }
+# MIX-NEXT: Symbol {
+# MIX-NEXT: Name: foo1@@VERSION_2.0
+# MIX-NEXT: Value: 0x1000
+# MIX-NEXT: Size: 0
+# MIX-NEXT: Binding: Global
+# MIX-NEXT: Type: None
+# MIX-NEXT: Other: 0
+# MIX-NEXT: Section: .text
+# MIX-NEXT: }
+# MIX-NEXT: Symbol {
+# MIX-NEXT: Name: foo2@@VERSION_1.0
+# MIX-NEXT: Value: 0x1001
+# MIX-NEXT: Size: 0
+# MIX-NEXT: Binding: Global
+# MIX-NEXT: Type: None
+# MIX-NEXT: Other: 0
+# MIX-NEXT: Section: .text
+# MIX-NEXT: }
+# MIX-NEXT: Symbol {
+# MIX-NEXT: Name: foo3@@VERSION_2.0
+# MIX-NEXT: Value: 0x1007
+# MIX-NEXT: Size: 0
+# MIX-NEXT: Binding: Global
+# MIX-NEXT: Type: None
+# MIX-NEXT: Other: 0
+# MIX-NEXT: Section: .text
+# MIX-NEXT: }
+# MIX-NEXT: ]
+
.globl foo1
foo1:
ret
OpenPOWER on IntegriCloud