diff options
Diffstat (limited to 'lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp')
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 459 |
1 files changed, 242 insertions, 217 deletions
diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp index 95c1acf897a..bc5c7cc8f10 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -59,11 +59,13 @@ private: typedef std::map<const coff_section *, SymbolVectorT> SectionToSymbolsT; typedef std::map<const StringRef, Atom *> SymbolNameToAtomT; typedef std::map<const coff_section *, vector<COFFDefinedFileAtom *> > - SectionToAtomsT; + SectionToAtomsT; public: - FileCOFF(const PECOFFLinkingContext &context, - std::unique_ptr<MemoryBuffer> mb, error_code &ec); + typedef const std::map<std::string, std::string> StringMap; + + FileCOFF(std::unique_ptr<MemoryBuffer> mb, StringMap &altNames, + error_code &ec); virtual const atom_collection<DefinedAtom> &defined() const { return _definedAtoms; @@ -81,11 +83,10 @@ public: return _absoluteAtoms; } - virtual const LinkingContext &getLinkingContext() const { return _context; } - StringRef getLinkerDirectives() const { return _directives; } private: + error_code readSymbolTable(vector<const coff_symbol *> &result); void createAbsoluteAtoms(const SymbolVectorT &symbols, @@ -95,16 +96,19 @@ private: vector<const UndefinedAtom *> &result); error_code createDefinedSymbols(const SymbolVectorT &symbols, + StringMap &altNames, vector<const DefinedAtom *> &result); error_code cacheSectionAttributes(); error_code - AtomizeDefinedSymbolsInSection(const coff_section *section, - vector<const coff_symbol *> &symbols, - vector<COFFDefinedFileAtom *> &atoms); + AtomizeDefinedSymbolsInSection(const coff_section *section, + StringMap &altNames, + vector<const coff_symbol *> &symbols, + vector<COFFDefinedFileAtom *> &atoms); error_code AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols, + StringMap &altNames, vector<const DefinedAtom *> &definedAtoms); error_code findAtomAt(const coff_section *section, uint32_t targetAddress, @@ -153,10 +157,9 @@ private: // the section. std::map<const coff_section *, std::map<uint32_t, std::vector<COFFDefinedAtom *> > > - _definedAtomLocations; + _definedAtomLocations; mutable llvm::BumpPtrAllocator _alloc; - const PECOFFLinkingContext &_context; uint64_t _ordinal; }; @@ -173,34 +176,6 @@ private: llvm::BumpPtrAllocator _alloc; }; -class ReaderCOFF : public Reader { -public: - explicit ReaderCOFF(PECOFFLinkingContext &context) - : Reader(context), _PECOFFLinkingContext(context) {} - - error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const; - -private: - error_code handleDirectiveSection(StringRef directives) const; - - ErrorOr<std::string> - writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const; - - ErrorOr<std::string> - convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const; - - error_code convertAndParseResourceFile( - std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const; - - error_code parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const; - - PECOFFLinkingContext &_PECOFFLinkingContext; - mutable BumpPtrStringSaver _stringSaver; -}; - // Converts the COFF symbol attribute to the LLD's atom attribute. Atom::Scope getScope(const coff_symbol *symbol) { switch (symbol->StorageClass) { @@ -278,10 +253,9 @@ DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) { } } -FileCOFF::FileCOFF(const PECOFFLinkingContext &context, - std::unique_ptr<MemoryBuffer> mb, error_code &ec) - : File(mb->getBufferIdentifier(), kindObject), _context(context), - _ordinal(0) { +FileCOFF::FileCOFF(std::unique_ptr<MemoryBuffer> mb, StringMap &altNames, + error_code &ec) + : File(mb->getBufferIdentifier(), kindObject), _ordinal(0) { OwningPtr<llvm::object::Binary> bin; ec = llvm::object::createBinary(mb.release(), bin); if (ec) @@ -304,7 +278,7 @@ FileCOFF::FileCOFF(const PECOFFLinkingContext &context, createAbsoluteAtoms(symbols, _absoluteAtoms._atoms); if ((ec = createUndefinedAtoms(symbols, _undefinedAtoms._atoms))) return; - if ((ec = createDefinedSymbols(symbols, _definedAtoms._atoms))) + if ((ec = createDefinedSymbols(symbols, altNames, _definedAtoms._atoms))) return; if ((ec = addRelocationReferenceToAtoms())) @@ -427,6 +401,7 @@ FileCOFF::createUndefinedAtoms(const SymbolVectorT &symbols, /// the other two, because in order to create the atom for the defined symbol /// we need to know the adjacent symbols. error_code FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols, + StringMap &altNames, vector<const DefinedAtom *> &result) { // A defined atom can be merged if its section attribute allows its contents // to be merged. In COFF, it's not very easy to get the section attribute @@ -499,7 +474,7 @@ error_code FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols, } // Atomize the defined symbols. - if (error_code ec = AtomizeDefinedSymbols(definedSymbols, result)) + if (error_code ec = AtomizeDefinedSymbols(definedSymbols, altNames, result)) return ec; return error_code::success(); @@ -552,17 +527,19 @@ error_code FileCOFF::cacheSectionAttributes() { /// assumed to have been defined in the \p section. error_code FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section, + StringMap &altNames, vector<const coff_symbol *> &symbols, vector<COFFDefinedFileAtom *> &atoms) { - // Sort symbols by position. + // Sort symbols by position. std::stable_sort( symbols.begin(), symbols.end(), // For some reason MSVC fails to allow the lambda in this context with a // "illegal use of local type in type instantiation". MSVC is clearly // wrong here. Force a conversion to function pointer to work around. - static_cast<bool (*)(const coff_symbol *, const coff_symbol *)>([]( - const coff_symbol * a, - const coff_symbol * b)->bool { return a->Value < b->Value; })); + static_cast<bool(*)(const coff_symbol *, const coff_symbol *)>( + [](const coff_symbol * a, const coff_symbol * b)->bool { + return a->Value < b->Value; + })); StringRef sectionName; if (error_code ec = _obj->getSectionName(section, sectionName)) @@ -626,12 +603,10 @@ FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section, // if this is the last symbol, take up the remaining data. const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size() : secData.data() + (*(si + 1))->Value; - StringRef symbolName = _symbolName[*si]; - StringRef alias = _context.getAlternateName(symbolName); - - if (!alias.empty()) { + auto pos = altNames.find(_symbolName[*si]); + if (pos != altNames.end()) { auto *atom = new (_alloc) COFFDefinedAtom( - *this, alias, sectionName, getScope(*si), type, isComdat, perms, + *this, pos->second, sectionName, getScope(*si), type, isComdat, perms, DefinedAtom::mergeAsWeak, ArrayRef<uint8_t>(), _ordinal++); atoms.push_back(atom); _symbolAtom[*si] = atom; @@ -655,6 +630,7 @@ FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section, error_code FileCOFF::AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols, + StringMap &altNames, vector<const DefinedAtom *> &definedAtoms) { // For each section, make atoms for all the symbols defined in the // section, and append the atoms to the result objects. @@ -662,7 +638,8 @@ FileCOFF::AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols, const coff_section *section = i.first; vector<const coff_symbol *> &symbols = i.second; vector<COFFDefinedFileAtom *> atoms; - if (error_code ec = AtomizeDefinedSymbolsInSection(section, symbols, atoms)) + if (error_code ec = + AtomizeDefinedSymbolsInSection(section, altNames, symbols, atoms)) return ec; // Connect atoms with layout-before/layout-after edges. @@ -815,127 +792,6 @@ error_code FileCOFF::maybeReadLinkerDirectives() { return error_code::success(); } -error_code -ReaderCOFF::parseFile(std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const { - StringRef magic(mb->getBufferStart(), mb->getBufferSize()); - - // The input file should be a resource file, an archive file, a regular COFF - // file, or an import library member file. Try to parse in that order. If - // the input file does not start with a known magic, parseCOFFImportLibrary - // will return an error object. - llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(magic); - - if (fileType == llvm::sys::fs::file_magic::windows_resource) - return convertAndParseResourceFile(mb, result); - if (fileType == llvm::sys::fs::file_magic::coff_import_library) - return lld::pecoff::parseCOFFImportLibrary(_context, mb, result); - return parseCOFFFile(mb, result); -} - -// 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. -error_code ReaderCOFF::handleDirectiveSection(StringRef directives) const { - DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n"); - - // Split the string into tokens, as the shell would do for argv. - SmallVector<const char *, 16> 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, _PECOFFLinkingContext, - stream, /*isDirective*/ true); - stream.flush(); - - // Print error message if error. - if (parseFailed) { - llvm::errs() << "Failed to parse '" << directives << "'\n" - << "Reason: " << errorMessage; - return make_error_code(llvm::object::object_error::invalid_file_type); - } - if (!errorMessage.empty()) { - llvm::errs() << "lld warning: " << errorMessage << "\n"; - } - return error_code::success(); -} - -ErrorOr<std::string> -ReaderCOFF::writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const { - // Get a temporary file path for .res file. - SmallString<128> tempFilePath; - if (error_code ec = - llvm::sys::fs::createTemporaryFile("tmp", "res", tempFilePath)) - return ec; - - // Write the memory buffer contents to .res file, so that we can run - // cvtres.exe on it. - OwningPtr<llvm::FileOutputBuffer> buffer; - if (error_code ec = llvm::FileOutputBuffer::create( - tempFilePath.str(), mb->getBufferSize(), buffer)) - return ec; - memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize()); - if (error_code ec = buffer->commit()) - return ec; - - // Convert SmallString -> StringRef -> std::string. - return tempFilePath.str().str(); -} - -ErrorOr<std::string> -ReaderCOFF::convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const { - // Write the resource file to a temporary file. - ErrorOr<std::string> inFilePath = writeResToTemporaryFile(std::move(mb)); - if (!inFilePath) - return error_code(inFilePath); - llvm::FileRemover inFileRemover(*inFilePath); - - // Create an output file path. - SmallString<128> outFilePath; - if (error_code ec = - llvm::sys::fs::createTemporaryFile("tmp", "obj", outFilePath)) - return ec; - std::string outFileArg = ("/out:" + outFilePath).str(); - - // Construct CVTRES.EXE command line and execute it. - std::string program = "cvtres.exe"; - std::string programPath = llvm::sys::FindProgramByName(program); - if (programPath.empty()) { - llvm::errs() << "Unable to find " << program << " in PATH\n"; - return llvm::errc::broken_pipe; - } - std::vector<const char *> args; - args.push_back(programPath.c_str()); - args.push_back("/machine:x86"); - args.push_back("/readonly"); - args.push_back("/nologo"); - args.push_back(outFileArg.c_str()); - args.push_back(inFilePath->c_str()); - args.push_back(nullptr); - - DEBUG({ - for (const char **p = &args[0]; *p; ++p) - llvm::dbgs() << *p << " "; - llvm::dbgs() << "\n"; - }); - - if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) { - llvm::errs() << program << " failed\n"; - return llvm::errc::broken_pipe; - } - return outFilePath.str().str(); -} - // Convert .res file to .coff file and then parse it. Resource file is a file // containing various types of data, such as icons, translation texts, // etc. "cvtres.exe" command reads an RC file to create a COFF file which @@ -943,57 +799,226 @@ ReaderCOFF::convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const { // // The linker is not capable to handle RC files directly. Instead, it runs // cvtres.exe on RC files and then then link its outputs. -error_code ReaderCOFF::convertAndParseResourceFile( - std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const { - // Convert an RC to a COFF - ErrorOr<std::string> coffFilePath = convertResourceFileToCOFF(std::move(mb)); - if (!coffFilePath) - return error_code(coffFilePath); - llvm::FileRemover coffFileRemover(*coffFilePath); - - // Read and parse the COFF - OwningPtr<MemoryBuffer> opmb; - if (error_code ec = MemoryBuffer::getFile(*coffFilePath, opmb)) - return ec; - std::unique_ptr<MemoryBuffer> newmb(opmb.take()); - return parseCOFFFile(newmb, result); -} +class ResourceFileReader : public Reader { +public: + virtual bool canParse(file_magic magic, StringRef ext, + const MemoryBuffer &) const { + return (magic == llvm::sys::fs::file_magic::windows_resource); + } -error_code -ReaderCOFF::parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb, - std::vector<std::unique_ptr<File> > &result) const { - // Parse the memory buffer as PECOFF file. - error_code ec; - std::unique_ptr<FileCOFF> file( - new FileCOFF(_PECOFFLinkingContext, std::move(mb), ec)); - if (ec) - return ec; + virtual error_code + parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &, + std::vector<std::unique_ptr<File> > &result) const { + // Convert RC file to COFF + ErrorOr<std::string> coffPath = convertResourceFileToCOFF(std::move(mb)); + if (!coffPath) + return error_code(coffPath); + llvm::FileRemover coffFileRemover(*coffPath); + + // Read and parse the COFF + OwningPtr<MemoryBuffer> opmb; + if (error_code ec = MemoryBuffer::getFile(*coffPath, opmb)) + return ec; + std::unique_ptr<MemoryBuffer> newmb(opmb.take()); + error_code ec; + FileCOFF::StringMap emptyMap; + std::unique_ptr<FileCOFF> file( + new FileCOFF(std::move(newmb), emptyMap, ec)); + if (ec) + return ec; + result.push_back(std::move(file)); + return error_code::success(); + } + +private: + static ErrorOr<std::string> + writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) { + // Get a temporary file path for .res file. + SmallString<128> tempFilePath; + if (error_code ec = + llvm::sys::fs::createTemporaryFile("tmp", "res", tempFilePath)) + return ec; + + // Write the memory buffer contents to .res file, so that we can run + // cvtres.exe on it. + OwningPtr<llvm::FileOutputBuffer> buffer; + if (error_code ec = llvm::FileOutputBuffer::create( + tempFilePath.str(), mb->getBufferSize(), buffer)) + return ec; + memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize()); + if (error_code ec = buffer->commit()) + return ec; + + // Convert SmallString -> StringRef -> std::string. + return tempFilePath.str().str(); + } - DEBUG({ - llvm::dbgs() << "Defined atoms:\n"; - for (const auto &atom : file->defined()) { - llvm::dbgs() << " " << atom->name() << "\n"; - for (const Reference *ref : *atom) - llvm::dbgs() << " @" << ref->offsetInAtom() << " -> " - << ref->target()->name() << "\n"; + static ErrorOr<std::string> + convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) { + // Write the resource file to a temporary file. + ErrorOr<std::string> inFilePath = writeResToTemporaryFile(std::move(mb)); + if (!inFilePath) + return error_code(inFilePath); + llvm::FileRemover inFileRemover(*inFilePath); + + // Create an output file path. + SmallString<128> outFilePath; + if (error_code ec = + llvm::sys::fs::createTemporaryFile("tmp", "obj", outFilePath)) + return ec; + std::string outFileArg = ("/out:" + outFilePath).str(); + + // Construct CVTRES.EXE command line and execute it. + std::string program = "cvtres.exe"; + std::string programPath = llvm::sys::FindProgramByName(program); + if (programPath.empty()) { + llvm::errs() << "Unable to find " << program << " in PATH\n"; + return llvm::errc::broken_pipe; + } + std::vector<const char *> args; + args.push_back(programPath.c_str()); + args.push_back("/machine:x86"); + args.push_back("/readonly"); + args.push_back("/nologo"); + args.push_back(outFileArg.c_str()); + args.push_back(inFilePath->c_str()); + args.push_back(nullptr); + + DEBUG({ + for (const char **p = &args[0]; *p; ++p) + llvm::dbgs() << *p << " "; + llvm::dbgs() << "\n"; + }); + + if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) { + llvm::errs() << program << " failed\n"; + return llvm::errc::broken_pipe; } - }); + return outFilePath.str().str(); + } +}; + +class COFFObjectReader : public Reader { +public: + COFFObjectReader(PECOFFLinkingContext &ctx) : _context(ctx) {} + + virtual bool canParse(file_magic magic, StringRef ext, + const MemoryBuffer &) const { + return (magic == llvm::sys::fs::file_magic::coff_object); + } - // Interpret .drectve section if the section has contents. - StringRef directives = file->getLinkerDirectives(); - if (!directives.empty()) - if (error_code ec = handleDirectiveSection(directives)) + virtual error_code + parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry ®istry, + std::vector<std::unique_ptr<File> > &result) const { + // Parse the memory buffer as PECOFF file. + error_code ec; + std::unique_ptr<FileCOFF> file( + new FileCOFF(std::move(mb), _context.alternateNames(), ec)); + if (ec) return ec; - result.push_back(std::move(file)); - return error_code::success(); -} + // Interpret .drectve section if the section has contents. + StringRef directives = file->getLinkerDirectives(); + if (!directives.empty()) + if (error_code ec2 = handleDirectiveSection(registry, directives)) + return ec2; + + result.push_back(std::move(file)); + return error_code::success(); + } + +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. + error_code handleDirectiveSection(const Registry ®istry, + StringRef directives) const { + DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n"); + + // Split the string into tokens, as the shell would do for argv. + SmallVector<const char *, 16> 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, _context, stream, + /*isDirective*/ true); + stream.flush(); + // Print error message if error. + if (parseFailed) { + llvm::errs() << "Failed to parse '" << directives << "'\n" + << "Reason: " << errorMessage; + return make_error_code(llvm::object::object_error::invalid_file_type); + } + if (!errorMessage.empty()) { + llvm::errs() << "lld warning: " << errorMessage << "\n"; + } + return error_code::success(); + } + + PECOFFLinkingContext &_context; + mutable BumpPtrStringSaver _stringSaver; +}; + +using namespace llvm::COFF; + +const Registry::KindStrings kindStringsI386[] = { + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_ABSOLUTE), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR16), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL16), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32NB), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SEG12), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECTION), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_TOKEN), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL7), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL32), LLD_KIND_STRING_END +}; + +const Registry::KindStrings kindStringsAMD64[] = { + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ABSOLUTE), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR64), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32NB), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_1), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_2), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_3), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_4), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_5), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECTION), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL7), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_TOKEN), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SREL32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_PAIR), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SSPAN32), LLD_KIND_STRING_END +}; } // end namespace anonymous namespace lld { -std::unique_ptr<Reader> createReaderPECOFF(PECOFFLinkingContext &context) { - return std::unique_ptr<Reader>(new ReaderCOFF(context)); + +void Registry::addSupportCOFFObjects(PECOFFLinkingContext &ctx) { + add(std::unique_ptr<Reader>(new COFFObjectReader(ctx))); + addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86, + kindStringsI386); + addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86_64, + kindStringsAMD64); } + +void Registry::addSupportWindowsResourceFiles() { + add(std::unique_ptr<Reader>(new ResourceFileReader())); +} + } |