[lld] [LLD][ELF] Add --why-live flag to report GC liveness reason (PR #119279)
Daniel Thornburgh via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 9 14:37:15 PST 2024
https://github.com/mysterymath created https://github.com/llvm/llvm-project/pull/119279
This adds a loose port of the MachO why-live flag to ELF LLD.
This flag takes a glob matching symbols for which to report liveness information. The flag can be specified multiple times. For each symbol, a chain of objects is reported from GC root to that symbol.
A reported object is either a symbol or a section. Sections might be alive by virtue of some symbol within them being alive. Symbols might be alive either by being directly referenced by another symbol or just by virtue of being within a live section. Both symbols and sections may intrinsically be alive for various internal or flag reasons; these are the GC roots.
>From a15fdeff8fe8aebfab0b7c8135e0a575ab33ed7e Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 13 Nov 2024 15:12:55 -0800
Subject: [PATCH 01/25] Pass through parent enqueue section and offset
---
lld/ELF/MarkLive.cpp | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 08d9ecedf2cc07..72e5ef14b73bca 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -42,6 +42,11 @@ using namespace lld;
using namespace lld::elf;
namespace {
+struct LiveParent {
+ InputSectionBase *sec;
+ std::optional<uint64_t> offset;
+};
+
template <class ELFT> class MarkLive {
public:
MarkLive(Ctx &ctx, unsigned partition) : ctx(ctx), partition(partition) {}
@@ -50,7 +55,7 @@ template <class ELFT> class MarkLive {
void moveToMain();
private:
- void enqueue(InputSectionBase *sec, uint64_t offset);
+ void enqueue(InputSectionBase *sec, uint64_t offset, std::optional<LiveParent> parent);
void markSymbol(Symbol *sym);
void mark();
@@ -101,6 +106,8 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
Symbol &sym = sec.file->getRelocTargetSym(rel);
sym.used = true;
+ LiveParent parent = {&sec, rel.r_offset};
+
if (auto *d = dyn_cast<Defined>(&sym)) {
auto *relSec = dyn_cast_or_null<InputSectionBase>(d->section);
if (!relSec)
@@ -120,7 +127,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
// discarded, marking the LSDA will unnecessarily retain the text section.
if (!(fromFDE && ((relSec->flags & (SHF_EXECINSTR | SHF_LINK_ORDER)) ||
relSec->nextInSectionGroup)))
- enqueue(relSec, offset);
+ enqueue(relSec, offset, parent);
return;
}
@@ -129,7 +136,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
cast<SharedFile>(ss->file)->isNeeded = true;
for (InputSectionBase *sec : cNamedSections.lookup(sym.getName()))
- enqueue(sec, 0);
+ enqueue(sec, 0, parent);
}
// The .eh_frame section is an unfortunate special case.
@@ -187,7 +194,8 @@ static bool isReserved(InputSectionBase *sec) {
}
template <class ELFT>
-void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset) {
+void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
+ std::optional<LiveParent> parent) {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
@@ -209,7 +217,7 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset) {
template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
if (auto *d = dyn_cast_or_null<Defined>(sym))
if (auto *isec = dyn_cast_or_null<InputSectionBase>(d->section))
- enqueue(isec, d->value);
+ enqueue(isec, d->value, std::nullopt);
}
// This is the main function of the garbage collector.
@@ -256,7 +264,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
}
for (InputSectionBase *sec : ctx.inputSections) {
if (sec->flags & SHF_GNU_RETAIN) {
- enqueue(sec, 0);
+ enqueue(sec, 0, std::nullopt);
continue;
}
if (sec->flags & SHF_LINK_ORDER)
@@ -295,7 +303,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
if (isReserved(sec) || ctx.script->shouldKeep(sec)) {
- enqueue(sec, 0);
+ enqueue(sec, 0, std::nullopt);
} else if ((!ctx.arg.zStartStopGC || sec->name.starts_with("__libc_")) &&
isValidCIdentifier(sec->name)) {
// As a workaround for glibc libc.a before 2.34
@@ -323,11 +331,11 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
resolveReloc(sec, rel, false);
for (InputSectionBase *isec : sec.dependentSections)
- enqueue(isec, 0);
+ enqueue(isec, 0, LiveParent{&sec, std::nullopt});
// Mark the next group member.
if (sec.nextInSectionGroup)
- enqueue(sec.nextInSectionGroup, 0);
+ enqueue(sec.nextInSectionGroup, 0, LiveParent{&sec, std::nullopt});
}
}
@@ -353,7 +361,7 @@ template <class ELFT> void MarkLive<ELFT>::moveToMain() {
continue;
if (ctx.symtab->find(("__start_" + sec->name).str()) ||
ctx.symtab->find(("__stop_" + sec->name).str()))
- enqueue(sec, 0);
+ enqueue(sec, 0, std::nullopt);
}
mark();
>From a916b1761fcaa6e39928fb02c229075ab429092b Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 27 Nov 2024 16:07:13 -0800
Subject: [PATCH 02/25] Track parents
---
lld/ELF/MarkLive.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 72e5ef14b73bca..e49d105546b86d 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -75,6 +75,8 @@ template <class ELFT> class MarkLive {
// There are normally few input sections whose names are valid C
// identifiers, so we just store a SmallVector instead of a multimap.
DenseMap<StringRef, SmallVector<InputSectionBase *, 0>> cNamedSections;
+
+ DenseMap<InputSectionBase*, LiveParent> parents;
};
} // namespace
@@ -209,6 +211,9 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
return;
sec->partition = sec->partition ? 1 : partition;
+ if (parent)
+ parents.try_emplace(sec, *parent);
+
// Add input section to the queue.
if (InputSection *s = dyn_cast<InputSection>(sec))
queue.push_back(s);
>From 4d7981a002e8e3331858c0f96a6066f3ec920e73 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Mon, 2 Dec 2024 15:51:10 -0800
Subject: [PATCH 03/25] Recast as LiveOffset
---
lld/ELF/MarkLive.cpp | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index e49d105546b86d..cb1ab59a0f1bd0 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -42,9 +42,13 @@ using namespace lld;
using namespace lld::elf;
namespace {
-struct LiveParent {
+struct LiveOffset {
InputSectionBase *sec;
std::optional<uint64_t> offset;
+
+ LiveOffset(InputSectionBase *sec,
+ std::optional<uint64_t> offset = std::nullopt)
+ : sec(sec), offset(offset) {}
};
template <class ELFT> class MarkLive {
@@ -55,7 +59,8 @@ template <class ELFT> class MarkLive {
void moveToMain();
private:
- void enqueue(InputSectionBase *sec, uint64_t offset, std::optional<LiveParent> parent);
+ void enqueue(InputSectionBase *sec, uint64_t offset,
+ std::optional<LiveOffset> parent);
void markSymbol(Symbol *sym);
void mark();
@@ -76,7 +81,7 @@ template <class ELFT> class MarkLive {
// identifiers, so we just store a SmallVector instead of a multimap.
DenseMap<StringRef, SmallVector<InputSectionBase *, 0>> cNamedSections;
- DenseMap<InputSectionBase*, LiveParent> parents;
+ DenseMap<LiveOffset, LiveOffset> whyLive;
};
} // namespace
@@ -108,7 +113,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
Symbol &sym = sec.file->getRelocTargetSym(rel);
sym.used = true;
- LiveParent parent = {&sec, rel.r_offset};
+ LiveOffset parent = {&sec, rel.r_offset};
if (auto *d = dyn_cast<Defined>(&sym)) {
auto *relSec = dyn_cast_or_null<InputSectionBase>(d->section);
@@ -197,7 +202,7 @@ static bool isReserved(InputSectionBase *sec) {
template <class ELFT>
void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
- std::optional<LiveParent> parent) {
+ std::optional<LiveOffset> parent) {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
@@ -212,7 +217,7 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
sec->partition = sec->partition ? 1 : partition;
if (parent)
- parents.try_emplace(sec, *parent);
+ whyLive.try_emplace(LiveOffset{sec, offset}, *parent);
// Add input section to the queue.
if (InputSection *s = dyn_cast<InputSection>(sec))
@@ -336,11 +341,11 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
resolveReloc(sec, rel, false);
for (InputSectionBase *isec : sec.dependentSections)
- enqueue(isec, 0, LiveParent{&sec, std::nullopt});
+ enqueue(isec, 0, &sec);
// Mark the next group member.
if (sec.nextInSectionGroup)
- enqueue(sec.nextInSectionGroup, 0, LiveParent{&sec, std::nullopt});
+ enqueue(sec.nextInSectionGroup, 0, &sec);
}
}
>From 5ad1d0b5013253f7700dde78dd2c94648d06e06d Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Mon, 2 Dec 2024 16:00:58 -0800
Subject: [PATCH 04/25] Use a pair
---
lld/ELF/MarkLive.cpp | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index cb1ab59a0f1bd0..3686b877c26b36 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -42,14 +42,7 @@ using namespace lld;
using namespace lld::elf;
namespace {
-struct LiveOffset {
- InputSectionBase *sec;
- std::optional<uint64_t> offset;
-
- LiveOffset(InputSectionBase *sec,
- std::optional<uint64_t> offset = std::nullopt)
- : sec(sec), offset(offset) {}
-};
+typedef std::pair<InputSectionBase *, uint64_t> LiveOffset;
template <class ELFT> class MarkLive {
public:
@@ -341,11 +334,11 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
resolveReloc(sec, rel, false);
for (InputSectionBase *isec : sec.dependentSections)
- enqueue(isec, 0, &sec);
+ enqueue(isec, 0, {{&sec, 0}});
// Mark the next group member.
if (sec.nextInSectionGroup)
- enqueue(sec.nextInSectionGroup, 0, &sec);
+ enqueue(sec.nextInSectionGroup, 0, {{&sec, 0}});
}
}
>From 973dbba4f490a1e158b26ff5da8f7bc680867ced Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 3 Dec 2024 11:00:50 -0800
Subject: [PATCH 05/25] Also record against the zero offset
---
lld/ELF/MarkLive.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 3686b877c26b36..5164c3c6df5a6f 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -209,8 +209,13 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
return;
sec->partition = sec->partition ? 1 : partition;
- if (parent)
+ if (parent) {
whyLive.try_emplace(LiveOffset{sec, offset}, *parent);
+ // Offset zero is treated as a stand-in for the section itself. The parent
+ // is both a specific reason that an offset within this section is alive and
+ // a generic reason the section itself is alive.
+ whyLive.try_emplace(LiveOffset{sec, 0}, *parent);
+ }
// Add input section to the queue.
if (InputSection *s = dyn_cast<InputSection>(sec))
>From 9d3fd211464461ac061f3661d632097f0e6d341e Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 3 Dec 2024 11:10:44 -0800
Subject: [PATCH 06/25] Track live objects as either symbols or sections
---
lld/ELF/MarkLive.cpp | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 5164c3c6df5a6f..d93f9ae187d337 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -29,9 +29,11 @@
#include "Target.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
+#include "llvm/ADT/DenseMapInfoVariant.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/TimeProfiler.h"
+#include <variant>
#include <vector>
using namespace llvm;
@@ -42,7 +44,7 @@ using namespace lld;
using namespace lld::elf;
namespace {
-typedef std::pair<InputSectionBase *, uint64_t> LiveOffset;
+typedef std::variant<InputSectionBase *, Defined *> LiveObject;
template <class ELFT> class MarkLive {
public:
@@ -53,7 +55,7 @@ template <class ELFT> class MarkLive {
private:
void enqueue(InputSectionBase *sec, uint64_t offset,
- std::optional<LiveOffset> parent);
+ std::optional<LiveObject> parent);
void markSymbol(Symbol *sym);
void mark();
@@ -74,7 +76,7 @@ template <class ELFT> class MarkLive {
// identifiers, so we just store a SmallVector instead of a multimap.
DenseMap<StringRef, SmallVector<InputSectionBase *, 0>> cNamedSections;
- DenseMap<LiveOffset, LiveOffset> whyLive;
+ DenseMap<LiveObject, LiveObject> whyLive;
};
} // namespace
@@ -106,7 +108,8 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
Symbol &sym = sec.file->getRelocTargetSym(rel);
sym.used = true;
- LiveOffset parent = {&sec, rel.r_offset};
+ Defined *parentSym = sec.getEnclosingSymbol(rel.r_offset);
+ auto parent = parentSym ? LiveObject(parentSym) : LiveObject(&sec);
if (auto *d = dyn_cast<Defined>(&sym)) {
auto *relSec = dyn_cast_or_null<InputSectionBase>(d->section);
@@ -195,7 +198,7 @@ static bool isReserved(InputSectionBase *sec) {
template <class ELFT>
void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
- std::optional<LiveOffset> parent) {
+ std::optional<LiveObject> parent) {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
@@ -210,11 +213,10 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
sec->partition = sec->partition ? 1 : partition;
if (parent) {
- whyLive.try_emplace(LiveOffset{sec, offset}, *parent);
- // Offset zero is treated as a stand-in for the section itself. The parent
- // is both a specific reason that an offset within this section is alive and
- // a generic reason the section itself is alive.
- whyLive.try_emplace(LiveOffset{sec, 0}, *parent);
+ whyLive.try_emplace(sec, *parent);
+ Defined *sym = sec->getEnclosingSymbol(offset);
+ if (sym)
+ whyLive.try_emplace(sym, *parent);
}
// Add input section to the queue.
@@ -339,11 +341,11 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
resolveReloc(sec, rel, false);
for (InputSectionBase *isec : sec.dependentSections)
- enqueue(isec, 0, {{&sec, 0}});
+ enqueue(isec, 0, &sec);
// Mark the next group member.
if (sec.nextInSectionGroup)
- enqueue(sec.nextInSectionGroup, 0, {{&sec, 0}});
+ enqueue(sec.nextInSectionGroup, 0, &sec);
}
}
>From 1bb7a314e36f8ceeb0d1b0b50be7e905a0a45959 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 3 Dec 2024 11:26:04 -0800
Subject: [PATCH 07/25] Be clear about the zero offset vs section distinction
---
lld/ELF/MarkLive.cpp | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index d93f9ae187d337..3c654921a0dfdc 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -54,7 +54,7 @@ template <class ELFT> class MarkLive {
void moveToMain();
private:
- void enqueue(InputSectionBase *sec, uint64_t offset,
+ void enqueue(InputSectionBase *sec, std::optional<uint64_t> offset,
std::optional<LiveObject> parent);
void markSymbol(Symbol *sym);
void mark();
@@ -139,7 +139,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
cast<SharedFile>(ss->file)->isNeeded = true;
for (InputSectionBase *sec : cNamedSections.lookup(sym.getName()))
- enqueue(sec, 0, parent);
+ enqueue(sec, std::nullopt, parent);
}
// The .eh_frame section is an unfortunate special case.
@@ -197,13 +197,14 @@ static bool isReserved(InputSectionBase *sec) {
}
template <class ELFT>
-void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
+void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
+ std::optional<uint64_t> offset,
std::optional<LiveObject> parent) {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
if (auto *ms = dyn_cast<MergeInputSection>(sec))
- ms->getSectionPiece(offset).live = true;
+ ms->getSectionPiece(offset.value_or(0)).live = true;
// Set Sec->Partition to the meet (i.e. the "minimum") of Partition and
// Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition
@@ -214,9 +215,11 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
if (parent) {
whyLive.try_emplace(sec, *parent);
- Defined *sym = sec->getEnclosingSymbol(offset);
- if (sym)
- whyLive.try_emplace(sym, *parent);
+ if (offset) {
+ Defined *sym = sec->getEnclosingSymbol(*offset);
+ if (sym)
+ whyLive.try_emplace(sym, *parent);
+ }
}
// Add input section to the queue.
@@ -274,7 +277,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
}
for (InputSectionBase *sec : ctx.inputSections) {
if (sec->flags & SHF_GNU_RETAIN) {
- enqueue(sec, 0, std::nullopt);
+ enqueue(sec, std::nullopt, std::nullopt);
continue;
}
if (sec->flags & SHF_LINK_ORDER)
@@ -313,7 +316,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
if (isReserved(sec) || ctx.script->shouldKeep(sec)) {
- enqueue(sec, 0, std::nullopt);
+ enqueue(sec, std::nullopt, std::nullopt);
} else if ((!ctx.arg.zStartStopGC || sec->name.starts_with("__libc_")) &&
isValidCIdentifier(sec->name)) {
// As a workaround for glibc libc.a before 2.34
@@ -341,11 +344,11 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
resolveReloc(sec, rel, false);
for (InputSectionBase *isec : sec.dependentSections)
- enqueue(isec, 0, &sec);
+ enqueue(isec, std::nullopt, &sec);
// Mark the next group member.
if (sec.nextInSectionGroup)
- enqueue(sec.nextInSectionGroup, 0, &sec);
+ enqueue(sec.nextInSectionGroup, std::nullopt, &sec);
}
}
@@ -371,7 +374,7 @@ template <class ELFT> void MarkLive<ELFT>::moveToMain() {
continue;
if (ctx.symtab->find(("__start_" + sec->name).str()) ||
ctx.symtab->find(("__stop_" + sec->name).str()))
- enqueue(sec, 0, std::nullopt);
+ enqueue(sec, std::nullopt, std::nullopt);
}
mark();
>From 75a1c47a65f5f08ce40e9dc5d8d26710941c202e Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 3 Dec 2024 11:37:59 -0800
Subject: [PATCH 08/25] Track shared symbols too
---
lld/ELF/MarkLive.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 3c654921a0dfdc..6cba7a36988e4e 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -44,7 +44,7 @@ using namespace lld;
using namespace lld::elf;
namespace {
-typedef std::variant<InputSectionBase *, Defined *> LiveObject;
+typedef std::variant<InputSectionBase *, Symbol *> LiveObject;
template <class ELFT> class MarkLive {
public:
@@ -134,9 +134,12 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
return;
}
- if (auto *ss = dyn_cast<SharedSymbol>(&sym))
- if (!ss->isWeak())
+ if (auto *ss = dyn_cast<SharedSymbol>(&sym)) {
+ if (!ss->isWeak()) {
cast<SharedFile>(ss->file)->isNeeded = true;
+ whyLive.try_emplace(&sym, parent);
+ }
+ }
for (InputSectionBase *sec : cNamedSections.lookup(sym.getName()))
enqueue(sec, std::nullopt, parent);
>From 8a489a2b191990b1d67b1abd991de9f4f93b3b6f Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 3 Dec 2024 14:49:45 -0800
Subject: [PATCH 09/25] Hax
---
lld/ELF/MarkLive.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 6cba7a36988e4e..5ebe94bcf9de45 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -56,6 +56,7 @@ template <class ELFT> class MarkLive {
private:
void enqueue(InputSectionBase *sec, std::optional<uint64_t> offset,
std::optional<LiveObject> parent);
+ void printWhyLive(const Symbol *s) const;
void markSymbol(Symbol *sym);
void mark();
@@ -230,6 +231,10 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
queue.push_back(s);
}
+template <class ELFT>
+void MarkLive<ELFT>::printWhyLive(const Symbol *s) const {
+}
+
template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
if (auto *d = dyn_cast_or_null<Defined>(sym))
if (auto *isec = dyn_cast_or_null<InputSectionBase>(d->section))
@@ -353,6 +358,8 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
if (sec.nextInSectionGroup)
enqueue(sec.nextInSectionGroup, std::nullopt, &sec);
}
+
+ printWhyLive(ctx.symtab->find("foo"));
}
// Move the sections for some symbols to the main partition, specifically ifuncs
>From b9e3defbf36bc04c3d45e03a994f1355a1995770 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 4 Dec 2024 14:11:31 -0800
Subject: [PATCH 10/25] Add simple why-live printing fn
---
lld/ELF/MarkLive.cpp | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 5ebe94bcf9de45..0092bc7ed45345 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -56,7 +56,7 @@ template <class ELFT> class MarkLive {
private:
void enqueue(InputSectionBase *sec, std::optional<uint64_t> offset,
std::optional<LiveObject> parent);
- void printWhyLive(const Symbol *s) const;
+ void printWhyLive(Symbol *s) const;
void markSymbol(Symbol *sym);
void mark();
@@ -231,8 +231,29 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
queue.push_back(s);
}
-template <class ELFT>
-void MarkLive<ELFT>::printWhyLive(const Symbol *s) const {
+template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
+ std::string out = toString(*s) + " from " + toString(s->file);
+ int indent = 2;
+ LiveObject cur = s;
+ while (true) {
+ auto it = whyLive.find(cur);
+ if (it == whyLive.end())
+ if (auto *d = dyn_cast<Defined>(s))
+ it = whyLive.find(LiveObject{d->section});
+ if (it == whyLive.end())
+ break;
+ cur = it->second;
+ out += "\n" + std::string(indent, ' ');
+ if (std::holds_alternative<Symbol *>(cur)) {
+ auto *s = std::get<Symbol *>(cur);
+ out += toString(*s) + " from " + toString(s->file);
+ } else {
+ auto *s = std::get<InputSectionBase *>(cur);
+ // TODO: Fancy formatting
+ out += toString(s);
+ }
+ }
+ message(out);
}
template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
>From f76105c763511ef46d048b8392eb16ec4c472654 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 4 Dec 2024 14:13:23 -0800
Subject: [PATCH 11/25] Add missing cast
---
lld/ELF/MarkLive.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 0092bc7ed45345..bdefe6d0ab21a8 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -239,7 +239,8 @@ template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
auto it = whyLive.find(cur);
if (it == whyLive.end())
if (auto *d = dyn_cast<Defined>(s))
- it = whyLive.find(LiveObject{d->section});
+ if (auto *s = dyn_cast<InputSectionBase>(d->section))
+ it = whyLive.find(LiveObject{s});
if (it == whyLive.end())
break;
cur = it->second;
>From 306ed975384a9f64296fb59f5838b04545e12eda Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 4 Dec 2024 15:14:39 -0800
Subject: [PATCH 12/25] Explicitly mark roots as roots to break cycles
---
lld/ELF/MarkLive.cpp | 35 ++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index bdefe6d0ab21a8..05fb6ce92f3e14 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -54,8 +54,9 @@ template <class ELFT> class MarkLive {
void moveToMain();
private:
- void enqueue(InputSectionBase *sec, std::optional<uint64_t> offset,
- std::optional<LiveObject> parent);
+ void enqueue(InputSectionBase *sec,
+ std::optional<uint64_t> offset = std::nullopt,
+ std::optional<LiveObject> parent = std::nullopt);
void printWhyLive(Symbol *s) const;
void markSymbol(Symbol *sym);
void mark();
@@ -77,7 +78,7 @@ template <class ELFT> class MarkLive {
// identifiers, so we just store a SmallVector instead of a multimap.
DenseMap<StringRef, SmallVector<InputSectionBase *, 0>> cNamedSections;
- DenseMap<LiveObject, LiveObject> whyLive;
+ DenseMap<LiveObject, std::optional<LiveObject>> whyLive;
};
} // namespace
@@ -143,7 +144,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
}
for (InputSectionBase *sec : cNamedSections.lookup(sym.getName()))
- enqueue(sec, std::nullopt, parent);
+ enqueue(sec);
}
// The .eh_frame section is an unfortunate special case.
@@ -217,13 +218,11 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
return;
sec->partition = sec->partition ? 1 : partition;
- if (parent) {
- whyLive.try_emplace(sec, *parent);
- if (offset) {
- Defined *sym = sec->getEnclosingSymbol(*offset);
- if (sym)
- whyLive.try_emplace(sym, *parent);
- }
+ whyLive.try_emplace(sec, parent);
+ if (offset) {
+ Defined *sym = sec->getEnclosingSymbol(*offset);
+ if (sym)
+ whyLive.try_emplace(sym, parent);
}
// Add input section to the queue.
@@ -241,9 +240,11 @@ template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
if (auto *d = dyn_cast<Defined>(s))
if (auto *s = dyn_cast<InputSectionBase>(d->section))
it = whyLive.find(LiveObject{s});
- if (it == whyLive.end())
+ assert(it != whyLive.end() &&
+ "all live objects should have a tracked reason for being live");
+ if (!it->second)
break;
- cur = it->second;
+ cur = *it->second;
out += "\n" + std::string(indent, ' ');
if (std::holds_alternative<Symbol *>(cur)) {
auto *s = std::get<Symbol *>(cur);
@@ -260,7 +261,7 @@ template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
if (auto *d = dyn_cast_or_null<Defined>(sym))
if (auto *isec = dyn_cast_or_null<InputSectionBase>(d->section))
- enqueue(isec, d->value, std::nullopt);
+ enqueue(isec, d->value);
}
// This is the main function of the garbage collector.
@@ -307,7 +308,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
}
for (InputSectionBase *sec : ctx.inputSections) {
if (sec->flags & SHF_GNU_RETAIN) {
- enqueue(sec, std::nullopt, std::nullopt);
+ enqueue(sec);
continue;
}
if (sec->flags & SHF_LINK_ORDER)
@@ -346,7 +347,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
if (isReserved(sec) || ctx.script->shouldKeep(sec)) {
- enqueue(sec, std::nullopt, std::nullopt);
+ enqueue(sec);
} else if ((!ctx.arg.zStartStopGC || sec->name.starts_with("__libc_")) &&
isValidCIdentifier(sec->name)) {
// As a workaround for glibc libc.a before 2.34
@@ -406,7 +407,7 @@ template <class ELFT> void MarkLive<ELFT>::moveToMain() {
continue;
if (ctx.symtab->find(("__start_" + sec->name).str()) ||
ctx.symtab->find(("__stop_" + sec->name).str()))
- enqueue(sec, std::nullopt, std::nullopt);
+ enqueue(sec);
}
mark();
>From 9c136667d034f19f20a163c112e6a6beed3ab6b6 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 4 Dec 2024 15:26:49 -0800
Subject: [PATCH 13/25] Find bar actually, not foo
---
lld/ELF/MarkLive.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 05fb6ce92f3e14..64878c158eeb8e 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -382,7 +382,7 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
enqueue(sec.nextInSectionGroup, std::nullopt, &sec);
}
- printWhyLive(ctx.symtab->find("foo"));
+ printWhyLive(ctx.symtab->find("bar"));
}
// Move the sections for some symbols to the main partition, specifically ifuncs
>From 49ecd5728a9ee3bb97afbc2b39d10f551081f4eb Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 4 Dec 2024 15:38:53 -0800
Subject: [PATCH 14/25] Report section membership as a reason for being alive
---
lld/ELF/MarkLive.cpp | 43 +++++++++++++++++++++++++------------------
1 file changed, 25 insertions(+), 18 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 64878c158eeb8e..db740551406d23 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -231,29 +231,36 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
}
template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
- std::string out = toString(*s) + " from " + toString(s->file);
- int indent = 2;
- LiveObject cur = s;
- while (true) {
- auto it = whyLive.find(cur);
- if (it == whyLive.end())
- if (auto *d = dyn_cast<Defined>(s))
- if (auto *s = dyn_cast<InputSectionBase>(d->section))
- it = whyLive.find(LiveObject{s});
- assert(it != whyLive.end() &&
- "all live objects should have a tracked reason for being live");
- if (!it->second)
- break;
- cur = *it->second;
- out += "\n" + std::string(indent, ' ');
- if (std::holds_alternative<Symbol *>(cur)) {
- auto *s = std::get<Symbol *>(cur);
+ std::string out;
+ int indent = 0;
+ for (std::optional<LiveObject> cur = s; cur; indent += 2) {
+ if (indent)
+ out += "\n" + std::string(indent, ' ');
+ if (std::holds_alternative<Symbol *>(*cur)) {
+ auto *s = std::get<Symbol *>(*cur);
out += toString(*s) + " from " + toString(s->file);
} else {
- auto *s = std::get<InputSectionBase *>(cur);
+ auto *s = std::get<InputSectionBase *>(*cur);
// TODO: Fancy formatting
out += toString(s);
}
+
+ auto it = whyLive.find(*cur);
+ if (it != whyLive.end()) {
+ // If there is a specific reason this object is live, report it.
+ if (!it->second)
+ break;
+ cur = *it->second;
+ } else {
+ // This object is live merely by being a member of its parent section, so
+ // report the parent.
+ InputSectionBase *parent = nullptr;
+ if (auto *d = dyn_cast<Defined>(s))
+ parent = dyn_cast<InputSectionBase>(d->section);
+ assert(parent &&
+ "all live objects should have a tracked reason for being live");
+ cur = LiveObject{parent};
+ }
}
message(out);
}
>From 1ddc660a2ebc03d98adaa15ed2ee4429ef7cd94e Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 4 Dec 2024 16:03:17 -0800
Subject: [PATCH 15/25] If a specific symbol is referenced, it's the reason its
section is alive
---
lld/ELF/MarkLive.cpp | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index db740551406d23..7669f99f9cd349 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -218,11 +218,17 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
return;
sec->partition = sec->partition ? 1 : partition;
- whyLive.try_emplace(sec, parent);
- if (offset) {
- Defined *sym = sec->getEnclosingSymbol(*offset);
- if (sym)
- whyLive.try_emplace(sym, parent);
+ Defined *sym = nullptr;
+ if (offset)
+ sym = sec->getEnclosingSymbol(*offset);
+ if (sym) {
+ // If a specific symbol is referenced, the parent makes it alive, and it
+ // (may) makes its section alive.
+ whyLive.try_emplace(sym, parent);
+ whyLive.try_emplace(sec, sym);
+ } else {
+ // Otherwise, the parent generically makes the section itself live.
+ whyLive.try_emplace(sec, parent);
}
// Add input section to the queue.
>From acf5e58b5442c0369d1303ab6eaef92f158ed73f Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <mysterymath at gmail.com>
Date: Thu, 5 Dec 2024 12:21:51 -0800
Subject: [PATCH 16/25] Determine canonical symbol for a reference
---
lld/ELF/MarkLive.cpp | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 7669f99f9cd349..4432eb592abc73 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -54,8 +54,8 @@ template <class ELFT> class MarkLive {
void moveToMain();
private:
- void enqueue(InputSectionBase *sec,
- std::optional<uint64_t> offset = std::nullopt,
+ void enqueue(InputSectionBase *sec, uint64_t offset = 0,
+ Symbol *sym = nullptr,
std::optional<LiveObject> parent = std::nullopt);
void printWhyLive(Symbol *s) const;
void markSymbol(Symbol *sym);
@@ -131,8 +131,13 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
// group/SHF_LINK_ORDER rules (b) if the associated text section should be
// discarded, marking the LSDA will unnecessarily retain the text section.
if (!(fromFDE && ((relSec->flags & (SHF_EXECINSTR | SHF_LINK_ORDER)) ||
- relSec->nextInSectionGroup)))
- enqueue(relSec, offset, parent);
+ relSec->nextInSectionGroup))) {
+ Symbol *canonicalSym = d;
+ if (offset >= d->value + d->size)
+ if (Symbol *s = relSec->getEnclosingSymbol(offset))
+ canonicalSym = s;
+ enqueue(relSec, offset, canonicalSym, parent);
+ }
return;
}
@@ -202,14 +207,13 @@ static bool isReserved(InputSectionBase *sec) {
}
template <class ELFT>
-void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
- std::optional<uint64_t> offset,
- std::optional<LiveObject> parent) {
+void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
+ Symbol *sym, std::optional<LiveObject> parent) {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
if (auto *ms = dyn_cast<MergeInputSection>(sec))
- ms->getSectionPiece(offset.value_or(0)).live = true;
+ ms->getSectionPiece(offset).live = true;
// Set Sec->Partition to the meet (i.e. the "minimum") of Partition and
// Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition
@@ -218,9 +222,6 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec,
return;
sec->partition = sec->partition ? 1 : partition;
- Defined *sym = nullptr;
- if (offset)
- sym = sec->getEnclosingSymbol(*offset);
if (sym) {
// If a specific symbol is referenced, the parent makes it alive, and it
// (may) makes its section alive.
@@ -388,11 +389,11 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
resolveReloc(sec, rel, false);
for (InputSectionBase *isec : sec.dependentSections)
- enqueue(isec, std::nullopt, &sec);
+ enqueue(isec, 0, nullptr, &sec);
// Mark the next group member.
if (sec.nextInSectionGroup)
- enqueue(sec.nextInSectionGroup, std::nullopt, &sec);
+ enqueue(sec.nextInSectionGroup, 0, nullptr, &sec);
}
printWhyLive(ctx.symtab->find("bar"));
>From 97d98224857e83eb43f7d93d492171589d278401 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <mysterymath at gmail.com>
Date: Thu, 5 Dec 2024 12:33:45 -0800
Subject: [PATCH 17/25] Refer to sections rather than STT_SECTION symbols
---
lld/ELF/MarkLive.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 4432eb592abc73..420f2f5f16cb13 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -136,6 +136,8 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
if (offset >= d->value + d->size)
if (Symbol *s = relSec->getEnclosingSymbol(offset))
canonicalSym = s;
+ if (canonicalSym->isSection())
+ canonicalSym = nullptr;
enqueue(relSec, offset, canonicalSym, parent);
}
return;
>From 21d4a90027e1c33db56eb5c86e41fdd301cdc125 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <mysterymath at gmail.com>
Date: Thu, 5 Dec 2024 12:43:35 -0800
Subject: [PATCH 18/25] Encode parent for named sections
---
lld/ELF/MarkLive.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 420f2f5f16cb13..a9e49cd32815c0 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -151,7 +151,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
}
for (InputSectionBase *sec : cNamedSections.lookup(sym.getName()))
- enqueue(sec);
+ enqueue(sec, 0, nullptr, parent);
}
// The .eh_frame section is an unfortunate special case.
>From 31980cf86f1e2b5bc4cd90ebe84760820f52b16a Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <mysterymath at gmail.com>
Date: Thu, 5 Dec 2024 12:47:18 -0800
Subject: [PATCH 19/25] No defaults; was missing things
---
lld/ELF/MarkLive.cpp | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index a9e49cd32815c0..06b822e14d9f35 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -54,9 +54,8 @@ template <class ELFT> class MarkLive {
void moveToMain();
private:
- void enqueue(InputSectionBase *sec, uint64_t offset = 0,
- Symbol *sym = nullptr,
- std::optional<LiveObject> parent = std::nullopt);
+ void enqueue(InputSectionBase *sec, uint64_t offset, Symbol *sym,
+ std::optional<LiveObject> parent);
void printWhyLive(Symbol *s) const;
void markSymbol(Symbol *sym);
void mark();
@@ -277,7 +276,7 @@ template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
if (auto *d = dyn_cast_or_null<Defined>(sym))
if (auto *isec = dyn_cast_or_null<InputSectionBase>(d->section))
- enqueue(isec, d->value);
+ enqueue(isec, d->value, sym, std::nullopt);
}
// This is the main function of the garbage collector.
@@ -324,7 +323,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
}
for (InputSectionBase *sec : ctx.inputSections) {
if (sec->flags & SHF_GNU_RETAIN) {
- enqueue(sec);
+ enqueue(sec, 0, nullptr, std::nullopt);
continue;
}
if (sec->flags & SHF_LINK_ORDER)
@@ -363,7 +362,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
if (isReserved(sec) || ctx.script->shouldKeep(sec)) {
- enqueue(sec);
+ enqueue(sec, 0, nullptr, std::nullopt);
} else if ((!ctx.arg.zStartStopGC || sec->name.starts_with("__libc_")) &&
isValidCIdentifier(sec->name)) {
// As a workaround for glibc libc.a before 2.34
@@ -423,7 +422,7 @@ template <class ELFT> void MarkLive<ELFT>::moveToMain() {
continue;
if (ctx.symtab->find(("__start_" + sec->name).str()) ||
ctx.symtab->find(("__stop_" + sec->name).str()))
- enqueue(sec);
+ enqueue(sec, 0, nullptr, std::nullopt);
}
mark();
>From 5ad90dbccb8db44fbb8f78343cf5824a9d24875b Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Fri, 6 Dec 2024 15:31:52 -0800
Subject: [PATCH 20/25] Add why-live option
---
lld/ELF/Options.td | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index ebe77204264210..9ad09fa3f89c40 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -556,6 +556,10 @@ defm wrap : Eq<"wrap", "Redirect symbol references to __wrap_symbol and "
"__real_symbol references to symbol">,
MetaVarName<"<symbol>">;
+defm why_live : EEq<"why-live", "Report a chain of references to <symbol-glob> that keeps it from "
+ "being garbage collected">,
+ MetaVarName<"<symbol-glob>">;
+
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
>From 6c55f640684c093a564d66249acc774a4d2299c8 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Fri, 6 Dec 2024 15:34:06 -0800
Subject: [PATCH 21/25] toStr
---
lld/ELF/MarkLive.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 06b822e14d9f35..796a50366f36f8 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -246,11 +246,11 @@ template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
out += "\n" + std::string(indent, ' ');
if (std::holds_alternative<Symbol *>(*cur)) {
auto *s = std::get<Symbol *>(*cur);
- out += toString(*s) + " from " + toString(s->file);
+ out += toStr(ctx, *s) + " from " + toStr(ctx, s->file);
} else {
auto *s = std::get<InputSectionBase *>(*cur);
// TODO: Fancy formatting
- out += toString(s);
+ out += toStr(ctx, s);
}
auto it = whyLive.find(*cur);
>From 90a8f52f171f414207c892c202be9509ceb5c207 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Fri, 6 Dec 2024 15:36:35 -0800
Subject: [PATCH 22/25] Better wording
---
lld/ELF/Options.td | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 9ad09fa3f89c40..4d0531005adb92 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -556,9 +556,9 @@ defm wrap : Eq<"wrap", "Redirect symbol references to __wrap_symbol and "
"__real_symbol references to symbol">,
MetaVarName<"<symbol>">;
-defm why_live : EEq<"why-live", "Report a chain of references to <symbol-glob> that keeps it from "
- "being garbage collected">,
- MetaVarName<"<symbol-glob>">;
+defm why_live : EEq<"why-live", "Report a chain of references preventing garbage collection for "
+ "each symbol matching <glob>">,
+ MetaVarName<"<glob>">;
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
>From 50ca32647a88a817eed2b310aa1d168570890f0f Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Mon, 9 Dec 2024 11:51:12 -0800
Subject: [PATCH 23/25] Parse whylive arg
---
lld/ELF/Config.h | 1 +
lld/ELF/Driver.cpp | 9 +++++++++
2 files changed, 10 insertions(+)
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index a2836733c2715e..e3a0d90ceb5682 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -223,6 +223,7 @@ struct Config {
llvm::StringRef thinLTOCacheDir;
llvm::StringRef thinLTOIndexOnlyArg;
llvm::StringRef whyExtract;
+ llvm::SmallVector<llvm::GlobPattern, 0> whyLive;
llvm::StringRef cmseInputLib;
llvm::StringRef cmseOutputLib;
StringRef zBtiReport = "none";
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index bc4b967ccbbbb4..b93178cebebd00 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1469,6 +1469,15 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
ctx.arg.warnSymbolOrdering =
args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
ctx.arg.whyExtract = args.getLastArgValue(OPT_why_extract);
+ for (opt::Arg *arg : args.filtered(OPT_why_live)) {
+ StringRef value(arg->getValue());
+ if (Expected<GlobPattern> pat = GlobPattern::create(arg->getValue())) {
+ ctx.arg.whyLive.emplace_back(std::move(*pat));
+ } else {
+ ErrAlways(ctx) << arg->getSpelling() << ": " << pat.takeError();
+ continue;
+ }
+ }
ctx.arg.zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true);
ctx.arg.zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true);
ctx.arg.zForceBti = hasZOption(args, "force-bti");
>From 94a10b29e8403cf7b448b426f3a7ff9c1f2bc6e5 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Mon, 9 Dec 2024 12:18:28 -0800
Subject: [PATCH 24/25] Connect whylive pattern matching
---
lld/ELF/MarkLive.cpp | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 796a50366f36f8..8bdf454bf32b28 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -397,8 +397,13 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
enqueue(sec.nextInSectionGroup, 0, nullptr, &sec);
}
- printWhyLive(ctx.symtab->find("bar"));
-}
+ for (Symbol *sym : ctx.symtab->getSymbols()) {
+ if (llvm::any_of(ctx.arg.whyLive, [sym](const llvm::GlobPattern &pat) {
+ return pat.match(sym->getName());
+ }))
+ printWhyLive(sym);
+ }
+ }
// Move the sections for some symbols to the main partition, specifically ifuncs
// (because they can result in an IRELATIVE being added to the main partition's
>From 99ec544fa24dc479251fd9af9c685421ca30810c Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Mon, 9 Dec 2024 14:30:19 -0800
Subject: [PATCH 25/25] Don't trigger assertion for dead symbols
---
lld/ELF/MarkLive.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 8bdf454bf32b28..2401ae056a6256 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -241,6 +241,8 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
std::string out;
int indent = 0;
+ if (!whyLive.contains(s))
+ return;
for (std::optional<LiveObject> cur = s; cur; indent += 2) {
if (indent)
out += "\n" + std::string(indent, ' ');
@@ -403,7 +405,7 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
}))
printWhyLive(sym);
}
- }
+}
// Move the sections for some symbols to the main partition, specifically ifuncs
// (because they can result in an IRELATIVE being added to the main partition's
More information about the llvm-commits
mailing list