diff options
Diffstat (limited to 'lld/lib/ReaderWriter/PECOFF')
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/Atoms.h | 19 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h | 2 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp | 42 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 459 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp | 54 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp | 21 |
6 files changed, 305 insertions, 292 deletions
diff --git a/lld/lib/ReaderWriter/PECOFF/Atoms.h b/lld/lib/ReaderWriter/PECOFF/Atoms.h index 50c983d9261..2057dd5bb42 100644 --- a/lld/lib/ReaderWriter/PECOFF/Atoms.h +++ b/lld/lib/ReaderWriter/PECOFF/Atoms.h @@ -27,13 +27,11 @@ class COFFDefinedAtom; /// to be fixed up so that the address points to atom Y's address. class COFFReference LLVM_FINAL : public Reference { public: - explicit COFFReference(Kind kind) : _target(nullptr), _offsetInAtom(0) { - _kind = kind; - } - - COFFReference(const Atom *target, uint32_t offsetInAtom, uint16_t relocType) - : _target(target), _offsetInAtom(offsetInAtom) { - setKind(static_cast<Reference::Kind>(relocType)); + COFFReference(const Atom *target, uint32_t offsetInAtom, uint16_t relocType, + Reference::KindNamespace ns=Reference::KindNamespace::COFF, + Reference::KindArch arch=Reference::KindArch::x86) + : Reference(ns, arch, relocType), + _target(target), _offsetInAtom(offsetInAtom) { } virtual const Atom *target() const { return _target; } @@ -326,7 +324,7 @@ private: class VirtualFile : public SimpleFile { public: VirtualFile(const LinkingContext &ctx) - : SimpleFile(ctx, "<virtual-file>"), _nextOrdinal(0) { + : SimpleFile("<virtual-file>"), _nextOrdinal(0) { setOrdinal(ctx.getNextOrdinalAndIncrement()); } @@ -343,8 +341,9 @@ private: //===----------------------------------------------------------------------===// template <typename T, typename U> -void addLayoutEdge(T *a, U *b, lld::Reference::Kind kind) { - auto ref = new COFFReference(kind); +void addLayoutEdge(T *a, U *b, uint32_t which) { + auto ref = new COFFReference(nullptr, 0, which, Reference::KindNamespace::all, + Reference::KindArch::all); ref->setTarget(b); a->addReference(std::unique_ptr<COFFReference>(ref)); } diff --git a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h index 06b453c816a..248aaabbef4 100644 --- a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h +++ b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h @@ -21,7 +21,7 @@ namespace pecoff { class LinkerGeneratedSymbolFile : public SimpleFile { public: LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx) - : SimpleFile(ctx, "<linker-internal-file>"), + : SimpleFile("<linker-internal-file>"), _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"), Atom::scopeGlobal, ctx.getBaseAddress()) { addAtom(_imageBaseAtom); diff --git a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp index 2560e45ad68..251812e386b 100644 --- a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp @@ -78,7 +78,6 @@ bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) { return false; } - _reader = createReaderPECOFF(*this); _writer = createWriterPECOFF(*this); return true; } @@ -87,7 +86,7 @@ std::unique_ptr<File> PECOFFLinkingContext::createEntrySymbolFile() const { if (entrySymbolName().empty()) return nullptr; std::unique_ptr<SimpleFile> entryFile( - new SimpleFile(*this, "command line option /entry")); + new SimpleFile("command line option /entry")); entryFile->addAtom( *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName()))); return std::move(entryFile); @@ -97,7 +96,7 @@ std::unique_ptr<File> PECOFFLinkingContext::createUndefinedSymbolFile() const { if (_initialUndefinedSymbols.empty()) return nullptr; std::unique_ptr<SimpleFile> undefinedSymFile( - new SimpleFile(*this, "command line option /c (or) /include")); + new SimpleFile("command line option /c (or) /include")); for (auto undefSymStr : _initialUndefinedSymbols) undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( *undefinedSymFile, undefSymStr))); @@ -208,40 +207,6 @@ StringRef PECOFFLinkingContext::decorateSymbol(StringRef name) const { Writer &PECOFFLinkingContext::writer() const { return *_writer; } -ErrorOr<Reference::Kind> -PECOFFLinkingContext::relocKindFromString(StringRef str) const { -#define LLD_CASE(name) .Case(#name, llvm::COFF::name) - int32_t ret = llvm::StringSwitch<int32_t>(str) - LLD_CASE(IMAGE_REL_I386_ABSOLUTE) - LLD_CASE(IMAGE_REL_I386_DIR32) - LLD_CASE(IMAGE_REL_I386_DIR32NB) - LLD_CASE(IMAGE_REL_I386_SECTION) - LLD_CASE(IMAGE_REL_I386_SECREL) - LLD_CASE(IMAGE_REL_I386_REL32) - .Default(-1); -#undef LLD_CASE - if (ret == -1) - return make_error_code(YamlReaderError::illegal_value); - return ret; -} - -ErrorOr<std::string> -PECOFFLinkingContext::stringFromRelocKind(Reference::Kind kind) const { - switch (kind) { -#define LLD_CASE(name) \ - case llvm::COFF::name: \ - return std::string(#name); - - LLD_CASE(IMAGE_REL_I386_ABSOLUTE) - LLD_CASE(IMAGE_REL_I386_DIR32) - LLD_CASE(IMAGE_REL_I386_DIR32NB) - LLD_CASE(IMAGE_REL_I386_SECTION) - LLD_CASE(IMAGE_REL_I386_SECREL) - LLD_CASE(IMAGE_REL_I386_REL32) -#undef LLD_CASE - } - return make_error_code(YamlReaderError::illegal_value); -} void PECOFFLinkingContext::setSectionSetMask(StringRef sectionName, uint32_t newFlags) { @@ -270,7 +235,8 @@ uint32_t PECOFFLinkingContext::getSectionAttributes(StringRef sectionName, uint32_t clearMask = (ci == _sectionClearMask.end()) ? 0 : ci->second; return (flags | setMask) & ~clearMask; } - + + void PECOFFLinkingContext::addPasses(PassManager &pm) { pm.add(std::unique_ptr<Pass>(new pecoff::SetSubsystemPass(*this))); pm.add(std::unique_ptr<Pass>(new pecoff::EdataPass(*this))); 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())); +} + } diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp index c16f53977a0..a6ad676546a 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp @@ -125,6 +125,7 @@ #include "lld/Core/File.h" #include "lld/Core/Error.h" #include "lld/Core/SharedLibraryAtom.h" +#include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/COFF.h" @@ -143,16 +144,15 @@ #include <cstring> using namespace lld; +using namespace lld::pecoff; using namespace llvm; namespace lld { -namespace pecoff { namespace { -uint8_t FuncAtomContent[] = { - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0 - 0xcc, 0xcc // int 3; int 3 +uint8_t FuncAtomContent[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0 + 0xcc, 0xcc // int 3; int 3 }; /// The defined atom for jump table. @@ -174,15 +174,14 @@ public: class FileImportLibrary : public File { public: - FileImportLibrary(const LinkingContext &context, - std::unique_ptr<MemoryBuffer> mb, error_code &ec) - : File(mb->getBufferIdentifier(), kindSharedLibrary), _context(context) { + FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, error_code &ec) + : File(mb->getBufferIdentifier(), kindSharedLibrary) { const char *buf = mb->getBufferStart(); const char *end = mb->getBufferEnd(); // The size of the string that follows the header. uint32_t dataSize = *reinterpret_cast<const support::ulittle32_t *>( - buf + offsetof(COFF::ImportHeader, SizeOfData)); + buf + offsetof(COFF::ImportHeader, SizeOfData)); // Check if the total size is valid. if (end - buf != sizeof(COFF::ImportHeader) + dataSize) { @@ -191,14 +190,14 @@ public: } uint16_t hint = *reinterpret_cast<const support::ulittle16_t *>( - 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<const support::ulittle16_t *>( - buf + offsetof(COFF::ImportHeader, TypeInfo)); + buf + offsetof(COFF::ImportHeader, TypeInfo)); int type = typeInfo & 0x3; int nameType = (typeInfo >> 2) & 0x7; @@ -231,8 +230,6 @@ public: return _noAbsoluteAtoms; } - virtual const LinkingContext &getLinkingContext() const { return _context; } - private: const COFFSharedLibraryAtom *addSharedLibraryAtom(uint16_t hint, StringRef symbolName, @@ -256,7 +253,6 @@ private: atom_collection_vector<DefinedAtom> _definedAtoms; atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms; - const LinkingContext &_context; mutable llvm::BumpPtrAllocator _alloc; // Does the same thing as StringRef::ltrim() but removes at most one @@ -294,8 +290,32 @@ private: } }; +class COFFImportLibraryReader : public Reader { +public: + virtual bool canParse(file_magic magic, StringRef, + const MemoryBuffer &mb) const { + if (mb.getBufferSize() < sizeof(COFF::ImportHeader)) + return false; + return (magic == llvm::sys::fs::file_magic::coff_import_library); + } + + virtual error_code + parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &, + std::vector<std::unique_ptr<File> > &result) const { + error_code ec; + auto file = std::unique_ptr<File>(new FileImportLibrary(std::move(mb), ec)); + if (ec) + return ec; + result.push_back(std::move(file)); + return error_code::success(); + } + +}; + } // end anonymous namespace +namespace pecoff { + error_code parseCOFFImportLibrary(const LinkingContext &targetInfo, std::unique_ptr<MemoryBuffer> &mb, std::vector<std::unique_ptr<File> > &result) { @@ -308,8 +328,7 @@ error_code parseCOFFImportLibrary(const LinkingContext &targetInfo, return make_error_code(NativeReaderError::unknown_file_format); error_code ec; - auto file = std::unique_ptr<File>( - new FileImportLibrary(targetInfo, std::move(mb), ec)); + auto file = std::unique_ptr<File>(new FileImportLibrary(std::move(mb), ec)); if (ec) return ec; result.push_back(std::move(file)); @@ -317,4 +336,9 @@ error_code parseCOFFImportLibrary(const LinkingContext &targetInfo, } } // end namespace pecoff + +void Registry::addSupportCOFFImportLibraries() { + add(std::unique_ptr<Reader>(new COFFImportLibraryReader())); +} + } // end namespace lld diff --git a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp index 05621416015..a1b81894208 100644 --- a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp @@ -72,7 +72,7 @@ public: }; explicit Chunk(Kind kind) : _kind(kind), _size(0) {} - virtual ~Chunk() {}; + virtual ~Chunk() {} virtual void write(uint8_t *buffer) = 0; virtual uint64_t size() const { return _size; } virtual uint64_t align() const { return 1; } @@ -106,7 +106,7 @@ public: : HeaderChunk(), _context(ctx) { // Minimum size of DOS stub is 64 bytes. The next block (PE header) needs to // be aligned on 8 byte boundary. - size_t size = std::max(_context.getDosStub().size(), (size_t)64); + size_t size = std::max(_context.getDosStub().size(), (size_t) 64); _size = llvm::RoundUpToAlignment(size, 8); } @@ -303,8 +303,8 @@ private: // Create the content of a relocation block. std::vector<uint8_t> - createBaseRelocBlock(uint64_t pageAddr, - const std::vector<uint16_t> &offsets) const; + createBaseRelocBlock(uint64_t pageAddr, + const std::vector<uint16_t> &offsets) const; std::vector<uint8_t> _contents; }; @@ -454,10 +454,9 @@ void AtomChunk::applyRelocations(uint8_t *buffer, for (const auto *layout : _atomLayouts) { const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); for (const Reference *ref : *atom) { - // Skip if this reference is not for relocation. - if (ref->kind() < lld::Reference::kindTargetLow) + // Skip if this reference is not for COFF relocation. + if (ref->kindNamespace() != Reference::KindNamespace::COFF) continue; - auto relocSite32 = reinterpret_cast<ulittle32_t *>( buffer + layout->_fileOffset + ref->offsetInAtom()); auto relocSite16 = reinterpret_cast<ulittle16_t *>(relocSite32); @@ -465,8 +464,7 @@ void AtomChunk::applyRelocations(uint8_t *buffer, // Also account for whatever offset is already stored at the relocation // site. targetAddr += *relocSite32; - - switch (ref->kind()) { + switch (ref->kindValue()) { case llvm::COFF::IMAGE_REL_I386_ABSOLUTE: // This relocation is no-op. break; @@ -539,7 +537,8 @@ void AtomChunk::addBaseRelocations(std::vector<uint64_t> &relocSites) const { for (const auto *layout : _atomLayouts) { const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); for (const Reference *ref : *atom) - if (ref->kind() == llvm::COFF::IMAGE_REL_I386_DIR32) + if ((ref->kindNamespace() == Reference::KindNamespace::COFF) && + (ref->kindValue() == llvm::COFF::IMAGE_REL_I386_DIR32)) relocSites.push_back(layout->_virtualAddr + ref->offsetInAtom()); } } @@ -753,7 +752,7 @@ private: void setImageSizeOnDisk(); void setAddressOfEntryPoint(AtomChunk *text, PEHeaderChunk *peHeader); uint64_t - calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const; + calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const; uint64_t calcSizeOfInitializedData() const { return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA); |