From 1d510428e8d110e9f1f4dcf3f2f0ea189948f330 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 12 Dec 2014 07:31:09 +0000 Subject: [PATCH] Separate file parsing from File's constructors. This is a second patch for InputGraph cleanup. Sorry about the size of the patch, but what I did in this patch is basically moving code from constructor to a new method, parse(), so the amount of new code is small. This has no change in functionality. We've discussed the issue that we have too many classes to represent a concept of "file". We have File subclasses that represent files read from disk. In addition to that, we have bunch of InputElement subclasses (that are part of InputGraph) that represent command line arguments for input file names. InputElement is a wrapper for File. InputElement has parseFile method. The method instantiates a File. The File's constructor reads a file from disk and parses that. Because parseFile method is called from multiple worker threads, file parsing is processed in parallel. In other words, one reason why we needed the wrapper classes is because a File would start reading a file as soon as it is instantiated. So, the reason why we have too many classes here is at least partly because of the design flaw of File class. Just like threads in a good threading library, we need to separate instantiation from "start" method, so that we can instantiate File objects when we need them (which should be very fast because it involves only one mmap() and no real file IO) and use them directly instead of the wrapper classes. Later, we call parse() on each file in parallel to let them do actual file IO. In this design, we can eliminate a reason to have the wrapper classes. In order to minimize the size of the patch, I didn't go so far as to replace the wrapper classes with File classes. The wrapper classes are still there. In this patch, we call parse() immediately after instantiating a File, so this really has no change in functionality. Eventually the call of parse() should be moved to Driver::link(). That'll be done in another patch. llvm-svn: 224102 --- lld/include/lld/Core/File.h | 21 +- .../lld/ReaderWriter/MachOLinkingContext.h | 1 + .../ReaderWriter/ELF/AArch64/AArch64ELFFile.h | 5 +- lld/lib/ReaderWriter/ELF/DynamicFile.h | 92 ++--- lld/lib/ReaderWriter/ELF/ELFFile.h | 10 +- .../ReaderWriter/ELF/Hexagon/HexagonELFFile.h | 5 +- lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h | 9 +- lld/lib/ReaderWriter/ELF/PPC/PPCELFFile.h | 11 +- lld/lib/ReaderWriter/ELF/X86/X86ELFFile.h | 5 +- .../ReaderWriter/ELF/X86_64/X86_64ELFFile.h | 5 +- lld/lib/ReaderWriter/FileArchive.cpp | 33 +- lld/lib/ReaderWriter/MachO/File.h | 49 ++- .../ReaderWriter/MachO/MachONormalizedFile.h | 10 + .../MachO/MachONormalizedFileBinaryReader.cpp | 47 ++- .../MachO/MachONormalizedFileToAtoms.cpp | 55 ++- lld/lib/ReaderWriter/Native/ReaderNative.cpp | 71 ++-- lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 331 +++++++++--------- .../PECOFF/ReaderImportHeader.cpp | 35 +- lld/lib/ReaderWriter/Reader.cpp | 14 +- .../ReaderWriter/YAML/ReaderWriterYAML.cpp | 1 + 20 files changed, 442 insertions(+), 368 deletions(-) diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h index 9fedd69f8235..321956b71478 100644 --- a/lld/include/lld/Core/File.h +++ b/lld/include/lld/Core/File.h @@ -16,6 +16,7 @@ #include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/UndefinedAtom.h" #include "lld/Core/range.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/ErrorHandling.h" #include #include @@ -153,9 +154,26 @@ public: /// all AbsoluteAtoms in this File. virtual const atom_collection &absolute() const = 0; + /// \brief Subclasses should override this method to parse the + /// memory buffer passed to this file's constructor. + virtual std::error_code doParse() { return std::error_code(); } + + /// \brief If a file is parsed using a different method than doParse(), + /// one must use this method to set the last error status, so that + /// doParse will not be called twice. Only YAML reader uses this + /// (because YAML reader does not read blobs but structured data). + void setLastError(std::error_code err) { _lastError = err; } + + std::error_code parse() { + if (!_lastError.hasValue()) + _lastError = doParse(); + return _lastError.getValue(); + } + protected: /// \brief only subclasses of File can be instantiated - File(StringRef p, Kind kind) : _path(p), _kind(kind), _ordinal(UINT64_MAX) {} + File(StringRef p, Kind kind) + : _path(p), _kind(kind), _ordinal(UINT64_MAX) {} /// \brief This is a convenience class for File subclasses which manage their /// atoms as a simple std::vector<>. @@ -211,6 +229,7 @@ protected: static atom_collection_empty _noUndefinedAtoms; static atom_collection_empty _noSharedLibraryAtoms; static atom_collection_empty _noAbsoluteAtoms; + llvm::Optional _lastError; mutable llvm::BumpPtrAllocator _allocator; private: diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h index ddc3af246572..ff248fe96145 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h @@ -26,6 +26,7 @@ namespace lld { namespace mach_o { class ArchHandler; class MachODylibFile; +class MachOFile; } class MachOLinkingContext : public LinkingContext { diff --git a/lld/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h b/lld/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h index 09da41d99e87..2f099dc91804 100644 --- a/lld/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h +++ b/lld/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h @@ -24,11 +24,8 @@ public: static ErrorOr> create(std::unique_ptr mb, bool atomizeStrings) { - std::unique_ptr> file( + return std::unique_ptr>( new AArch64ELFFile(std::move(mb), atomizeStrings)); - if (std::error_code ec = file->parse()) - return ec; - return std::move(file); } }; diff --git a/lld/lib/ReaderWriter/ELF/DynamicFile.h b/lld/lib/ReaderWriter/ELF/DynamicFile.h index 55b257e906eb..73211c7d3085 100644 --- a/lld/lib/ReaderWriter/ELF/DynamicFile.h +++ b/lld/lib/ReaderWriter/ELF/DynamicFile.h @@ -55,8 +55,51 @@ public: *this, name, _soname, sym->second._symbol); } + std::error_code doParse() override { + std::error_code ec; + _objFile.reset( + new llvm::object::ELFFile(_mb.release()->getBuffer(), ec)); + if (ec) + return ec; + + llvm::object::ELFFile &obj = *_objFile; + + _soname = obj.getLoadName(); + if (_soname.empty()) + _soname = llvm::sys::path::filename(path()); + + // Create a map from names to dynamic symbol table entries. + // TODO: This should use the object file's build in hash table instead if + // it exists. + for (auto i = obj.begin_dynamic_symbols(), e = obj.end_dynamic_symbols(); + i != e; ++i) { + auto name = obj.getSymbolName(i); + if ((ec = name.getError())) + return ec; + + // TODO: Add absolute symbols + if (i->st_shndx == llvm::ELF::SHN_ABS) + continue; + + if (i->st_shndx == llvm::ELF::SHN_UNDEF) { + if (!_useShlibUndefines) + continue; + // Create an undefined atom. + if (!name->empty()) { + auto *newAtom = new (_alloc) ELFUndefinedAtom(*this, *name, &*i); + _undefinedAtoms._atoms.push_back(newAtom); + } + continue; + } + _nameToSym[*name]._symbol = &*i; + } + return std::error_code(); + } + private: - DynamicFile(StringRef name) : SharedLibraryFile(name) {} + DynamicFile(std::unique_ptr mb, bool useShlibUndefines) + : SharedLibraryFile(mb->getBufferIdentifier()), + _mb(std::move(mb)), _useShlibUndefines(useShlibUndefines) {} mutable llvm::BumpPtrAllocator _alloc; std::unique_ptr> _objFile; @@ -73,6 +116,8 @@ private: const SharedLibraryAtom *_atom; }; + std::unique_ptr _mb; + bool _useShlibUndefines; mutable std::unordered_map _nameToSym; }; @@ -80,49 +125,8 @@ template ErrorOr>> DynamicFile::create(std::unique_ptr mb, bool useShlibUndefines) { - std::unique_ptr file(new DynamicFile(mb->getBufferIdentifier())); - - std::error_code ec; - file->_objFile.reset( - new llvm::object::ELFFile(mb.release()->getBuffer(), ec)); - - if (ec) - return ec; - - llvm::object::ELFFile &obj = *file->_objFile; - - file->_soname = obj.getLoadName(); - if (file->_soname.empty()) - file->_soname = llvm::sys::path::filename(file->path()); - - // Create a map from names to dynamic symbol table entries. - // TODO: This should use the object file's build in hash table instead if - // it exists. - for (auto i = obj.begin_dynamic_symbols(), e = obj.end_dynamic_symbols(); - i != e; ++i) { - auto name = obj.getSymbolName(i); - if ((ec = name.getError())) - return ec; - - // TODO: Add absolute symbols - if (i->st_shndx == llvm::ELF::SHN_ABS) - continue; - - if (i->st_shndx == llvm::ELF::SHN_UNDEF) { - if (!useShlibUndefines) - continue; - // Create an undefined atom. - if (!name->empty()) { - auto *newAtom = - new (file->_alloc) ELFUndefinedAtom(*file.get(), *name, &*i); - file->_undefinedAtoms._atoms.push_back(newAtom); - } - continue; - } - file->_nameToSym[*name]._symbol = &*i; - } - - return std::move(file); + return std::unique_ptr( + new DynamicFile(std::move(mb), useShlibUndefines)); } } // end namespace elf diff --git a/lld/lib/ReaderWriter/ELF/ELFFile.h b/lld/lib/ReaderWriter/ELF/ELFFile.h index b1fc88619431..8ca4c2de7f12 100644 --- a/lld/lib/ReaderWriter/ELF/ELFFile.h +++ b/lld/lib/ReaderWriter/ELF/ELFFile.h @@ -122,7 +122,7 @@ public: : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)), _ordinal(0), _doStringsMerge(atomizeStrings) {} - virtual std::error_code parse(); + virtual std::error_code doParse() override; static ErrorOr> create(std::unique_ptr mb, bool atomizeStrings); @@ -417,19 +417,15 @@ public: template ErrorOr>> ELFFile::create(std::unique_ptr mb, bool atomizeStrings) { - std::error_code ec; std::unique_ptr> file( new ELFFile(std::move(mb), atomizeStrings)); - if (std::error_code ec = file->parse()) - return ec; return std::move(file); } template -std::error_code ELFFile::parse() { +std::error_code ELFFile::doParse() { std::error_code ec; - _objFile.reset( - new llvm::object::ELFFile(_mb.release()->getBuffer(), ec)); + _objFile.reset(new llvm::object::ELFFile(_mb.release()->getBuffer(), ec)); if (ec) return ec; diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h index e892a206297e..03bfe7fdddec 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h @@ -119,11 +119,8 @@ public: static ErrorOr> create(std::unique_ptr mb, bool atomizeStrings) { - std::unique_ptr> file( + return std::unique_ptr>( new HexagonELFFile(std::move(mb), atomizeStrings)); - if (std::error_code ec = file->parse()) - return ec; - return std::move(file); } virtual bool isCommonSymbol(const Elf_Sym *symbol) const { diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h index 6526b0307ad6..dd874f755fc7 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h @@ -85,11 +85,8 @@ public: static ErrorOr> create(std::unique_ptr mb, bool atomizeStrings) { - std::unique_ptr> file( + return std::unique_ptr>( new MipsELFFile(std::move(mb), atomizeStrings)); - if (std::error_code ec = file->parse()) - return ec; - return std::move(file); } bool isPIC() const { @@ -103,8 +100,8 @@ public: uint64_t getTPOffset() const { return *_tpOff; } uint64_t getDTPOffset() const { return *_dtpOff; } - std::error_code parse() override { - if (std::error_code ec = ELFFile::parse()) + std::error_code doParse() override { + if (std::error_code ec = ELFFile::doParse()) return ec; // Retrieve some auxiliary data like GP value, TLS section address etc // from the object file. diff --git a/lld/lib/ReaderWriter/ELF/PPC/PPCELFFile.h b/lld/lib/ReaderWriter/ELF/PPC/PPCELFFile.h index dd97b9a65e3d..bbcd49eb9aef 100644 --- a/lld/lib/ReaderWriter/ELF/PPC/PPCELFFile.h +++ b/lld/lib/ReaderWriter/ELF/PPC/PPCELFFile.h @@ -19,11 +19,14 @@ class PPCLinkingContext; template class PPCELFFile : public ELFFile { public: - PPCELFFile(StringRef name) : ELFFile(name) {} + PPCELFFile(std::unique_ptr mb, bool atomizeStrings) + : ELFFile(std::move(mb), atomizeStrings) {} - PPCELFFile(std::unique_ptr mb, bool atomizeStrings, - TargetHandlerBase *handler, std::error_code &ec) - : ELFFile(std::move(mb), atomizeStrings, handler, ec) {} + static ErrorOr> + create(std::unique_ptr mb, bool atomizeStrings) { + return std::unique_ptr>( + new PPCELFFile(std::move(mb), atomizeStrings)); + } }; template class PPCDynamicFile : public DynamicFile { diff --git a/lld/lib/ReaderWriter/ELF/X86/X86ELFFile.h b/lld/lib/ReaderWriter/ELF/X86/X86ELFFile.h index 516e9a204ad3..cee2509e796c 100644 --- a/lld/lib/ReaderWriter/ELF/X86/X86ELFFile.h +++ b/lld/lib/ReaderWriter/ELF/X86/X86ELFFile.h @@ -24,11 +24,8 @@ public: static ErrorOr> create(std::unique_ptr mb, bool atomizeStrings) { - std::unique_ptr> file( + return std::unique_ptr>( new X86ELFFile(std::move(mb), atomizeStrings)); - if (std::error_code ec = file->parse()) - return ec; - return std::move(file); } }; diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h index 24854e580461..bf1721c8ae3c 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h @@ -24,11 +24,8 @@ public: static ErrorOr> create(std::unique_ptr mb, bool atomizeStrings) { - std::unique_ptr> file( + return std::unique_ptr>( new X86_64ELFFile(std::move(mb), atomizeStrings)); - if (std::error_code ec = file->parse()) - return ec; - return std::move(file); } }; diff --git a/lld/lib/ReaderWriter/FileArchive.cpp b/lld/lib/ReaderWriter/FileArchive.cpp index a76399e57d0e..20a9a1c0b884 100644 --- a/lld/lib/ReaderWriter/FileArchive.cpp +++ b/lld/lib/ReaderWriter/FileArchive.cpp @@ -33,12 +33,22 @@ namespace { /// \brief The FileArchive class represents an Archive Library file class FileArchive : public lld::ArchiveLibraryFile { public: - FileArchive(const Registry ®istry, Archive *archive, StringRef path, - bool isWholeArchive, bool logLoading) - : ArchiveLibraryFile(path), _registry(registry), - _archive(std::move(archive)), _isWholeArchive(isWholeArchive), + FileArchive(std::unique_ptr &mb, const Registry ®, + StringRef path, bool logLoading) + : ArchiveLibraryFile(path), _mb(mb), _registry(reg), _logLoading(logLoading) {} + std::error_code doParse() override { + // Make Archive object which will be owned by FileArchive object. + std::error_code ec; + _archive.reset(new Archive(_mb->getMemBufferRef(), ec)); + if (ec) + return ec; + if ((ec = buildTableOfContents())) + return ec; + return std::error_code(); + } + virtual ~FileArchive() {} /// \brief Check if any member of the archive contains an Atom with the @@ -204,6 +214,7 @@ private: typedef std::unordered_map MemberMap; typedef std::set InstantiatedSet; + std::unique_ptr &_mb; const Registry &_registry; std::unique_ptr _archive; mutable MemberMap _symbolMemberMap; @@ -229,20 +240,8 @@ public: std::error_code parseFile(std::unique_ptr &mb, const Registry ®, std::vector> &result) const override { - MemoryBuffer &buff = *mb; - // Make Archive object which will be owned by FileArchive object. - std::error_code ec; - Archive *archive = new Archive(mb->getMemBufferRef(), ec); - if (ec) - return ec; - StringRef path = buff.getBufferIdentifier(); - // Construct FileArchive object. std::unique_ptr file( - new FileArchive(reg, archive, path, false, _logLoading)); - ec = file->buildTableOfContents(); - if (ec) - return ec; - + new FileArchive(mb, reg, mb->getBufferIdentifier(), _logLoading)); result.push_back(std::move(file)); return std::error_code(); } diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index 9f3979b7863e..8d9d4517b761 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -24,6 +24,9 @@ using lld::mach_o::normalized::Section; class MachOFile : public SimpleFile { public: + MachOFile(MemoryBuffer *mb, MachOLinkingContext *ctx) + : SimpleFile(mb->getBufferIdentifier()), _mb(mb), _ctx(ctx) {} + MachOFile(StringRef path) : SimpleFile(path) {} void addDefinedAtom(StringRef name, Atom::Scope scope, @@ -172,6 +175,19 @@ public: visitor(offAndAtom.atom, offAndAtom.offset); } + std::error_code doParse() override { + // Convert binary file to normalized mach-o. + std::unique_ptrmb(_mb); + auto normFile = normalized::readBinary(mb, _ctx->arch()); + mb.release(); + if (std::error_code ec = normFile.getError()) + return ec; + // Convert normalized mach-o to atoms. + if (std::error_code ec = normalized::normalizedObjectToAtoms( + this, **normFile, false)) + return ec; + return std::error_code(); + } private: struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; }; @@ -190,17 +206,18 @@ private: std::vector> SectionToAtoms; typedef llvm::StringMap NameToAtom; + MemoryBuffer *_mb; + MachOLinkingContext *_ctx; SectionToAtoms _sectionAtoms; NameToAtom _undefAtoms; }; class MachODylibFile : public SharedLibraryFile { public: - MachODylibFile(StringRef path, StringRef installName, uint32_t compatVersion, - uint32_t currentVersion) - : SharedLibraryFile(path), _installName(installName), - _currentVersion(currentVersion), _compatVersion(compatVersion) { - } + MachODylibFile(MemoryBuffer *mb, MachOLinkingContext *ctx) + : SharedLibraryFile(mb->getBufferIdentifier()), _mb(mb), _ctx(ctx) {} + + MachODylibFile(StringRef path) : SharedLibraryFile(path) {} const SharedLibraryAtom *exports(StringRef name, bool isData) const override { // Pass down _installName so that if this requested symbol @@ -241,11 +258,13 @@ public: } StringRef installName() { return _installName; } - uint32_t currentVersion() { return _currentVersion; } - uint32_t compatVersion() { return _compatVersion; } + void setInstallName(StringRef name) { _installName = name; } + void setCompatVersion(uint32_t version) { _compatVersion = version; } + void setCurrentVersion(uint32_t version) { _currentVersion = version; } + typedef std::function FindDylib; void loadReExportedDylibs(FindDylib find) { @@ -254,6 +273,20 @@ public: } } + std::error_code doParse() override { + // Convert binary file to normalized mach-o. + std::unique_ptrmb(_mb); + auto normFile = normalized::readBinary(mb, _ctx->arch()); + mb.release(); + if (std::error_code ec = normFile.getError()) + return ec; + // Convert normalized mach-o to atoms. + if (std::error_code ec = normalized::normalizedDylibToAtoms( + this, **normFile, false)) + return ec; + return std::error_code(); + } + private: const SharedLibraryAtom *exports(StringRef name, StringRef installName) const { @@ -295,6 +328,8 @@ private: bool weakDef; }; + MemoryBuffer *_mb; + MachOLinkingContext *_ctx; StringRef _installName; uint32_t _currentVersion; uint32_t _compatVersion; diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h index 64b8231eb2b1..70bcde2dea22 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -285,6 +285,16 @@ readYaml(std::unique_ptr &mb); /// Writes a yaml encoded mach-o files given an in-memory normalized view. std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out); +std::error_code +normalizedObjectToAtoms(MachOFile *file, + const NormalizedFile &normalizedFile, + bool copyRefs); + +std::error_code +normalizedDylibToAtoms(MachODylibFile *file, + const NormalizedFile &normalizedFile, + bool copyRefs); + /// Takes in-memory normalized dylib or object and parses it into lld::File ErrorOr> normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path, diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index a05fa7503264..0b3f76c19cbc 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -505,14 +505,39 @@ readBinary(std::unique_ptr &mb, return std::move(f); } -class MachOReader : public Reader { +class MachOObjectReader : public Reader { public: - MachOReader(MachOLinkingContext &ctx) : _ctx(ctx) {} + MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {} bool canParse(file_magic magic, StringRef ext, const MemoryBuffer &mb) const override { switch (magic) { case llvm::sys::fs::file_magic::macho_object: + return (mb.getBufferSize() > 32); + default: + return false; + } + } + + std::error_code + parseFile(std::unique_ptr &mb, const Registry ®istry, + std::vector> &result) const override { + auto *file = new MachOFile(mb.get(), &_ctx); + result.push_back(std::unique_ptr(file)); + return std::error_code(); + } + +private: + MachOLinkingContext &_ctx; +}; + +class MachODylibReader : public Reader { +public: + MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {} + + bool canParse(file_magic magic, StringRef ext, + const MemoryBuffer &mb) const override { + switch (magic) { case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib: case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: return (mb.getBufferSize() > 32); @@ -524,30 +549,22 @@ public: std::error_code parseFile(std::unique_ptr &mb, const Registry ®istry, std::vector> &result) const override { - // Convert binary file to normalized mach-o. - auto normFile = readBinary(mb, _ctx.arch()); - if (std::error_code ec = normFile.getError()) - return ec; - // Convert normalized mach-o to atoms. - auto file = normalizedToAtoms(**normFile, mb->getBufferIdentifier(), false); - if (std::error_code ec = file.getError()) - return ec; - - result.push_back(std::move(*file)); - + auto *file = new MachODylibFile(mb.get(), &_ctx); + result.push_back(std::unique_ptr(file)); return std::error_code(); } + private: MachOLinkingContext &_ctx; }; - } // namespace normalized } // namespace mach_o void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) { MachOLinkingContext::Arch arch = ctx.arch(); - add(std::unique_ptr(new mach_o::normalized::MachOReader(ctx))); + add(std::unique_ptr(new mach_o::normalized::MachOObjectReader(ctx))); + add(std::unique_ptr(new mach_o::normalized::MachODylibReader(ctx))); addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(), ctx.archHandler().kindStrings()); add(std::unique_ptr( diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 7465fb2e6137..1c22ecf11270 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -712,9 +712,32 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, /// Converts normalized mach-o file into an lld::File and lld::Atoms. ErrorOr> -normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, - bool copyRefs) { +objectToAtoms(const NormalizedFile &normalizedFile, StringRef path, + bool copyRefs) { std::unique_ptr file(new MachOFile(path)); + if (std::error_code ec = normalizedObjectToAtoms( + file.get(), normalizedFile, copyRefs)) + return ec; + return std::unique_ptr(std::move(file)); +} + +ErrorOr> +dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path, + bool copyRefs) { + // Instantiate SharedLibraryFile object. + std::unique_ptr file(new MachODylibFile(path)); + normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs); + return std::unique_ptr(std::move(file)); +} + +} // anonymous namespace + +namespace normalized { + +std::error_code +normalizedObjectToAtoms(MachOFile *file, + const NormalizedFile &normalizedFile, + bool copyRefs) { bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0); // Create atoms from each section. @@ -811,18 +834,17 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, for (const DefinedAtom* defAtom : file->defined()) { reinterpret_cast(defAtom)->sortReferences(); } - - return std::unique_ptr(std::move(file)); + return std::error_code(); } -ErrorOr> -normalizedDylibToAtoms(const NormalizedFile &normalizedFile, StringRef path, +std::error_code +normalizedDylibToAtoms(MachODylibFile *file, + const NormalizedFile &normalizedFile, bool copyRefs) { - // Instantiate SharedLibraryFile object. - std::unique_ptr file( - new MachODylibFile(path, normalizedFile.installName, - normalizedFile.compatVersion, - normalizedFile.currentVersion)); + file->setInstallName(normalizedFile.installName); + file->setCompatVersion(normalizedFile.compatVersion); + file->setCurrentVersion(normalizedFile.currentVersion); + // Tell MachODylibFile object about all symbols it exports. if (!normalizedFile.exportInfo.empty()) { // If exports trie exists, use it instead of traditional symbol table. @@ -843,14 +865,9 @@ normalizedDylibToAtoms(const NormalizedFile &normalizedFile, StringRef path, if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB) file->addReExportedDylib(dep.path); } - - return std::unique_ptr(std::move(file)); + return std::error_code(); } -} // anonymous namespace - -namespace normalized { - void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType, StringRef &segmentName, StringRef §ionName, @@ -881,9 +898,9 @@ normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path, switch (normalizedFile.fileType) { case MH_DYLIB: case MH_DYLIB_STUB: - return normalizedDylibToAtoms(normalizedFile, path, copyRefs); + return dylibToAtoms(normalizedFile, path, copyRefs); case MH_OBJECT: - return normalizedObjectToAtoms(normalizedFile, path, copyRefs); + return objectToAtoms(normalizedFile, path, copyRefs); default: llvm_unreachable("unhandled MachO file type!"); } diff --git a/lld/lib/ReaderWriter/Native/ReaderNative.cpp b/lld/lib/ReaderWriter/Native/ReaderNative.cpp index 3c7846b1ae31..c29fc4543f21 100644 --- a/lld/lib/ReaderWriter/Native/ReaderNative.cpp +++ b/lld/lib/ReaderWriter/Native/ReaderNative.cpp @@ -259,14 +259,21 @@ private: // class File : public lld::File { public: + File(std::unique_ptr mb) + : lld::File(mb->getBufferIdentifier(), kindObject), + _mb(std::move(mb)), // Reader now takes ownership of buffer + _header(nullptr), _targetsTable(nullptr), _targetsTableCount(0), + _strings(nullptr), _stringsMaxOffset(0), _addends(nullptr), + _addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) { + _header = + reinterpret_cast(_mb->getBufferStart()); + } - /// Instantiates a File object from a native object file. Ownership - /// of the MemoryBuffer is transferred to the resulting File object. - static std::error_code make(std::unique_ptr mb, - std::vector> &result) { + /// Parses a File object from a native object file. + std::error_code doParse() override { const uint8_t *const base = - reinterpret_cast(mb->getBufferStart()); - StringRef path(mb->getBufferIdentifier()); + reinterpret_cast(_mb->getBufferStart()); + StringRef path(_mb->getBufferIdentifier()); const NativeFileHeader *const header = reinterpret_cast(base); const NativeChunk *const chunks = @@ -277,7 +284,7 @@ public: return make_error_code(NativeReaderError::unknown_file_format); // make sure mapped file contains all needed data - const size_t fileSize = mb->getBufferSize(); + const size_t fileSize = _mb->getBufferSize(); if (header->fileSize > fileSize) return make_error_code(NativeReaderError::file_too_short); @@ -286,9 +293,6 @@ public: << header->fileSize << " chunkCount=" << header->chunkCount << "\n"); - // instantiate NativeFile object and add values to it as found - std::unique_ptr file(new File(std::move(mb), path)); - // process each chunk for (uint32_t i = 0; i < header->chunkCount; ++i) { std::error_code ec; @@ -301,40 +305,40 @@ public: // process chunk, based on signature switch ( chunk->signature ) { case NCS_DefinedAtomsV1: - ec = file->processDefinedAtomsV1(base, chunk); + ec = processDefinedAtomsV1(base, chunk); break; case NCS_AttributesArrayV1: - ec = file->processAttributesV1(base, chunk); + ec = processAttributesV1(base, chunk); break; case NCS_UndefinedAtomsV1: - ec = file->processUndefinedAtomsV1(base, chunk); + ec = processUndefinedAtomsV1(base, chunk); break; case NCS_SharedLibraryAtomsV1: - ec = file->processSharedLibraryAtomsV1(base, chunk); + ec = processSharedLibraryAtomsV1(base, chunk); break; case NCS_AbsoluteAtomsV1: - ec = file->processAbsoluteAtomsV1(base, chunk); + ec = processAbsoluteAtomsV1(base, chunk); break; case NCS_AbsoluteAttributesV1: - ec = file->processAbsoluteAttributesV1(base, chunk); + ec = processAbsoluteAttributesV1(base, chunk); break; case NCS_ReferencesArrayV1: - ec = file->processReferencesV1(base, chunk); + ec = processReferencesV1(base, chunk); break; case NCS_ReferencesArrayV2: - ec = file->processReferencesV2(base, chunk); + ec = processReferencesV2(base, chunk); break; case NCS_TargetsTable: - ec = file->processTargetsTable(base, chunk); + ec = processTargetsTable(base, chunk); break; case NCS_AddendsTable: - ec = file->processAddendsTable(base, chunk); + ec = processAddendsTable(base, chunk); break; case NCS_Content: - ec = file->processContent(base, chunk); + ec = processContent(base, chunk); break; case NCS_Strings: - ec = file->processStrings(base, chunk); + ec = processStrings(base, chunk); break; default: return make_error_code(NativeReaderError::unknown_chunk_type); @@ -347,7 +351,7 @@ public: DEBUG_WITH_TYPE("ReaderNative", { llvm::dbgs() << " ReaderNative DefinedAtoms:\n"; - for (const DefinedAtom *a : file->defined()) { + for (const DefinedAtom *a : defined()) { llvm::dbgs() << llvm::format(" 0x%09lX", a) << ", name=" << a->name() << ", size=" << a->size() << "\n"; @@ -359,12 +363,11 @@ public: } } }); - result.push_back(std::move(file)); return make_error_code(NativeReaderError::success); } virtual ~File() { - // _buffer is automatically deleted because of std::unique_ptr<> + // _mb is automatically deleted because of std::unique_ptr<> // All other ivar pointers are pointers into the MemoryBuffer, except // the _definedAtoms array which was allocated to contain an array @@ -785,17 +788,6 @@ private: _targetsTable[index] = newAtom; } - // private constructor, only called by make() - File(std::unique_ptr mb, StringRef path) - : lld::File(path, kindObject), - _buffer(std::move(mb)), // Reader now takes ownership of buffer - _header(nullptr), _targetsTable(nullptr), _targetsTableCount(0), - _strings(nullptr), _stringsMaxOffset(0), _addends(nullptr), - _addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) { - _header = - reinterpret_cast(_buffer->getBufferStart()); - } - template class AtomArray : public File::atom_collection { public: @@ -836,7 +828,7 @@ private: uint32_t elementCount; }; - std::unique_ptr _buffer; + std::unique_ptr _mb; const NativeFileHeader* _header; AtomArray _definedAtoms; AtomArray _undefinedAtoms; @@ -1009,9 +1001,12 @@ public: virtual std::error_code parseFile(std::unique_ptr &mb, const class Registry &, std::vector> &result) const override { - return lld::native::File::make(std::move(mb), result); + auto *file = new lld::native::File(std::move(mb)); + result.push_back(std::unique_ptr(file)); + return std::error_code(); } }; + } void Registry::addSupportNativeObjects() { diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp index 889cbbe6906d..6a908a74c249 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -55,6 +55,21 @@ using namespace lld; namespace { +class BumpPtrStringSaver : public llvm::cl::StringSaver { +public: + const char *SaveString(const char *str) override { + size_t len = strlen(str); + std::lock_guard lock(_allocMutex); + char *copy = _alloc.Allocate(len + 1); + memcpy(copy, str, len + 1); + return copy; + } + +private: + llvm::BumpPtrAllocator _alloc; + std::mutex _allocMutex; +}; + class FileCOFF : public File { private: typedef std::vector SymbolVectorT; @@ -66,10 +81,12 @@ private: public: typedef const std::map StringMap; - FileCOFF(std::unique_ptr mb, std::error_code &ec); + FileCOFF(std::unique_ptr mb, PECOFFLinkingContext &ctx) + : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)), + _compatibleWithSEH(false), _ordinal(0), + _machineType(llvm::COFF::MT_Invalid), _ctx(ctx) {} - std::error_code parse(); - StringRef getLinkerDirectives() const { return _directives; } + std::error_code doParse() override; bool isCompatibleWithSEH() const { return _compatibleWithSEH; } llvm::COFF::MachineTypes getMachineType() { return _machineType; } @@ -98,6 +115,11 @@ public: _undefinedAtoms._atoms.push_back(new (_alloc) COFFUndefinedAtom(*this, sym)); } + AliasAtom *createAlias(StringRef name, const DefinedAtom *target); + void createAlternateNameAtoms(); + std::error_code parseDirectiveSection( + StringRef directives, std::set *undefinedSymbols); + mutable llvm::BumpPtrAllocator _alloc; private: @@ -155,9 +177,6 @@ private: // The target type of the object. Reference::KindArch _referenceArch; - // The contents of .drectve section. - StringRef _directives; - // True if the object has "@feat.00" symbol. bool _compatibleWithSEH; @@ -192,21 +211,8 @@ private: uint64_t _ordinal; llvm::COFF::MachineTypes _machineType; -}; - -class BumpPtrStringSaver : public llvm::cl::StringSaver { -public: - const char *SaveString(const char *str) override { - size_t len = strlen(str); - std::lock_guard lock(_allocMutex); - char *copy = _alloc.Allocate(len + 1); - memcpy(copy, str, len + 1); - return copy; - } - -private: - llvm::BumpPtrAllocator _alloc; - std::mutex _allocMutex; + PECOFFLinkingContext &_ctx; + mutable BumpPtrStringSaver _stringSaver; }; // Converts the COFF symbol attribute to the LLD's atom attribute. @@ -290,33 +296,54 @@ DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) { } } -FileCOFF::FileCOFF(std::unique_ptr mb, std::error_code &ec) - : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)), - _compatibleWithSEH(false), _ordinal(0), - _machineType(llvm::COFF::MT_Invalid) { +StringRef getMachineName(llvm::COFF::MachineTypes Type) { + switch (Type) { + default: llvm_unreachable("unsupported machine type"); + case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT: + return "ARM"; + case llvm::COFF::IMAGE_FILE_MACHINE_I386: + return "X86"; + case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: + return "X64"; + } +} + +std::error_code FileCOFF::doParse() { auto binaryOrErr = llvm::object::createBinary(_mb->getMemBufferRef()); - if ((ec = binaryOrErr.getError())) - return; + if (std::error_code ec = binaryOrErr.getError()) + return ec; std::unique_ptr bin = std::move(binaryOrErr.get()); _obj.reset(dyn_cast(bin.get())); - if (!_obj) { - ec = make_error_code(llvm::object::object_error::invalid_file_type); - return; - } + if (!_obj) + return make_error_code(llvm::object::object_error::invalid_file_type); bin.release(); _machineType = static_cast(_obj->getMachine()); + if (getMachineType() != llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN && + getMachineType() != _ctx.getMachineType()) { + llvm::errs() << "module machine type '" + << getMachineName(getMachineType()) + << "' conflicts with target machine type '" + << getMachineName(_ctx.getMachineType()) << "'\n"; + return NativeReaderError::conflicting_target_machine; + } + + // The set to contain the symbols specified as arguments of + // /INCLUDE option. + std::set undefinedSymbols; + + // Interpret .drectve section if the section has contents. // Read .drectve section if exists. ArrayRef directives; - if ((ec = getSectionContents(".drectve", directives))) - return; + if (std::error_code ec = getSectionContents(".drectve", directives)) + return ec; if (!directives.empty()) - _directives = ArrayRefToString(directives); -} + if (std::error_code ec = parseDirectiveSection( + ArrayRefToString(directives), &undefinedSymbols)) + return ec; -std::error_code FileCOFF::parse() { if (std::error_code ec = getReferenceArch(_referenceArch)) return ec; @@ -329,7 +356,7 @@ std::error_code FileCOFF::parse() { createAbsoluteAtoms(symbols, _absoluteAtoms._atoms); if (std::error_code ec = - createUndefinedAtoms(symbols, _undefinedAtoms._atoms)) + createUndefinedAtoms(symbols, _undefinedAtoms._atoms)) return ec; if (std::error_code ec = createDefinedSymbols(symbols, _definedAtoms._atoms)) return ec; @@ -337,6 +364,37 @@ std::error_code FileCOFF::parse() { return ec; if (std::error_code ec = maybeCreateSXDataAtoms()) return ec; + + // Check for /SAFESEH. + if (_ctx.requireSEH() && !isCompatibleWithSEH()) { + llvm::errs() << "/SAFESEH is specified, but " + << _mb->getBufferIdentifier() + << " is not compatible with SEH.\n"; + return llvm::object::object_error::parse_failed; + } + + // Add /INCLUDE'ed symbols to the file as if they existed in the + // file as undefined symbols. + for (StringRef sym : undefinedSymbols) + addUndefinedSymbol(sym); + + // One can define alias symbols using /alternatename:= option. + // The mapping for /alternatename is in the context object. This helper + // function iterate over defined atoms and create alias atoms if needed. + createAlternateNameAtoms(); + + // Acquire the mutex to mutate _ctx. + std::lock_guard lock(_ctx.getMutex()); + + // In order to emit SEH table, all input files need to be compatible with + // SEH. Disable SEH if the file being read is not compatible. + if (!isCompatibleWithSEH()) + _ctx.setSafeSEH(false); + + if (_ctx.deadStrip()) + for (StringRef sym : undefinedSymbols) + _ctx.addDeadStripRoot(sym); + return std::error_code(); } @@ -804,6 +862,67 @@ std::error_code FileCOFF::getSectionContents(StringRef sectionName, return std::error_code(); } +AliasAtom *FileCOFF::createAlias(StringRef name, + const DefinedAtom *target) { + AliasAtom *alias = new (_alloc) AliasAtom(*this, name); + alias->addReference(Reference::KindNamespace::all, Reference::KindArch::all, + Reference::kindLayoutAfter, 0, target, 0); + alias->setMerge(DefinedAtom::mergeAsWeak); + if (target->contentType() == DefinedAtom::typeCode) + alias->setDeadStrip(DefinedAtom::deadStripNever); + return alias; +} + +void FileCOFF::createAlternateNameAtoms() { + std::vector aliases; + for (const DefinedAtom *atom : defined()) { + auto it = _ctx.alternateNames().find(atom->name()); + if (it != _ctx.alternateNames().end()) + aliases.push_back(createAlias(it->second, atom)); + } + for (AliasAtom *alias : aliases) + addDefinedAtom(alias); +} + +// Interpret the contents of .drectve section. If exists, the section contains +// a string containing command line options. The linker is expected to +// interpret the options as if they were given via the command line. +// +// The section mainly contains /defaultlib (-l in Unix), but can contain any +// options as long as they are valid. +std::error_code +FileCOFF::parseDirectiveSection(StringRef directives, + std::set *undefinedSymbols) { + DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n"); + + // Split the string into tokens, as the shell would do for argv. + SmallVector tokens; + tokens.push_back("link"); // argv[0] is the command name. Will be ignored. + llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens); + tokens.push_back(nullptr); + + // Calls the command line parser to interpret the token string as if they + // were given via the command line. + int argc = tokens.size() - 1; + const char **argv = &tokens[0]; + std::string errorMessage; + llvm::raw_string_ostream stream(errorMessage); + bool parseFailed = !WinLinkDriver::parse(argc, argv, _ctx, stream, + /*isDirective*/ true, + undefinedSymbols); + stream.flush(); + // Print error message if error. + if (parseFailed) { + auto msg = Twine("Failed to parse '") + directives + "'\n" + + "Reason: " + errorMessage; + return make_dynamic_error_code(msg); + } + if (!errorMessage.empty()) { + llvm::errs() << "lld warning: " << errorMessage << "\n"; + } + return std::error_code(); +} + /// Returns the target machine type of the current object file. std::error_code FileCOFF::getReferenceArch(Reference::KindArch &result) { switch (_obj->getMachine()) { @@ -945,18 +1064,6 @@ StringRef FileCOFF::ArrayRefToString(ArrayRef array) { return StringRef(*contents).trim(); } -StringRef getMachineName(llvm::COFF::MachineTypes Type) { - switch (Type) { - default: llvm_unreachable("unsupported machine type"); - case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT: - return "ARM"; - case llvm::COFF::IMAGE_FILE_MACHINE_I386: - return "X86"; - case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: - return "X64"; - } -} - class COFFObjectReader : public Reader { public: COFFObjectReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {} @@ -967,136 +1074,16 @@ public: } std::error_code - parseFile(std::unique_ptr &mb, const Registry ®istry, + parseFile(std::unique_ptr &mb, const Registry &, std::vector> &result) const override { // Parse the memory buffer as PECOFF file. - const char *mbName = mb->getBufferIdentifier(); - std::error_code ec; - std::unique_ptr file(new FileCOFF(std::move(mb), ec)); - if (ec) - return ec; - - if (file->getMachineType() != llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN && - file->getMachineType() != _ctx.getMachineType()) { - llvm::errs() << "module machine type '" - << getMachineName(file->getMachineType()) - << "' conflicts with target machine type '" - << getMachineName(_ctx.getMachineType()) << "'\n"; - return NativeReaderError::conflicting_target_machine; - } - - // The set to contain the symbols specified as arguments of - // /INCLUDE option. - std::set undefinedSymbols; - - // Interpret .drectve section if the section has contents. - StringRef directives = file->getLinkerDirectives(); - if (!directives.empty()) - if (std::error_code ec = handleDirectiveSection( - directives, &undefinedSymbols)) - return ec; - - if (std::error_code ec = file->parse()) - return ec; - - // Check for /SAFESEH. - if (_ctx.requireSEH() && !file->isCompatibleWithSEH()) { - llvm::errs() << "/SAFESEH is specified, but " << mbName - << " is not compatible with SEH.\n"; - return llvm::object::object_error::parse_failed; - } - - // Add /INCLUDE'ed symbols to the file as if they existed in the - // file as undefined symbols. - for (StringRef sym : undefinedSymbols) - file->addUndefinedSymbol(sym); - - // One can define alias symbols using /alternatename:= option. - // The mapping for /alternatename is in the context object. This helper - // function iterate over defined atoms and create alias atoms if needed. - createAlternateNameAtoms(*file); - - // Acquire the mutex to mutate _ctx. - std::lock_guard lock(_ctx.getMutex()); - - // In order to emit SEH table, all input files need to be compatible with - // SEH. Disable SEH if the file being read is not compatible. - if (!file->isCompatibleWithSEH()) - _ctx.setSafeSEH(false); - - if (_ctx.deadStrip()) - for (StringRef sym : undefinedSymbols) - _ctx.addDeadStripRoot(sym); - - result.push_back(std::move(file)); + auto *file = new FileCOFF(std::move(mb), _ctx); + result.push_back(std::unique_ptr(file)); return std::error_code(); } private: - // Interpret the contents of .drectve section. If exists, the section contains - // a string containing command line options. The linker is expected to - // interpret the options as if they were given via the command line. - // - // The section mainly contains /defaultlib (-l in Unix), but can contain any - // options as long as they are valid. - std::error_code handleDirectiveSection(StringRef directives, - std::set *undefinedSymbols) const { - DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n"); - - // Split the string into tokens, as the shell would do for argv. - SmallVector tokens; - tokens.push_back("link"); // argv[0] is the command name. Will be ignored. - llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens); - tokens.push_back(nullptr); - - // Calls the command line parser to interpret the token string as if they - // were given via the command line. - int argc = tokens.size() - 1; - const char **argv = &tokens[0]; - std::string errorMessage; - llvm::raw_string_ostream stream(errorMessage); - bool parseFailed = !WinLinkDriver::parse(argc, argv, _ctx, stream, - /*isDirective*/ true, - undefinedSymbols); - stream.flush(); - // Print error message if error. - if (parseFailed) { - auto msg = Twine("Failed to parse '") + directives + "'\n" - + "Reason: " + errorMessage; - return make_dynamic_error_code(msg); - } - if (!errorMessage.empty()) { - llvm::errs() << "lld warning: " << errorMessage << "\n"; - } - return std::error_code(); - } - - AliasAtom *createAlias(FileCOFF &file, StringRef name, - const DefinedAtom *target) const { - AliasAtom *alias = new (file._alloc) AliasAtom(file, name); - alias->addReference(Reference::KindNamespace::all, Reference::KindArch::all, - Reference::kindLayoutAfter, 0, target, 0); - alias->setMerge(DefinedAtom::mergeAsWeak); - if (target->contentType() == DefinedAtom::typeCode) - alias->setDeadStrip(DefinedAtom::deadStripNever); - return alias; - } - - // Iterates over defined atoms and create alias atoms if needed. - void createAlternateNameAtoms(FileCOFF &file) const { - std::vector aliases; - for (const DefinedAtom *atom : file.defined()) { - auto it = _ctx.alternateNames().find(atom->name()); - if (it != _ctx.alternateNames().end()) - aliases.push_back(createAlias(file, it->second, atom)); - } - for (AliasAtom *alias : aliases) { - file.addDefinedAtom(alias); - } - } - PECOFFLinkingContext &_ctx; - mutable BumpPtrStringSaver _stringSaver; }; using namespace llvm::COFF; diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp index 258887ac0bc4..e511ef2d40ed 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp @@ -197,31 +197,31 @@ private: class FileImportLibrary : public File { public: - FileImportLibrary(std::unique_ptr mb, std::error_code &ec, - MachineTypes machine) - : File(mb->getBufferIdentifier(), kindSharedLibrary), _machine(machine) { - const char *buf = mb->getBufferStart(); - const char *end = mb->getBufferEnd(); + FileImportLibrary(std::unique_ptr mb, MachineTypes machine) + : File(mb->getBufferIdentifier(), kindSharedLibrary), + _mb(std::move(mb)), _machine(machine) {} + + std::error_code doParse() override { + const char *buf = _mb->getBufferStart(); + const char *end = _mb->getBufferEnd(); // The size of the string that follows the header. uint32_t dataSize = *reinterpret_cast( - buf + offsetof(COFF::ImportHeader, SizeOfData)); + buf + offsetof(COFF::ImportHeader, SizeOfData)); // Check if the total size is valid. - if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize) { - ec = make_error_code(NativeReaderError::unknown_file_format); - return; - } + if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize) + return make_error_code(NativeReaderError::unknown_file_format); uint16_t hint = *reinterpret_cast( - buf + offsetof(COFF::ImportHeader, OrdinalHint)); + buf + offsetof(COFF::ImportHeader, OrdinalHint)); StringRef symbolName(buf + sizeof(COFF::ImportHeader)); StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1); // TypeInfo is a bitfield. The least significant 2 bits are import // type, followed by 3 bit import name type. uint16_t typeInfo = *reinterpret_cast( - buf + offsetof(COFF::ImportHeader, TypeInfo)); + buf + offsetof(COFF::ImportHeader, TypeInfo)); int type = typeInfo & 0x3; int nameType = (typeInfo >> 2) & 0x7; @@ -235,7 +235,7 @@ public: if (type == llvm::COFF::IMPORT_CODE) addFuncAtom(symbolName, dllName, dataAtom); - ec = std::error_code(); + return std::error_code(); } const atom_collection &defined() const override { @@ -309,6 +309,7 @@ private: return *str; } + std::unique_ptr _mb; MachineTypes _machine; }; @@ -326,12 +327,8 @@ public: std::error_code parseFile(std::unique_ptr &mb, const class Registry &, std::vector > &result) const override { - std::error_code ec; - auto file = std::unique_ptr( - new FileImportLibrary(std::move(mb), ec, _machine)); - if (ec) - return ec; - result.push_back(std::move(file)); + auto *file = new FileImportLibrary(std::move(mb), _machine); + result.push_back(std::unique_ptr(file)); return std::error_code(); } diff --git a/lld/lib/ReaderWriter/Reader.cpp b/lld/lib/ReaderWriter/Reader.cpp index f7077199c0ba..a730d0d216f9 100644 --- a/lld/lib/ReaderWriter/Reader.cpp +++ b/lld/lib/ReaderWriter/Reader.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "lld/Core/File.h" #include "lld/ReaderWriter/Reader.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Errc.h" @@ -38,9 +39,16 @@ Registry::parseFile(std::unique_ptr &mb, StringRef extension = llvm::sys::path::extension(mb->getBufferIdentifier()); // Ask each registered reader if it can handle this file type or extension. - for (const std::unique_ptr &reader : _readers) - if (reader->canParse(fileType, extension, *mb)) - return reader->parseFile(mb, *this, result); + for (const std::unique_ptr &reader : _readers) { + if (!reader->canParse(fileType, extension, *mb)) + continue; + if (std::error_code ec = reader->parseFile(mb, *this, result)) + return ec; + for (std::unique_ptr &file : result) + if (std::error_code ec = file->parse()) + return ec; + return std::error_code(); + } // No Reader could parse this file. return make_error_code(llvm::errc::executable_format_error); diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index f41f978d7c6f..3b03cdc4a41d 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -1351,6 +1351,7 @@ public: for (const File *file : createdFiles) { // Note: parseFile() should return vector of *const* File File *f = const_cast(file); + f->setLastError(std::error_code()); result.emplace_back(f); } return make_error_code(lld::YamlReaderError::success);