diff options
author | Fangrui Song <maskray@google.com> | 2018-12-27 22:24:45 +0000 |
---|---|---|
committer | Fangrui Song <maskray@google.com> | 2018-12-27 22:24:45 +0000 |
commit | 6b3b6d6b3e8ef4f956f26fd20a099ce91582fa7a (patch) | |
tree | 2b73c6233ed9b0b4881eb762ed72bbbd88c7b8d4 /lld | |
parent | 8ed1379899d55f9390abf2b1209cd57baa53beca (diff) |
[ELF] A shared object is needed if any of its occurrences is needed
Summary:
If a DSO appears more than once with and without --as-needed, ld.bfd and gold consider --no-as-needed to takes precedence over --as-needed. lld didn't and this patch makes it do so.
This makes it a bit away from the position-dependent behavior (how
different occurrences of the same DSO interact) and protects us from
some mysterious runtime errors: if some interceptor libraries add their
own --no-as-needed dependencies (e.g. librt.so), and the user
application specifies -Wl,--as-needed -lrt , the absence of the
DT_NEEDED entry would make dlsym(RTLD_NEXT, "clock_gettime") return NULL
and would break at runtime.
Reviewers: ruiu, espindola
Reviewed By: ruiu
Subscribers: emaste, arichardson, llvm-commits
Differential Revision: https://reviews.llvm.org/D56089
Diffstat (limited to 'lld')
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 14 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.h | 2 | ||||
-rw-r--r-- | lld/test/ELF/as-needed-not-in-regular.s | 6 |
3 files changed, 20 insertions, 2 deletions
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index ba746375e3e..7615e12199f 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -94,8 +94,20 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) { if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); - if (errorCount() || !SoNames.insert(F->SoName).second) + if (errorCount()) return; + + // If a DSO appears more than once on the command line with and without + // --as-needed, --no-as-needed takes precedence over --as-needed because a + // user can add an extra DSO with --no-as-needed to force it to be added to + // the dependency list. + DenseMap<StringRef, InputFile *>::iterator It; + bool WasInserted; + std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F); + cast<SharedFile<ELFT>>(It->second)->IsNeeded |= F->IsNeeded; + if (!WasInserted) + return; + SharedFiles.push_back(F); F->parseRest(); return; diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index b5fd8d3b4ed..898185fc961 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -108,7 +108,7 @@ private: llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups; // Set of .so files to not link the same shared object file more than once. - llvm::DenseSet<StringRef> SoNames; + llvm::DenseMap<StringRef, InputFile *> SoNames; // A map from demangled symbol names to their symbol objects. // This mapping is 1:N because two symbols with different versions diff --git a/lld/test/ELF/as-needed-not-in-regular.s b/lld/test/ELF/as-needed-not-in-regular.s index a78f7742d57..cd7efa6d268 100644 --- a/lld/test/ELF/as-needed-not-in-regular.s +++ b/lld/test/ELF/as-needed-not-in-regular.s @@ -19,6 +19,12 @@ # the reference to a2 is weak, don't add a DT_NEEDED entry for a.so. # CHECK-NOT: a.so +# RUN: ld.lld %t.o %tb.so --as-needed %ta.so --no-as-needed %ta.so -o %t +# RUN: llvm-readelf -d %t | FileCheck %s -check-prefix=NEEDED + +# a.so is needed because one of its occurrences is needed. +# NEEDED: a.so + .global _start .weak a2 _start: |