summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/ScriptParser.cpp17
-rw-r--r--lld/ELF/SymbolTable.cpp19
-rw-r--r--lld/ELF/SymbolTable.h2
-rw-r--r--lld/ELF/Writer.cpp5
-rw-r--r--lld/test/ELF/dynamic-list-preempt.s65
6 files changed, 105 insertions, 4 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 45c9565e210..59745cd0817 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -104,6 +104,7 @@ struct Configuration {
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> SymbolOrderingFile;
std::vector<llvm::StringRef> Undefined;
+ std::vector<SymbolVersion> DynamicList;
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 6d6af301a6d..34460dbfcb8 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -180,9 +180,22 @@ static ExprValue bitOr(ExprValue A, ExprValue B) {
void ScriptParser::readDynamicList() {
expect("{");
- readAnonymousDeclaration();
- if (!atEOF())
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::tie(Locals, Globals) = readSymbols();
+ expect(";");
+
+ if (!atEOF()) {
setError("EOF expected, but got " + next());
+ return;
+ }
+ if (!Locals.empty()) {
+ setError("\"local:\" scope not supported in --dynamic-list");
+ return;
+ }
+
+ for (SymbolVersion V : Globals)
+ Config->DynamicList.push_back(V);
}
void ScriptParser::readVersionScript() {
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index ec8ae5d75bb..9962b2554e0 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -680,6 +680,24 @@ void SymbolTable::handleAnonymousVersion() {
assignWildcardVersion(Ver, VER_NDX_LOCAL);
}
+// Handles -dynamic-list.
+void SymbolTable::handleDynamicList() {
+ for (SymbolVersion &Ver : Config->DynamicList) {
+ std::vector<SymbolBody *> Syms;
+ if (Ver.HasWildcard)
+ Syms = findByVersion(Ver);
+ else
+ Syms = findAllByVersion(Ver);
+
+ for (SymbolBody *B : Syms) {
+ if (!Config->Shared)
+ B->symbol()->VersionId = VER_NDX_GLOBAL;
+ else if (B->symbol()->includeInDynsym())
+ B->IsPreemptible = true;
+ }
+ }
+}
+
// Set symbol versions to symbols. This function handles patterns
// containing no wildcard characters.
void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
@@ -729,6 +747,7 @@ void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) {
void SymbolTable::scanVersionScript() {
// Handle edge cases first.
handleAnonymousVersion();
+ handleDynamicList();
// Now we have version definitions, so we need to set version ids to symbols.
// Each version definition has a glob pattern, and all symbols that match
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index 3127cd66690..6c094073e6c 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -90,6 +90,8 @@ public:
void trace(StringRef Name);
+ void handleDynamicList();
+
private:
std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 664d468e2ef..3c509557bec 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1294,8 +1294,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
applySynthetic({In<ELFT>::EhFrame},
[](SyntheticSection *SS) { SS->finalizeContents(); });
- for (Symbol *S : Symtab->getSymbols())
- S->body()->IsPreemptible = computeIsPreemptible(*S->body());
+ if (Config->DynamicList.empty())
+ for (Symbol *S : Symtab->getSymbols())
+ S->body()->IsPreemptible = computeIsPreemptible(*S->body());
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
diff --git a/lld/test/ELF/dynamic-list-preempt.s b/lld/test/ELF/dynamic-list-preempt.s
new file mode 100644
index 00000000000..487aa9fa106
--- /dev/null
+++ b/lld/test/ELF/dynamic-list-preempt.s
@@ -0,0 +1,65 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "{ foo; zed; };" > %t.list
+# RUN: echo "{ global: foo; bar; local: *; };" > %t.vers
+# RUN: ld.lld -fatal-warnings -dynamic-list %t.list -version-script %t.vers -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOCS %s
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=DYNSYMS %s
+
+# RELOCS: Relocations [
+# RELOCS-NEXT: Section ({{.*}}) .rela.plt {
+# RELOCS-NEXT: R_X86_64_JUMP_SLOT foo 0x0
+# RELOCS-NEXT: }
+# RELOCS-NEXT: ]
+
+# DYNSYMS: DynamicSymbols [
+# DYNSYMS-NEXT: Symbol {
+# DYNSYMS-NEXT: Name: @ (0)
+# DYNSYMS-NEXT: Value: 0x0
+# DYNSYMS-NEXT: Size: 0
+# DYNSYMS-NEXT: Binding: Local
+# DYNSYMS-NEXT: Type: None
+# DYNSYMS-NEXT: Other: 0
+# DYNSYMS-NEXT: Section: Undefined
+# DYNSYMS-NEXT: }
+# DYNSYMS-NEXT: Symbol {
+# DYNSYMS-NEXT: Name: bar@
+# DYNSYMS-NEXT: Value:
+# DYNSYMS-NEXT: Size:
+# DYNSYMS-NEXT: Binding: Global
+# DYNSYMS-NEXT: Type:
+# DYNSYMS-NEXT: Other:
+# DYNSYMS-NEXT: Section:
+# DYNSYMS-NEXT: }
+# DYNSYMS-NEXT: Symbol {
+# DYNSYMS-NEXT: Name: foo@
+# DYNSYMS-NEXT: Value:
+# DYNSYMS-NEXT: Size:
+# DYNSYMS-NEXT: Binding: Global
+# DYNSYMS-NEXT: Type:
+# DYNSYMS-NEXT: Other:
+# DYNSYMS-NEXT: Section:
+# DYNSYMS-NEXT: }
+# DYNSYMS-NEXT: ]
+
+ .globl foo
+foo:
+ ret
+
+ .globl bar
+bar:
+ ret
+
+ .globl baz
+baz:
+ ret
+
+ .globl zed
+zed:
+ ret
+
+ call foo@PLT
+ call bar@PLT
+ call baz@PLT
+ call zed@PLT
OpenPOWER on IntegriCloud