diff --git a/lld/MachO/MapFile.cpp b/lld/MachO/MapFile.cpp --- a/lld/MachO/MapFile.cpp +++ b/lld/MachO/MapFile.cpp @@ -40,25 +40,6 @@ using namespace lld; using namespace lld::macho; -// Returns a list of all symbols that we want to print out. -static std::vector getSymbols() { - std::vector v; - for (InputFile *file : inputFiles) - if (isa(file)) - for (Symbol *sym : file->symbols) - if (auto *d = dyn_cast_or_null(sym)) - if (d->isLive() && d->isec && d->getFile() == file) { - assert(!shouldOmitFromOutput(d->isec)); - v.push_back(d); - } - - parallelSort(v.begin(), v.end(), [](Defined *a, Defined *b) { - return a->getVA() != b->getVA() ? a->getVA() < b->getVA() - : a->getName() < b->getName(); - }); - return v; -} - // Construct a map from symbols to their stringified representations. // Demangling symbols (which is what toString() does) is slow, so // we do that in batch using parallel-for. @@ -76,6 +57,73 @@ return ret; } +namespace { + +using ReaderToFileOrdinal = DenseMap; + +// A collection of symbols. All the symbols contained are live iff Live == true. +// Else, all the symbols contained are dead. +template class Symbols { +public: + void push_back(Defined *symbol) { + assert(symbol != nullptr); + assert(symbol->isLive() == Live); + data.push_back(symbol); + } + + void sort() { + parallelSort(data.begin(), data.end(), [](Defined *a, Defined *b) { + return Live && a->getVA() != b->getVA() ? a->getVA() < b->getVA() + : a->getName() < b->getName(); + }); + } + + // Dump table of symbols + void print(raw_ostream &os, ReaderToFileOrdinal &readerToFileOrdinal) { + DenseMap symStr = getSymbolStrings(data); + os << "# Address\t File Name\n"; + + if (Live) { + for (Symbol *sym : data) { + os << format("0x%08llX\t[%3u] %s\n", sym->getVA(), + readerToFileOrdinal[sym->getFile()], symStr[sym].c_str()); + } + } else { + for (Symbol *sym : data) { + os << format("<>\t[%3u] %s\n", + readerToFileOrdinal[sym->getFile()], symStr[sym].c_str()); + } + } + }; + +private: + std::vector data; +}; + +} // namespace + +// Return all live symbols and dead symbols in two separate collections. +static std::pair, Symbols> getSymbols() { + Symbols liveSymbols; + Symbols deadSymbols; + for (InputFile *file : inputFiles) + if (isa(file)) + for (Symbol *sym : file->symbols) + if (auto *d = dyn_cast_or_null(sym)) + if (d->isec && d->getFile() == file) { + if (d->isLive()) { + assert(!shouldOmitFromOutput(d->isec)); + liveSymbols.push_back(d); + } else { + deadSymbols.push_back(d); + } + } + + liveSymbols.sort(); + deadSymbols.sort(); + return std::make_pair(std::move(liveSymbols), std::move(deadSymbols)); +} + void macho::writeMapFile() { if (config->mapFile.empty()) return; @@ -101,7 +149,7 @@ os << "# Object files:\n"; os << format("[%3u] %s\n", 0, (const char *)"linker synthesized"); uint32_t fileIndex = 1; - DenseMap readerToFileOrdinal; + ReaderToFileOrdinal readerToFileOrdinal; for (InputFile *file : inputFiles) { if (isa(file)) { os << format("[%3u] %s\n", fileIndex, file->getName().str().c_str()); @@ -109,10 +157,6 @@ } } - // Collect symbol info that we want to print out. - std::vector syms = getSymbols(); - DenseMap symStr = getSymbolStrings(syms); - // Dump table of sections os << "# Sections:\n"; os << "# Address\tSize \tSegment\tSection\n"; @@ -125,13 +169,15 @@ seg->name.str().c_str(), osec->name.str().c_str()); } - // Dump table of symbols + Symbols liveSymbols; + Symbols deadSymbols; + std::tie(liveSymbols, deadSymbols) = getSymbols(); + os << "# Symbols:\n"; - os << "# Address\t File Name\n"; - for (Symbol *sym : syms) { - os << format("0x%08llX\t[%3u] %s\n", sym->getVA(), - readerToFileOrdinal[sym->getFile()], symStr[sym].c_str()); - } + liveSymbols.print(os, readerToFileOrdinal); - // TODO: when we implement -dead_strip, we should dump dead stripped symbols + if (config->deadStrip) { + os << "# Dead Stripped Symbols:\n"; + deadSymbols.print(os, readerToFileOrdinal); + } } diff --git a/lld/test/MachO/dead-strip.s b/lld/test/MachO/dead-strip.s --- a/lld/test/MachO/dead-strip.s +++ b/lld/test/MachO/dead-strip.s @@ -16,7 +16,7 @@ # RUN: --exports-trie --indirect-symbols %t/basics | \ # RUN: FileCheck --check-prefix=EXECDATA --implicit-check-not _unref %s # RUN: llvm-otool -l %t/basics | grep -q 'segname __PAGEZERO' -# RUN: FileCheck --check-prefix=MAP --implicit-check-not _unref %s < %t/map +# RUN: FileCheck --check-prefix=MAP %s < %t/map # EXEC-LABEL: Sections: # EXEC-LABEL: Name # EXEC-NEXT: __text @@ -45,6 +45,13 @@ # EXECDATA-NEXT: _ref_com # EXECDATA-NEXT: _no_dead_strip_globl # MAP: _main +# MAP-LABEL: Dead Stripped Symbols +# MAP: <> [ 1] _unref_com +# MAP: <> [ 1] _unref_data +# MAP: <> [ 1] _unref_extern +# MAP: <> [ 1] _unref_local +# MAP: <> [ 1] _unref_private_extern +# MAP: <> [ 1] l_unref_data # RUN: %lld -dylib -dead_strip -u _ref_private_extern_u %t/basics.o -o %t/basics.dylib # RUN: llvm-objdump --syms %t/basics.dylib | \