//===- 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 not included into output. // //===----------------------------------------------------------------------===// #include "InputSection.h" #include "LinkerScript.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::elf; // Calls Fn for each section that Sec refers to via relocations. template static void forEachSuccessor( InputSection *Sec, std::function *, typename ELFT::uint Offset)> Fn) { typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::uint uintX_t; 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)) { std::pair *, uintX_t> P = Sec->getRelocTarget(RI); Fn(P.first, P.second); } } else { for (const Elf_Rel &RI : Obj.rels(RelSec)) { std::pair *, uintX_t> P = Sec->getRelocTarget(RI); Fn(P.first, P.second); } } } } // 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(); // We do not want to reclaim sections if they can be referred // by __start_* and __stop_* symbols. if (isValidCIdentifier(S)) return true; return S.startswith(".ctors") || S.startswith(".dtors") || S.startswith(".init") || S.startswith(".fini") || S.startswith(".jcr"); } } // This is the main function of the garbage collector. // Starting from GC-root sections, this function visits all reachable // sections to set their "Live" bits. template void elf::markLive(SymbolTable *Symtab) { typedef typename ELFT::uint uintX_t; SmallVector *, 256> Q; auto Enqueue = [&](InputSectionBase *Sec, uintX_t Offset) { if (!Sec) return; if (auto *MS = dyn_cast>(Sec)) { std::pair *, uintX_t> T = MS->getRangeAndSize(Offset); T.first->second = 0; } if (Sec->Live) return; Sec->Live = true; if (InputSection *S = dyn_cast>(Sec)) Q.push_back(S); }; auto MarkSymbol = [&](SymbolBody *Sym) { if (Sym) if (auto *D = dyn_cast>(Sym)) Enqueue(D->Section, D->Value); }; // Add GC root symbols. if (Config->EntrySym) MarkSymbol(Config->EntrySym->Body); 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 can interrupt other ELF file's symbols at runtime. for (const Symbol *S : Symtab->getSymbols()) if (S->includeInDynsym()) MarkSymbol(S->Body); // Preserve special sections and those which are specified in linker // script KEEP command. for (const std::unique_ptr> &F : Symtab->getObjectFiles()) for (InputSectionBase *Sec : F->getSections()) if (Sec && Sec != &InputSection::Discarded) if (isReserved(Sec) || Script::X->shouldKeep(Sec)) Enqueue(Sec, 0); // Mark all reachable sections. while (!Q.empty()) forEachSuccessor(Q.pop_back_val(), Enqueue); } template void elf::markLive(SymbolTable *); template void elf::markLive(SymbolTable *); template void elf::markLive(SymbolTable *); template void elf::markLive(SymbolTable *);