Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -104,6 +104,7 @@ std::vector SearchPaths; std::vector SymbolOrderingFile; std::vector Undefined; + std::vector DynamicList; std::vector VersionScriptGlobals; std::vector VersionScriptLocals; std::vector BuildIdVector; Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -175,9 +175,16 @@ void ScriptParser::readDynamicList() { expect("{"); - readAnonymousDeclaration(); + std::vector Locals; + std::vector Globals; + std::tie(Locals, Globals) = readSymbols(); + expect(";"); if (!atEOF()) setError("EOF expected, but got " + next()); + if (!Locals.empty()) + setError("\"local:\" scope not supported in --dynamic-list" + next()); + for (SymbolVersion V : Globals) + Config->DynamicList.push_back(V); } void ScriptParser::readVersionScript() { Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -91,6 +91,8 @@ void trace(StringRef Name); + void handleDynamicList(); + private: std::vector findByVersion(SymbolVersion Ver); std::vector findAllByVersion(SymbolVersion Ver); Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -687,6 +687,22 @@ assignWildcardVersion(Ver, VER_NDX_LOCAL); } +void SymbolTable::handleDynamicList() { + for (SymbolVersion &Ver : Config->DynamicList) { + std::vector 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, @@ -736,6 +752,7 @@ 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 Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1215,8 +1215,9 @@ applySynthetic({In::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. Index: test/ELF/dynamic-list-preempt.s =================================================================== --- /dev/null +++ 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