summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/include/lld/Core/Reference.h13
-rw-r--r--lld/include/lld/Core/Resolver.h2
-rw-r--r--lld/lib/Core/Resolver.cpp19
-rw-r--r--lld/test/core/dead-strip-reverse.objtxt25
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
OpenPOWER on IntegriCloud