diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:19:15 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:19:15 +0000 |
commit | d93e1dfac8711cfed1a9d9cd1876a788b83945cd (patch) | |
tree | 5896fa6c02a262a6148b215487e545d937de58b7 /ELF/MarkLive.cpp | |
parent | 8d43286d630f9224de07809ea253e83ebb9cdee6 (diff) |
Notes
Diffstat (limited to 'ELF/MarkLive.cpp')
-rw-r--r-- | ELF/MarkLive.cpp | 150 |
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()) |