[lld] r275257 - [ELF] - Implement extern "c++" version script tag
George Rimar via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 13 00:46:01 PDT 2016
Author: grimar
Date: Wed Jul 13 02:46:00 2016
New Revision: 275257
URL: http://llvm.org/viewvc/llvm-project?rev=275257&view=rev
Log:
[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
Added:
lld/trunk/test/ELF/version-script-extern.s
Modified:
lld/trunk/ELF/Config.h
lld/trunk/ELF/SymbolListFile.cpp
lld/trunk/ELF/SymbolTable.cpp
lld/trunk/ELF/SymbolTable.h
lld/trunk/test/ELF/version-script-err.s
Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Wed Jul 13 02:46:00 2016
@@ -35,13 +35,18 @@ enum class BuildIdKind { None, Fnv1, Md5
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;
Modified: lld/trunk/ELF/SymbolListFile.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolListFile.cpp?rev=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolListFile.cpp (original)
+++ lld/trunk/ELF/SymbolListFile.cpp Wed Jul 13 02:46:00 2016
@@ -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(";");
}
}
Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Wed Jul 13 02:46:00 2016
@@ -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<E
// 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<E
// 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");
+ // 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();
+
+ for (Version &V : Config->SymbolVersions) {
+ for (SymbolVersion Sym : V.Globals) {
+ if (hasWildcard(Sym.Name))
continue;
- }
-
- 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;
+ 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;
Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Wed Jul 13 02:46:00 2016
@@ -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
Modified: lld/trunk/test/ELF/version-script-err.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/version-script-err.s?rev=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/test/ELF/version-script-err.s (original)
+++ lld/trunk/test/ELF/version-script-err.s Wed Jul 13 02:46:00 2016
@@ -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
Added: lld/trunk/test/ELF/version-script-extern.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/version-script-extern.s?rev=275257&view=auto
==============================================================================
--- lld/trunk/test/ELF/version-script-extern.s (added)
+++ lld/trunk/test/ELF/version-script-extern.s Wed Jul 13 02:46:00 2016
@@ -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, at function
+_Z3foov:
+retq
+
+.globl _Z3barv
+.type _Z3barv, at function
+_Z3barv:
+retq
+
+.globl _Z3zedv
+.type _Z3zedv, at function
+_Z3zedv:
+retq
More information about the llvm-commits
mailing list