diff options
-rw-r--r-- | lld/include/lld/Core/Reference.h | 13 | ||||
-rw-r--r-- | lld/include/lld/Core/Resolver.h | 2 | ||||
-rw-r--r-- | lld/lib/Core/Resolver.cpp | 19 | ||||
-rw-r--r-- | lld/test/core/dead-strip-reverse.objtxt | 25 |
4 files changed, 54 insertions, 5 deletions
diff --git a/lld/include/lld/Core/Reference.h b/lld/include/lld/Core/Reference.h index c5252495915..528319711a2 100644 --- a/lld/include/lld/Core/Reference.h +++ b/lld/include/lld/Core/Reference.h @@ -36,6 +36,12 @@ class Atom; /// means R_X86_64_32 for x86_64, and R_386_GOTPC for i386. For PE/COFF /// relocation 10 means IMAGE_REL_AMD64_SECTION. /// +/// References and atoms form a directed graph. The dead-stripping pass +/// traverses them starting from dead-strip root atoms to garbage collect +/// unreachable ones. +/// +/// References of any kind are considered as directed edges. In addition to +/// that, references of some kind is considered as bidirected edges. class Reference { public: /// Which universe defines the kindValue(). @@ -77,10 +83,11 @@ public: /// KindValues used with KindNamespace::all and KindArch::all. enum { kindInGroup = 1, + // kindLayoutAfter is treated as a bidirected edge by the dead-stripping + // pass. kindLayoutAfter = 2, - // kindLayoutBefore is currently used only by dead-stripping pass in - // the Resolver. Will be removed soon. To enforce layout, use - // kindLayoutAfter instead. + // kindLayoutBefore is currently used only by PECOFF port, and will + // be removed soon. To enforce layout, use kindLayoutAfter instead. kindLayoutBefore = 3, kindGroupChild = 4, kindGroupParent = 5 diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h index 0bb1223f15e..3d8fe9c5ea3 100644 --- a/lld/include/lld/Core/Resolver.h +++ b/lld/include/lld/Core/Resolver.h @@ -14,6 +14,7 @@ #include "lld/Core/SharedLibraryFile.h" #include "lld/Core/SymbolTable.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include <set> @@ -105,6 +106,7 @@ private: std::set<const Atom *> _deadStripRoots; llvm::DenseSet<const Atom *> _liveAtoms; std::unique_ptr<MergedFile> _result; + llvm::DenseMap<const Atom *, llvm::DenseSet<const Atom *>> _reverseRef; }; } // namespace lld diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index bf4b4842ab8..b73d80adc70 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -312,9 +312,17 @@ void Resolver::markLive(const Atom *atom) { return; // Mark all atoms it references as live - if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) { for (const Reference *ref : *defAtom) markLive(ref->target()); + for (const Atom *target : _reverseRef[defAtom]) + markLive(target); + } +} + +static bool isBackref(const Reference *ref) { + return ref->kindNamespace() == lld::Reference::KindNamespace::all && + ref->kindValue() == lld::Reference::kindLayoutBefore; } // remove all atoms not actually used @@ -323,7 +331,14 @@ void Resolver::deadStripOptimize() { // only do this optimization with -dead_strip if (!_context.deadStrip()) return; - assert(_liveAtoms.empty()); + + // Some type of references prevent referring atoms to be dead-striped. + // Make a reverse map of such references before traversing the graph. + for (const Atom *atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) + for (const Reference *ref : *defAtom) + if (isBackref(ref)) + _reverseRef[ref->target()].insert(atom); // By default, shared libraries are built with all globals as dead strip roots if (_context.globalsAreDeadStripRoots()) diff --git a/lld/test/core/dead-strip-reverse.objtxt b/lld/test/core/dead-strip-reverse.objtxt new file mode 100644 index 00000000000..f471bebcdf4 --- /dev/null +++ b/lld/test/core/dead-strip-reverse.objtxt @@ -0,0 +1,25 @@ +# RUN: lld -core --dead-strip %s | FileCheck -check-prefix=CHECK1 %s +# RUN: lld -core %s | FileCheck -check-prefix=CHECK2 %s + +--- +defined-atoms: + - name: entry + dead-strip: never + scope: global + references: + - kind: layout-after + offset: 0 + target: def + - name: def + scope: global + - name: dead + scope: global +... + +# CHECK1: name: entry +# CHECK1: name: def +# CHECK1-NOT: name: dead + +# CHECK2: name: entry +# CHECK2: name: def +# CHECK2: name: dead |