summaryrefslogtreecommitdiff
path: root/ELF/MarkLive.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:19:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:19:15 +0000
commitd93e1dfac8711cfed1a9d9cd1876a788b83945cd (patch)
tree5896fa6c02a262a6148b215487e545d937de58b7 /ELF/MarkLive.cpp
parent8d43286d630f9224de07809ea253e83ebb9cdee6 (diff)
Notes
Diffstat (limited to 'ELF/MarkLive.cpp')
-rw-r--r--ELF/MarkLive.cpp150
1 files changed, 102 insertions, 48 deletions
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index 41e30ce599d2..8d129fc3ff13 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -36,22 +36,24 @@
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
+namespace {
// A resolved relocation. The Sec and Offset fields are set if the relocation
// was resolved to an offset within a section.
-template <class ELFT>
-struct ResolvedReloc {
+template <class ELFT> struct ResolvedReloc {
InputSectionBase<ELFT> *Sec;
typename ELFT::uint Offset;
};
+} // end anonymous namespace
template <class ELFT>
static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
const typename ELFT::Rel &Rel) {
- return Target->getImplicitAddend(Sec.getSectionData().begin(),
+ return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
Rel.getType(Config->Mips64EL));
}
@@ -74,56 +76,103 @@ static ResolvedReloc<ELFT> resolveReloc(InputSectionBase<ELFT> &Sec,
return {D->Section->Repl, Offset};
}
-template <class ELFT, class Elf_Shdr>
-static void run(ELFFile<ELFT> &Obj, InputSectionBase<ELFT> &Sec,
- Elf_Shdr *RelSec, std::function<void(ResolvedReloc<ELFT>)> Fn) {
- if (RelSec->sh_type == SHT_RELA) {
- for (const typename ELFT::Rela &RI : Obj.relas(RelSec))
- Fn(resolveReloc(Sec, RI));
- } else {
- for (const typename ELFT::Rel &RI : Obj.rels(RelSec))
- Fn(resolveReloc(Sec, RI));
- }
-}
-
// Calls Fn for each section that Sec refers to via relocations.
template <class ELFT>
static void forEachSuccessor(InputSection<ELFT> &Sec,
std::function<void(ResolvedReloc<ELFT>)> Fn) {
- ELFFile<ELFT> &Obj = Sec.getFile()->getObj();
- for (const typename ELFT::Shdr *RelSec : Sec.RelocSections)
- run(Obj, Sec, RelSec, Fn);
+ if (Sec.AreRelocsRela) {
+ for (const typename ELFT::Rela &Rel : Sec.relas())
+ Fn(resolveReloc(Sec, Rel));
+ } else {
+ for (const typename ELFT::Rel &Rel : Sec.rels())
+ Fn(resolveReloc(Sec, Rel));
+ }
+ if (Sec.DependentSection)
+ Fn({Sec.DependentSection, 0});
+}
+
+// The .eh_frame section is an unfortunate special case.
+// The section is divided in CIEs and FDEs and the relocations it can have are
+// * CIEs can refer to a personality function.
+// * FDEs can refer to a LSDA
+// * FDEs refer to the function they contain information about
+// The last kind of relocation cannot keep the referred section alive, or they
+// would keep everything alive in a common object file. In fact, each FDE is
+// alive if the section it refers to is alive.
+// To keep things simple, in here we just ignore the last relocation kind. The
+// other two keep the referred section alive.
+//
+// A possible improvement would be to fully process .eh_frame in the middle of
+// the gc pass. With that we would be able to also gc some sections holding
+// LSDAs and personality functions if we found that they were unused.
+template <class ELFT, class RelTy>
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
+ std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+ const endianness E = ELFT::TargetEndianness;
+ for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
+ EhSectionPiece &Piece = EH.Pieces[I];
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI == (unsigned)-1)
+ continue;
+ if (read32<E>(Piece.data().data() + 4) == 0) {
+ // This is a CIE, we only need to worry about the first relocation. It is
+ // known to point to the personality function.
+ Enqueue(resolveReloc(EH, Rels[FirstRelI]));
+ continue;
+ }
+ // This is a FDE. The relocations point to the described function or to
+ // a LSDA. We only need to keep the LSDA alive, so ignore anything that
+ // points to executable sections.
+ typename ELFT::uint PieceEnd = Piece.InputOff + Piece.size();
+ for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) {
+ const RelTy &Rel = Rels[I2];
+ if (Rel.r_offset >= PieceEnd)
+ break;
+ ResolvedReloc<ELFT> R = resolveReloc(EH, Rels[I2]);
+ if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ continue;
+ if (R.Sec->Flags & SHF_EXECINSTR)
+ continue;
+ Enqueue({R.Sec, 0});
+ }
+ }
}
template <class ELFT>
-static void scanEhFrameSection(EhInputSection<ELFT> &EH,
- std::function<void(ResolvedReloc<ELFT>)> Fn) {
- if (!EH.RelocSection)
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH,
+ std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+ if (!EH.NumRelocations)
return;
- ELFFile<ELFT> &EObj = EH.getFile()->getObj();
- run<ELFT>(EObj, EH, EH.RelocSection, [&](ResolvedReloc<ELFT> R) {
- if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
- return;
- if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR)
- return;
- Fn({R.Sec, 0});
- });
+
+ // Unfortunately we need to split .eh_frame early since some relocations in
+ // .eh_frame keep other section alive and some don't.
+ EH.split();
+
+ if (EH.AreRelocsRela)
+ scanEhFrameSection(EH, EH.relas(), Enqueue);
+ else
+ scanEhFrameSection(EH, EH.rels(), Enqueue);
}
-// Sections listed below are special because they are used by the loader
-// just by being in an ELF file. They should not be garbage-collected.
+// We do not garbage-collect two types of sections:
+// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr)
+// 2) Non-allocatable sections which typically contain debugging information
template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
- switch (Sec->getSectionHdr()->sh_type) {
+ switch (Sec->Type) {
case SHT_FINI_ARRAY:
case SHT_INIT_ARRAY:
case SHT_NOTE:
case SHT_PREINIT_ARRAY:
return true;
default:
- StringRef S = Sec->getSectionName();
+ if (!(Sec->Flags & SHF_ALLOC))
+ return true;
// We do not want to reclaim sections if they can be referred
// by __start_* and __stop_* symbols.
+ StringRef S = Sec->Name;
if (isValidCIdentifier(S))
return true;
@@ -140,7 +189,15 @@ template <class ELFT> void elf::markLive() {
SmallVector<InputSection<ELFT> *, 256> Q;
auto Enqueue = [&](ResolvedReloc<ELFT> R) {
- if (!R.Sec)
+ // Skip over discarded sections. This in theory shouldn't happen, because
+ // the ELF spec doesn't allow a relocation to point to a deduplicated
+ // COMDAT section directly. Unfortunately this happens in practice (e.g.
+ // .eh_frame) so we need to add a check.
+ if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ return;
+
+ // We don't gc non alloc sections.
+ if (!(R.Sec->Flags & SHF_ALLOC))
return;
// Usually, a whole section is marked as live or dead, but in mergeable
@@ -152,6 +209,7 @@ template <class ELFT> void elf::markLive() {
if (R.Sec->Live)
return;
R.Sec->Live = true;
+ // Add input section to the queue.
if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec))
Q.push_back(S);
};
@@ -162,8 +220,7 @@ template <class ELFT> void elf::markLive() {
};
// Add GC root symbols.
- if (Config->EntrySym)
- MarkSymbol(Config->EntrySym->body());
+ MarkSymbol(Symtab<ELFT>::X->find(Config->Entry));
MarkSymbol(Symtab<ELFT>::X->find(Config->Init));
MarkSymbol(Symtab<ELFT>::X->find(Config->Fini));
for (StringRef S : Config->Undefined)
@@ -177,18 +234,15 @@ template <class ELFT> void elf::markLive() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
- for (const std::unique_ptr<ObjectFile<ELFT>> &F :
- Symtab<ELFT>::X->getObjectFiles())
- for (InputSectionBase<ELFT> *Sec : F->getSections())
- if (Sec && Sec != &InputSection<ELFT>::Discarded) {
- // .eh_frame is always marked as live now, but also it can reference to
- // sections that contain personality. We preserve all non-text sections
- // referred by .eh_frame here.
- if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec))
- scanEhFrameSection<ELFT>(*EH, Enqueue);
- if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec))
- Enqueue({Sec, 0});
- }
+ for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
+ // .eh_frame is always marked as live now, but also it can reference to
+ // sections that contain personality. We preserve all non-text sections
+ // referred by .eh_frame here.
+ if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec))
+ scanEhFrameSection<ELFT>(*EH, Enqueue);
+ if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec))
+ Enqueue({Sec, 0});
+ }
// Mark all reachable sections.
while (!Q.empty())