diff --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt index 2bfd93b9aea7..e76496bc4db9 100644 --- a/lld/COFF/CMakeLists.txt +++ b/lld/COFF/CMakeLists.txt @@ -10,6 +10,7 @@ add_llvm_library(lldCOFF Error.cpp ICF.cpp InputFiles.cpp + MarkLive.cpp ModuleDef.cpp SymbolTable.cpp Symbols.cpp diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index fe931a40bdac..9eade900ffca 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -644,6 +644,14 @@ void LinkerDriver::link(llvm::ArrayRef ArgsArr) { if (auto *Arg = Args.getLastArg(OPT_pdb)) touchFile(Arg->getValue()); + // Identify unreferenced COMDAT sections. + if (Config->DoGC) + markLive(Symtab.getChunks()); + + // Identify identical COMDAT sections to merge them. + if (Config->DoICF) + doICF(Symtab.getChunks()); + // Write the result. writeResult(&Symtab); diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index cf2c575e912e..f3439682dc0d 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -37,6 +37,12 @@ class InputFile; // Entry point of the COFF linker. void link(llvm::ArrayRef Args); +// Implemented in MarkLive.cpp. +void markLive(const std::vector &Chunks); + +// Implemented in ICF.cpp. +void doICF(const std::vector &Chunks); + class ArgParser { public: ArgParser() : Alloc(AllocAux) {} diff --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp new file mode 100644 index 000000000000..0870986ad81a --- /dev/null +++ b/lld/COFF/MarkLive.cpp @@ -0,0 +1,61 @@ +//===- MarkLive.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Chunks.h" +#include "Symbols.h" +#include "llvm/ADT/STLExtras.h" +#include + +namespace lld { +namespace coff { + +// Set live bit on for each reachable chunk. Unmarked (unreachable) +// COMDAT chunks will be ignored by Writer, so they will be excluded +// from the final output. +void markLive(const std::vector &Chunks) { + // We build up a worklist of sections which have been marked as live. We only + // push into the worklist when we discover an unmarked section, and we mark + // as we push, so sections never appear twice in the list. + SmallVector Worklist; + + // COMDAT section chunks are dead by default. Add non-COMDAT chunks. + for (Chunk *C : Chunks) + if (auto *SC = dyn_cast(C)) + if (SC->isLive()) + Worklist.push_back(SC); + + auto Enqueue = [&](SectionChunk *C) { + if (C->isLive()) + return; + C->markLive(); + Worklist.push_back(C); + }; + + // Add GC root chunks. + for (Undefined *U : Config->GCRoot) + if (auto *D = dyn_cast(U->repl())) + Enqueue(D->getChunk()); + + while (!Worklist.empty()) { + SectionChunk *SC = Worklist.pop_back_val(); + assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); + + // Mark all symbols listed in the relocation table for this section. + for (SymbolBody *S : SC->symbols()) + if (auto *D = dyn_cast(S->repl())) + Enqueue(D->getChunk()); + + // Mark associative sections if any. + for (SectionChunk *C : SC->children()) + Enqueue(C); + } +} + +} +} diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 7a4fbc2bdd3b..8e1a652980f3 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -49,8 +49,6 @@ public: void run(); private: - void markLive(); - void dedupCOMDATs(); void createSections(); void createMiscChunks(); void createImportTables(); @@ -216,8 +214,6 @@ bool Defined::isExecutable() { // The main function of the writer. void Writer::run() { - markLive(); - dedupCOMDATs(); createSections(); createMiscChunks(); createImportTables(); @@ -239,57 +235,6 @@ void Writer::run() { error(Buffer->commit(), "Failed to write the output file"); } -// Set live bit on for each reachable chunk. Unmarked (unreachable) -// COMDAT chunks will be ignored in the next step, so that they don't -// come to the final output file. -void Writer::markLive() { - if (!Config->DoGC) - return; - - // We build up a worklist of sections which have been marked as live. We only - // push into the worklist when we discover an unmarked section, and we mark - // as we push, so sections never appear twice in the list. - SmallVector Worklist; - - // COMDAT section chunks are dead by default. Add non-COMDAT chunks. - for (Chunk *C : Symtab->getChunks()) - if (auto *SC = dyn_cast(C)) - if (SC->isLive()) - Worklist.push_back(SC); - - auto Enqueue = [&](SectionChunk *C) { - if (C->isLive()) - return; - C->markLive(); - Worklist.push_back(C); - }; - - // Add GC root chunks. - for (Undefined *U : Config->GCRoot) - if (auto *D = dyn_cast(U->repl())) - Enqueue(D->getChunk()); - - while (!Worklist.empty()) { - SectionChunk *SC = Worklist.pop_back_val(); - assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); - - // Mark all symbols listed in the relocation table for this section. - for (SymbolBody *S : SC->symbols()) - if (auto *D = dyn_cast(S->repl())) - Enqueue(D->getChunk()); - - // Mark associative sections if any. - for (SectionChunk *C : SC->children()) - Enqueue(C); - } -} - -// Merge identical COMDAT sections. -void Writer::dedupCOMDATs() { - if (Config->DoICF) - doICF(Symtab->getChunks()); -} - static StringRef getOutputSection(StringRef Name) { StringRef S = Name.split('$').first; auto It = Config->Merge.find(S); diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h index 6c1592cd6cb5..0473315ae50a 100644 --- a/lld/COFF/Writer.h +++ b/lld/COFF/Writer.h @@ -20,9 +20,6 @@ class OutputSection; void writeResult(SymbolTable *T); -// Implemented in ICF.cpp. -void doICF(const std::vector &Chunks); - } }