diff options
-rw-r--r-- | lld/ELF/Config.h | 1 | ||||
-rw-r--r-- | lld/ELF/ScriptParser.cpp | 17 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 19 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.h | 2 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 5 | ||||
-rw-r--r-- | lld/test/ELF/dynamic-list-preempt.s | 65 |
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 |