summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Rimar <grimar@accesssoftek.com>2016-07-13 07:46:00 +0000
committerGeorge Rimar <grimar@accesssoftek.com>2016-07-13 07:46:00 +0000
commite05103ea11f797a6f210fe11dfaf46289cceba24 (patch)
treebf7fb241fce04f6631e5c84327aa470d5add434e
parent14ef11c110e574ecc575fff3e43a95b88452a8fb (diff)
downloadbcm5719-llvm-e05103ea11f797a6f210fe11dfaf46289cceba24.tar.gz
bcm5719-llvm-e05103ea11f797a6f210fe11dfaf46289cceba24.zip
[ELF] - Implement extern "c++" version script tag
Patch implements 'extern' version script tag. Currently only values in quotes(") are supported. Matching of externs is performed in the same pass as exact match of globals. Differential revision: http://reviews.llvm.org/D21930 llvm-svn: 275257
-rw-r--r--lld/ELF/Config.h9
-rw-r--r--lld/ELF/SymbolListFile.cpp26
-rw-r--r--lld/ELF/SymbolTable.cpp72
-rw-r--r--lld/ELF/SymbolTable.h2
-rw-r--r--lld/test/ELF/version-script-err.s5
-rw-r--r--lld/test/ELF/version-script-extern.s98
6 files changed, 179 insertions, 33 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 8a8cc04b760..7412163624f 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -35,13 +35,18 @@ enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore };
+struct SymbolVersion {
+ llvm::StringRef Name;
+ bool IsExternCpp;
+};
+
// This struct contains symbols version definition that
// can be found in version script if it is used for link.
struct Version {
Version(llvm::StringRef Name, size_t Id) : Name(Name), Id(Id) {}
llvm::StringRef Name;
size_t Id;
- std::vector<llvm::StringRef> Globals;
+ std::vector<SymbolVersion> Globals;
size_t NameOff; // Offset in string table.
};
@@ -68,7 +73,7 @@ struct Configuration {
std::vector<llvm::StringRef> DynamicList;
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> Undefined;
- std::vector<llvm::StringRef> VersionScriptGlobals;
+ std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<uint8_t> BuildIdVector;
bool AllowMultipleDefinition;
bool AsNeeded = false;
diff --git a/lld/ELF/SymbolListFile.cpp b/lld/ELF/SymbolListFile.cpp
index 68867cf8ae6..1525540e259 100644
--- a/lld/ELF/SymbolListFile.cpp
+++ b/lld/ELF/SymbolListFile.cpp
@@ -77,6 +77,7 @@ public:
void run();
private:
+ void parseExtern(std::vector<SymbolVersion> *Globals);
void parseVersion(StringRef Version);
void parseLocal();
void parseVersionSymbols(StringRef Version);
@@ -120,21 +121,38 @@ void VersionScriptParser::parseLocal() {
Config->VersionScriptGlobalByDefault = false;
}
+void VersionScriptParser::parseExtern(std::vector<SymbolVersion> *Globals) {
+ expect("extern");
+ expect("C++");
+ expect("{");
+
+ for (;;) {
+ if (peek() == "}" || Error)
+ break;
+ Globals->push_back({next(), true});
+ expect(";");
+ }
+
+ expect("}");
+ expect(";");
+}
+
void VersionScriptParser::parseVersionSymbols(StringRef Version) {
- std::vector<StringRef> *Globals;
+ std::vector<SymbolVersion> *Globals;
if (Version.empty())
Globals = &Config->VersionScriptGlobals;
else
Globals = &Config->SymbolVersions.back().Globals;
for (;;) {
+ if (peek() == "extern")
+ parseExtern(Globals);
+
StringRef Cur = peek();
- if (Cur == "extern")
- setError("extern keyword is not supported");
if (Cur == "}" || Cur == "local:" || Error)
return;
next();
- Globals->push_back(Cur);
+ Globals->push_back({Cur, false});
expect(";");
}
}
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 2474bb35a54..b3887249be0 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -567,6 +567,37 @@ static bool hasWildcard(StringRef S) {
return S.find_first_of("?*") != StringRef::npos;
}
+static void setVersionId(SymbolBody *Body, StringRef VersionName,
+ StringRef Name, uint16_t Version) {
+ if (!Body || Body->isUndefined()) {
+ if (Config->NoUndefinedVersion)
+ error("version script assignment of " + VersionName + " to symbol " +
+ Name + " failed: symbol not defined");
+ return;
+ }
+
+ Symbol *Sym = Body->symbol();
+ if (Sym->VersionId != VER_NDX_GLOBAL && Sym->VersionId != VER_NDX_LOCAL)
+ warning("duplicate symbol " + Name + " in version script");
+ Sym->VersionId = Version;
+}
+
+template <class ELFT>
+std::map<std::string, SymbolBody *> SymbolTable<ELFT>::getDemangledSyms() {
+ std::map<std::string, SymbolBody *> Result;
+ for (std::pair<SymName, unsigned> Sym : Symtab)
+ Result[demangle(Sym.first.Val)] = SymVector[Sym.second]->body();
+ return Result;
+}
+
+static bool hasExternCpp() {
+ for (Version& V : Config->SymbolVersions)
+ for (SymbolVersion Sym : V.Globals)
+ if (Sym.IsExternCpp)
+ return true;
+ return false;
+}
+
// 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,8 +605,8 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
// If version script does not contain versions declarations,
// we just should mark global symbols.
if (!Config->VersionScriptGlobals.empty()) {
- for (StringRef S : Config->VersionScriptGlobals)
- if (SymbolBody *B = find(S))
+ for (SymbolVersion &Sym : Config->VersionScriptGlobals)
+ if (SymbolBody *B = find(Sym.Name))
B->symbol()->VersionId = VER_NDX_GLOBAL;
return;
}
@@ -586,38 +617,35 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
// If we have symbols version declarations, we should
// assign version references for each symbol.
// Current rules are:
- // * If there is an exact match for the mangled name, we use it.
+ // * If there is an exact match for the mangled name or we have extern C++
+ // exact match, then 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) {
- 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;
- }
+ // Handle exact matches and build a map of demangled externs for
+ // quick search during next step.
+ std::map<std::string, SymbolBody *> Demangled;
+ if (hasExternCpp())
+ Demangled = getDemangledSyms();
- if (B->symbol()->VersionId != VER_NDX_GLOBAL &&
- B->symbol()->VersionId != VER_NDX_LOCAL)
- warning("duplicate symbol " + Name + " in version script");
- B->symbol()->VersionId = V.Id;
+ for (Version &V : Config->SymbolVersions) {
+ for (SymbolVersion Sym : V.Globals) {
+ if (hasWildcard(Sym.Name))
+ continue;
+ SymbolBody *B = Sym.IsExternCpp ? Demangled[Sym.Name] : find(Sym.Name);
+ setVersionId(B, V.Name, Sym.Name, V.Id);
}
}
+ // Handle wildcards.
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))
+ for (SymbolVersion Sym : V.Globals) {
+ if (!hasWildcard(Sym.Name))
continue;
- for (SymbolBody *B : findAll(Name))
+ for (SymbolBody *B : findAll(Sym.Name))
if (B->symbol()->VersionId == VER_NDX_GLOBAL ||
B->symbol()->VersionId == VER_NDX_LOCAL)
B->symbol()->VersionId = V.Id;
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index 39a6ec96c09..9e26ffe86ea 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -97,6 +97,8 @@ private:
std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile);
void reportDuplicate(SymbolBody *Existing, InputFile *NewFile);
+ std::map<std::string, SymbolBody *> getDemangledSyms();
+
// The order the global symbols are in is not defined. We can use an arbitrary
// order, but it has to be reproducible. That is true even when cross linking.
// The default hashing of StringRef produces different results on 32 and 64
diff --git a/lld/test/ELF/version-script-err.s b/lld/test/ELF/version-script-err.s
index 4df15d59265..15b69e98505 100644
--- a/lld/test/ELF/version-script-err.s
+++ b/lld/test/ELF/version-script-err.s
@@ -8,8 +8,3 @@
// RUN: not ld.lld --version-script %terr1.script -shared %t.o -o %t.so 2>&1 | \
// RUN: FileCheck -check-prefix=ERR1 %s
// ERR1: unclosed quote
-
-// RUN: echo "VERSION { extern "C++" {}; }; " > %terr2.script
-// RUN: not ld.lld --version-script %terr2.script -shared %t.o -o %t.so 2>&1 | \
-// RUN: FileCheck -check-prefix=ERR2 %s
-// ERR2: extern keyword is not supported
diff --git a/lld/test/ELF/version-script-extern.s b/lld/test/ELF/version-script-extern.s
new file mode 100644
index 00000000000..c5533fbdced
--- /dev/null
+++ b/lld/test/ELF/version-script-extern.s
@@ -0,0 +1,98 @@
+# REQUIRES: x86
+# XFAIL: win32
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0 { \
+# RUN: global: \
+# RUN: extern "C++" { \
+# RUN: \"foo()\"; \
+# RUN: \"zed()\"; \
+# RUN: }; \
+# RUN: }; \
+# RUN: LIBSAMPLE_2.0 { \
+# RUN: global: \
+# RUN: extern "C++" { \
+# RUN: \"bar()\"; \
+# RUN: }; \
+# RUN: }; " > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO: DynamicSymbols [
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Name: @
+# DSO-NEXT: Value: 0x0
+# DSO-NEXT: Size: 0
+# DSO-NEXT: Binding: Local
+# DSO-NEXT: Type: None
+# DSO-NEXT: Other: 0
+# DSO-NEXT: Section: Undefined
+# DSO-NEXT: }
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Name: _Z3barv@@LIBSAMPLE_2.0
+# DSO-NEXT: Value: 0x1001
+# DSO-NEXT: Size: 0
+# DSO-NEXT: Binding: Global
+# DSO-NEXT: Type: Function
+# DSO-NEXT: Other: 0
+# DSO-NEXT: Section: .text
+# DSO-NEXT: }
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Name: _Z3foov@@LIBSAMPLE_1.0
+# DSO-NEXT: Value: 0x1000
+# DSO-NEXT: Size: 0
+# DSO-NEXT: Binding: Global
+# DSO-NEXT: Type: Function
+# DSO-NEXT: Other: 0
+# DSO-NEXT: Section: .text
+# DSO-NEXT: }
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Name: _Z3zedv@@LIBSAMPLE_1.0
+# DSO-NEXT: Value: 0x1002
+# DSO-NEXT: Size: 0
+# DSO-NEXT: Binding: Global (0x1)
+# DSO-NEXT: Type: Function (0x2)
+# DSO-NEXT: Other: 0
+# DSO-NEXT: Section: .text (0x6)
+# DSO-NEXT: }
+# DSO-NEXT: ]
+# DSO-NEXT: Version symbols {
+# DSO-NEXT: Section Name: .gnu.version
+# DSO-NEXT: Address: 0x228
+# DSO-NEXT: Offset: 0x228
+# DSO-NEXT: Link: 1
+# DSO-NEXT: Symbols [
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Version: 0
+# DSO-NEXT: Name: @
+# DSO-NEXT: }
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Version: 3
+# DSO-NEXT: Name: _Z3barv@@LIBSAMPLE_2.0
+# DSO-NEXT: }
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Version: 2
+# DSO-NEXT: Name: _Z3foov@@LIBSAMPLE_1.0
+# DSO-NEXT: }
+# DSO-NEXT: Symbol {
+# DSO-NEXT: Version: 2
+# DSO-NEXT: Name: _Z3zedv@@LIBSAMPLE_1.0
+# DSO-NEXT: }
+# DSO-NEXT: ]
+# DSO-NEXT: }
+
+.text
+.globl _Z3foov
+.type _Z3foov,@function
+_Z3foov:
+retq
+
+.globl _Z3barv
+.type _Z3barv,@function
+_Z3barv:
+retq
+
+.globl _Z3zedv
+.type _Z3zedv,@function
+_Z3zedv:
+retq
OpenPOWER on IntegriCloud