Index: lld/trunk/include/lld/Core/Reference.h =================================================================== --- lld/trunk/include/lld/Core/Reference.h +++ lld/trunk/include/lld/Core/Reference.h @@ -36,6 +36,12 @@ /// 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 @@ /// 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 Index: lld/trunk/include/lld/Core/Resolver.h =================================================================== --- lld/trunk/include/lld/Core/Resolver.h +++ lld/trunk/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 @@ -105,6 +106,7 @@ std::set _deadStripRoots; llvm::DenseSet _liveAtoms; std::unique_ptr _result; + llvm::DenseMap> _reverseRef; }; } // namespace lld Index: lld/trunk/lib/Core/Resolver.cpp =================================================================== --- lld/trunk/lib/Core/Resolver.cpp +++ lld/trunk/lib/Core/Resolver.cpp @@ -312,9 +312,17 @@ return; // Mark all atoms it references as live - if (const DefinedAtom *defAtom = dyn_cast(atom)) + if (const DefinedAtom *defAtom = dyn_cast(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 @@ // 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(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()) Index: lld/trunk/test/core/dead-strip-reverse.objtxt =================================================================== --- lld/trunk/test/core/dead-strip-reverse.objtxt +++ lld/trunk/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