//===- MarkLive.cpp -------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements --gc-sections, which is a feature to remove unused // sections from output. Unused sections are sections that are not reachable // from known GC-root symbols or sections. Naturally the feature is // implemented as a mark-sweep garbage collector. // // Here's how it works. Each InputSectionBase has a "Live" bit. The bit is off // by default. Starting with GC-root symbols or sections, markLive function // defined in this file visits all reachable sections to set their Live // bits. Writer will then ignore sections whose Live bits are off, so that // such sections are removed from output. // //===----------------------------------------------------------------------===// #include "InputSection.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace lld; using namespace lld::elf2; // Calls Fn for each section that Sec refers to. template static void forEachSuccessor(InputSection *Sec, std::function *)> Fn) { typedef typename ELFFile::Elf_Rel Elf_Rel; typedef typename ELFFile::Elf_Rela Elf_Rela; typedef typename ELFFile::Elf_Shdr Elf_Shdr; ELFFile &Obj = Sec->getFile()->getObj(); for (const Elf_Shdr *RelSec : Sec->RelocSections) { if (RelSec->sh_type == SHT_RELA) { for (const Elf_Rela &RI : Obj.relas(RelSec)) if (InputSectionBase *Succ = Sec->getRelocTarget(RI)) Fn(Succ); } else { for (const Elf_Rel &RI : Obj.rels(RelSec)) if (InputSectionBase *Succ = Sec->getRelocTarget(RI)) Fn(Succ); } } } // 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. template static bool isReserved(InputSectionBase *Sec) { switch (Sec->getSectionHdr()->sh_type) { case SHT_FINI_ARRAY: case SHT_INIT_ARRAY: case SHT_NOTE: case SHT_PREINIT_ARRAY: return true; default: StringRef S = Sec->getSectionName(); return S.startswith(".init") || S.startswith(".fini") || S.startswith(".jcr") || S == ".eh_frame"; } } template void lld::elf2::markLive(SymbolTable *Symtab) { SmallVector *, 256> Q; auto Enqueue = [&](InputSectionBase *Sec) { if (!Sec || Sec->Live) return; Sec->Live = true; Q.push_back(Sec); }; auto MarkSymbol = [&](SymbolBody *Sym) { if (Sym) if (auto *D = dyn_cast>(Sym->repl())) Enqueue(&D->Section); }; // Add GC root symbols. MarkSymbol(Config->EntrySym); MarkSymbol(Symtab->find(Config->Init)); MarkSymbol(Symtab->find(Config->Fini)); for (StringRef S : Config->Undefined) MarkSymbol(Symtab->find(S)); // Preserve externally-visible symbols if the symbols defined by this // file could override other ELF file's symbols at runtime. if (Config->Shared || Config->ExportDynamic) { for (const std::pair &P : Symtab->getSymbols()) { SymbolBody *B = P.second->Body; if (B->getVisibility() == STV_DEFAULT) MarkSymbol(B); } } // Preserve special sections. for (const std::unique_ptr> &F : Symtab->getObjectFiles()) for (InputSectionBase *Sec : F->getSections()) if (Sec && Sec != &InputSection::Discarded) if (isReserved(Sec)) Enqueue(Sec); // Mark all reachable sections. while (!Q.empty()) if (auto *Sec = dyn_cast>(Q.pop_back_val())) forEachSuccessor(Sec, Enqueue); } template void lld::elf2::markLive(SymbolTable *); template void lld::elf2::markLive(SymbolTable *); template void lld::elf2::markLive(SymbolTable *); template void lld::elf2::markLive(SymbolTable *);