Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -13,6 +13,7 @@ #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/ELF.h" #include @@ -34,8 +35,8 @@ // For --build-id. enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; -// For --discard-{all,locals,none}. -enum class DiscardPolicy { Default, All, Locals, None }; +// For --discard-{all,locals,none} and --retain-symbols-file. +enum class DiscardPolicy { Default, All, Locals, RetainFile, None }; // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; @@ -84,6 +85,7 @@ llvm::StringRef OutputFile; llvm::StringRef SoName; llvm::StringRef Sysroot; + llvm::StringSet<> RetainSymbolsFile; std::string RPath; std::vector VersionDefinitions; std::vector AuxiliaryList; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -474,18 +474,31 @@ return SortSectionPolicy::Default; } +static std::vector getLines(MemoryBufferRef MB) { + SmallVector Arr; + MB.getBuffer().split(Arr, '\n', INT32_MAX, /*KeepEmpty*/ false); + return {Arr.begin(), Arr.end()}; +} + // Parse the --symbol-ordering-file argument. File has form: // symbolName1 // [...] // symbolNameN static void parseSymbolOrderingList(MemoryBufferRef MB) { unsigned I = 0; - SmallVector Arr; - MB.getBuffer().split(Arr, '\n'); - for (StringRef S : Arr) + for (StringRef S : getLines(MB)) Config->SymbolOrderingFile.insert({CachedHashStringRef(S.trim()), I++}); } +// Parse the --retain-symbols-file argument. File has form: +// symbolName1 +// [...] +// symbolNameN +static void parseRetainSymbolsList(MemoryBufferRef MB) { + for (StringRef S : getLines(MB)) + Config->RetainSymbolsFile.insert(S.trim()); +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -632,6 +645,14 @@ if (Optional Buffer = readFile(Arg->getValue())) parseSymbolOrderingList(*Buffer); + // If --retain-symbol-file is used, we'll retail only the symbols listed in + // the file and discard all others. + if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) { + Config->Discard = DiscardPolicy::RetainFile; + if (Optional Buffer = readFile(Arg->getValue())) + parseRetainSymbolsList(*Buffer); + } + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) Config->VersionScriptGlobals.push_back( {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -176,6 +176,9 @@ def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; +def retain_symbols_file: J<"retain-symbols-file=">, MetaVarName<"">, + HelpText<"Retain only the symbols listed in the file">; + def script: S<"script">, HelpText<"Read linker script">; def section_start: S<"section-start">, MetaVarName<"
">, Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -422,6 +422,11 @@ if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) return false; + // If --retain-symbols-file used, we do not keep include unlisted symbols. + if (Config->Discard == DiscardPolicy::RetainFile) + if (!Config->RetainSymbolsFile.count(CachedHashString(B.getName()))) + return false; + if (auto *D = dyn_cast>(&B)) { // Always include absolute symbols. if (!D->Section) Index: test/ELF/retain-symbols-file.s =================================================================== --- test/ELF/retain-symbols-file.s +++ test/ELF/retain-symbols-file.s @@ -0,0 +1,40 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: echo "bar" > %t_retain.txt +# RUN: echo "foo" >> %t_retain.txt +# RUN: ld.lld -shared --retain-symbols-file=%t_retain.txt %t -o %t2 +# RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: (0) +# CHECK: Symbol { +# CHECK-NEXT: Name: bar +# CHECK: Symbol { +# CHECK-NEXT: Name: foo +# CHECK-NOT: Symbol + +.text +.globl _start +_start: +call zed@PLT +call und@PLT + +.globl foo +.type foo,@function +foo: +retq + +.globl bar +.type bar,@function +bar: +retq + +.globl zed +.type zed,@function +zed: +retq + +.type loc,@function +loc: +retq