diff --git a/lld/include/lld/Core/ArchiveLibraryFile.h b/lld/include/lld/Core/ArchiveLibraryFile.h index e85f7886515c..be0213ed8cd5 100644 --- a/lld/include/lld/Core/ArchiveLibraryFile.h +++ b/lld/include/lld/Core/ArchiveLibraryFile.h @@ -12,6 +12,8 @@ #include "lld/Core/File.h" +#include + namespace lld { /// @@ -36,6 +38,10 @@ public: virtual error_code parseAllMembers(std::vector> &result) const = 0; + virtual std::set getDefinedSymbols() const { + return std::set(); + } + protected: /// only subclasses of ArchiveLibraryFile can be instantiated ArchiveLibraryFile(StringRef path) : File(path, kindArchiveLibrary) {} diff --git a/lld/include/lld/Core/InputGraph.h b/lld/include/lld/Core/InputGraph.h index 2c63b6166407..2a2c85b1ab1e 100644 --- a/lld/include/lld/Core/InputGraph.h +++ b/lld/include/lld/Core/InputGraph.h @@ -23,6 +23,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include #include #include #include @@ -67,6 +68,11 @@ public: /// whether it should iterate over again or terminate or not. void notifyProgress(); + /// Adds an observer of getNextFile(). Each time a new file is about to be + /// returned from getNextFile(), registered observers are called with the file + /// being returned. + void registerObserver(std::function &fn); + /// \brief Adds a node into the InputGraph void addInputElement(std::unique_ptr); @@ -93,6 +99,7 @@ protected: // Index of the next element to be processed uint32_t _nextElementIndex; InputElement *_currentInputElement; + std::vector> _observers; private: ErrorOr getNextInputElement(); diff --git a/lld/lib/Core/InputGraph.cpp b/lld/lib/Core/InputGraph.cpp index 754a19f109fd..13604a1a1b22 100644 --- a/lld/lib/Core/InputGraph.cpp +++ b/lld/lib/Core/InputGraph.cpp @@ -21,9 +21,12 @@ ErrorOr InputGraph::getNextFile() { // it will succeed. If not, try to get the next file in the input graph. for (;;) { if (_currentInputElement) { - ErrorOr nextFile = _currentInputElement->getNextFile(); - if (nextFile.getError() != InputGraphError::no_more_files) - return std::move(nextFile); + ErrorOr next = _currentInputElement->getNextFile(); + if (next.getError() != InputGraphError::no_more_files) { + for (std::function &observer : _observers) + observer(&next.get()); + return std::move(next); + } } ErrorOr elt = getNextInputElement(); @@ -35,6 +38,10 @@ ErrorOr InputGraph::getNextFile() { void InputGraph::notifyProgress() { _currentInputElement->notifyProgress(); } +void InputGraph::registerObserver(std::function &fn) { + _observers.push_back(fn); +} + void InputGraph::addInputElement(std::unique_ptr ie) { _inputArgs.push_back(std::move(ie)); } diff --git a/lld/lib/Driver/WinLinkDriver.cpp b/lld/lib/Driver/WinLinkDriver.cpp index 74d6a5bf8354..685f8c00c1ec 100644 --- a/lld/lib/Driver/WinLinkDriver.cpp +++ b/lld/lib/Driver/WinLinkDriver.cpp @@ -13,10 +13,12 @@ /// //===----------------------------------------------------------------------===// +#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Driver/Driver.h" #include "lld/Driver/WinLinkInputGraph.h" #include "lld/Driver/WinLinkModuleDef.h" #include "lld/ReaderWriter/PECOFFLinkingContext.h" +#include "../ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" @@ -34,6 +36,7 @@ #include #include +#include #include #include #include @@ -1293,6 +1296,19 @@ bool WinLinkDriver::parse(int argc, const char *argv[], } } + if (!isReadingDirectiveSection) { + std::unique_ptr node(new SimpleFileNode("")); + pecoff::ExportedSymbolRenameFile *renameFile = + new pecoff::ExportedSymbolRenameFile(ctx); + node->appendInputFile(std::unique_ptr(renameFile)); + ctx.getLibraryGroup()->addFile(std::move(node)); + std::function observer = [=](File *file) { + if (auto *archive = dyn_cast(file)) + renameFile->addResolvableSymbols(archive); + }; + ctx.getInputGraph().registerObserver(observer); + } + // Validate the combination of options used. return ctx.validate(diag); } diff --git a/lld/lib/ReaderWriter/FileArchive.cpp b/lld/lib/ReaderWriter/FileArchive.cpp index fc0dc6d3e425..6902bb0ec4f8 100644 --- a/lld/lib/ReaderWriter/FileArchive.cpp +++ b/lld/lib/ReaderWriter/FileArchive.cpp @@ -97,6 +97,16 @@ public: return _absoluteAtoms; } + /// Returns a set of all defined symbols in the archive. + std::set getDefinedSymbols() const override { + std::set ret; + for (const auto &e : _symbolMemberMap) { + StringRef sym = e.first; + ret.insert(sym); + } + return ret; + } + protected: error_code instantiateMember(Archive::child_iterator member, diff --git a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h index 5ff8bc647bde..e24d86dfa7e5 100644 --- a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h +++ b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h @@ -13,6 +13,9 @@ #include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "lld/ReaderWriter/Simple.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Debug.h" + +#include namespace lld { namespace pecoff { @@ -86,6 +89,18 @@ private: atom_collection_vector _absoluteAtoms; }; +class SymbolRenameFile : public SimpleFile { +public: + SymbolRenameFile(StringRef from, StringRef to) + : SimpleFile(""), _to(*this, to), _from(*this, from, &_to) { + addAtom(_from); + }; + +private: + COFFUndefinedAtom _to; + COFFUndefinedAtom _from; +}; + } // anonymous namespace // A virtual file containing absolute symbol __ImageBase. __ImageBase (or @@ -141,5 +156,51 @@ private: mutable llvm::BumpPtrAllocator _alloc; }; +class ExportedSymbolRenameFile : public VirtualArchiveLibraryFile { +public: + ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx) + : VirtualArchiveLibraryFile("") { + for (const PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) + _exportedSyms.insert(desc.name); + } + + void addResolvableSymbols(ArchiveLibraryFile *archive) { + std::lock_guard lock(_mutex); + if (_seen.count(archive) > 0) + return; + _seen.insert(archive); + for (const std::string &sym : archive->getDefinedSymbols()) + _resolvableSyms.insert(sym); + } + + const File *find(StringRef sym, bool dataSymbolOnly) const override { + if (_exportedSyms.count(sym) == 0) + return nullptr; + std::string expsym = sym; + expsym.append("@"); + auto it = _resolvableSyms.lower_bound(expsym); + for (auto e = _resolvableSyms.end(); it != e; ++it) { + if (!StringRef(*it).startswith(expsym)) + return nullptr; + if (it->size() == expsym.size()) + continue; + StringRef suffix = it->substr(expsym.size()); + bool digitSuffix = + suffix.find_first_not_of("0123456789") == StringRef::npos; + if (digitSuffix) { + return new (_alloc) SymbolRenameFile(sym, *it); + } + } + return nullptr; + } + +private: + std::set _exportedSyms; + std::set _resolvableSyms; + std::set _seen; + mutable std::mutex _mutex; + mutable llvm::BumpPtrAllocator _alloc; +}; + } // end namespace pecoff } // end namespace lld