From 0b57cec536236d46e3dba9bd041533462f33dbb7 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Fri, 20 Dec 2019 19:53:05 +0000 Subject: Move all sources from the llvm project into contrib/llvm-project. This uses the new layout of the upstream repository, which was recently migrated to GitHub, and converted into a "monorepo". That is, most of the earlier separate sub-projects with their own branches and tags were consolidated into one top-level directory, and are now branched and tagged together. Updating the vendor area to match this layout is next. --- contrib/llvm/lib/Object/WindowsResource.cpp | 803 ---------------------------- 1 file changed, 803 deletions(-) delete mode 100644 contrib/llvm/lib/Object/WindowsResource.cpp (limited to 'contrib/llvm/lib/Object/WindowsResource.cpp') diff --git a/contrib/llvm/lib/Object/WindowsResource.cpp b/contrib/llvm/lib/Object/WindowsResource.cpp deleted file mode 100644 index d76e1231684c..000000000000 --- a/contrib/llvm/lib/Object/WindowsResource.cpp +++ /dev/null @@ -1,803 +0,0 @@ -//===-- WindowsResource.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the .res file class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Object/WindowsResource.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/ScopedPrinter.h" -#include -#include -#include - -using namespace llvm; -using namespace object; - -namespace llvm { -namespace object { - -#define RETURN_IF_ERROR(X) \ - if (auto EC = X) \ - return EC; - -const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); - -// COFF files seem to be inconsistent with alignment between sections, just use -// 8-byte because it makes everyone happy. -const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); - -uint32_t WindowsResourceParser::TreeNode::StringCount = 0; -uint32_t WindowsResourceParser::TreeNode::DataCount = 0; - -WindowsResource::WindowsResource(MemoryBufferRef Source) - : Binary(Binary::ID_WinRes, Source) { - size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE; - BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize), - support::little); -} - -// static -Expected> -WindowsResource::createWindowsResource(MemoryBufferRef Source) { - if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE) - return make_error( - Source.getBufferIdentifier() + ": too small to be a resource file", - object_error::invalid_file_type); - std::unique_ptr Ret(new WindowsResource(Source)); - return std::move(Ret); -} - -Expected WindowsResource::getHeadEntry() { - if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix)) - return make_error(getFileName() + " contains no entries", - object_error::unexpected_eof); - return ResourceEntryRef::create(BinaryStreamRef(BBS), this); -} - -ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, - const WindowsResource *Owner) - : Reader(Ref), Owner(Owner) {} - -Expected -ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) { - auto Ref = ResourceEntryRef(BSR, Owner); - if (auto E = Ref.loadNext()) - return std::move(E); - return Ref; -} - -Error ResourceEntryRef::moveNext(bool &End) { - // Reached end of all the entries. - if (Reader.bytesRemaining() == 0) { - End = true; - return Error::success(); - } - RETURN_IF_ERROR(loadNext()); - - return Error::success(); -} - -static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, - ArrayRef &Str, bool &IsString) { - uint16_t IDFlag; - RETURN_IF_ERROR(Reader.readInteger(IDFlag)); - IsString = IDFlag != 0xffff; - - if (IsString) { - Reader.setOffset( - Reader.getOffset() - - sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. - RETURN_IF_ERROR(Reader.readWideString(Str)); - } else - RETURN_IF_ERROR(Reader.readInteger(ID)); - - return Error::success(); -} - -Error ResourceEntryRef::loadNext() { - const WinResHeaderPrefix *Prefix; - RETURN_IF_ERROR(Reader.readObject(Prefix)); - - if (Prefix->HeaderSize < MIN_HEADER_SIZE) - return make_error(Owner->getFileName() + - ": header size too small", - object_error::parse_failed); - - RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); - - RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); - - RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT)); - - RETURN_IF_ERROR(Reader.readObject(Suffix)); - - RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize)); - - RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT)); - - return Error::success(); -} - -WindowsResourceParser::WindowsResourceParser() : Root(false) {} - -void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) { - switch (TypeID) { - case 1: OS << "CURSOR (ID 1)"; break; - case 2: OS << "BITMAP (ID 2)"; break; - case 3: OS << "ICON (ID 3)"; break; - case 4: OS << "MENU (ID 4)"; break; - case 5: OS << "DIALOG (ID 5)"; break; - case 6: OS << "STRINGTABLE (ID 6)"; break; - case 7: OS << "FONTDIR (ID 7)"; break; - case 8: OS << "FONT (ID 8)"; break; - case 9: OS << "ACCELERATOR (ID 9)"; break; - case 10: OS << "RCDATA (ID 10)"; break; - case 11: OS << "MESSAGETABLE (ID 11)"; break; - case 12: OS << "GROUP_CURSOR (ID 12)"; break; - case 14: OS << "GROUP_ICON (ID 14)"; break; - case 16: OS << "VERSIONINFO (ID 16)"; break; - case 17: OS << "DLGINCLUDE (ID 17)"; break; - case 19: OS << "PLUGPLAY (ID 19)"; break; - case 20: OS << "VXD (ID 20)"; break; - case 21: OS << "ANICURSOR (ID 21)"; break; - case 22: OS << "ANIICON (ID 22)"; break; - case 23: OS << "HTML (ID 23)"; break; - case 24: OS << "MANIFEST (ID 24)"; break; - default: OS << "ID " << TypeID; break; - } -} - -static bool convertUTF16LEToUTF8String(ArrayRef Src, std::string &Out) { - if (!sys::IsBigEndianHost) - return convertUTF16ToUTF8String(Src, Out); - - std::vector EndianCorrectedSrc; - EndianCorrectedSrc.resize(Src.size() + 1); - llvm::copy(Src, EndianCorrectedSrc.begin() + 1); - EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; - return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out); -} - -static std::string makeDuplicateResourceError( - const ResourceEntryRef &Entry, StringRef File1, StringRef File2) { - std::string Ret; - raw_string_ostream OS(Ret); - - OS << "duplicate resource:"; - - OS << " type "; - if (Entry.checkTypeString()) { - std::string UTF8; - if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8)) - UTF8 = "(failed conversion from UTF16)"; - OS << '\"' << UTF8 << '\"'; - } else - printResourceTypeName(Entry.getTypeID(), OS); - - OS << "/name "; - if (Entry.checkNameString()) { - std::string UTF8; - if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8)) - UTF8 = "(failed conversion from UTF16)"; - OS << '\"' << UTF8 << '\"'; - } else { - OS << "ID " << Entry.getNameID(); - } - - OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in " - << File2; - - return OS.str(); -} - -Error WindowsResourceParser::parse(WindowsResource *WR, - std::vector &Duplicates) { - auto EntryOrErr = WR->getHeadEntry(); - if (!EntryOrErr) { - auto E = EntryOrErr.takeError(); - if (E.isA()) { - // Check if the .res file contains no entries. In this case we don't have - // to throw an error but can rather just return without parsing anything. - // This applies for files which have a valid PE header magic and the - // mandatory empty null resource entry. Files which do not fit this - // criteria would have already been filtered out by - // WindowsResource::createWindowsResource(). - consumeError(std::move(E)); - return Error::success(); - } - return E; - } - - ResourceEntryRef Entry = EntryOrErr.get(); - bool End = false; - while (!End) { - Data.push_back(Entry.getData()); - - bool IsNewTypeString = false; - bool IsNewNameString = false; - - TreeNode* Node; - bool IsNewNode = Root.addEntry(Entry, InputFilenames.size(), - IsNewTypeString, IsNewNameString, Node); - InputFilenames.push_back(WR->getFileName()); - if (!IsNewNode) { - Duplicates.push_back(makeDuplicateResourceError( - Entry, InputFilenames[Node->Origin], WR->getFileName())); - } - - if (IsNewTypeString) - StringTable.push_back(Entry.getTypeString()); - - if (IsNewNameString) - StringTable.push_back(Entry.getNameString()); - - RETURN_IF_ERROR(Entry.moveNext(End)); - } - - return Error::success(); -} - -void WindowsResourceParser::printTree(raw_ostream &OS) const { - ScopedPrinter Writer(OS); - Root.print(Writer, "Resource Tree"); -} - -bool WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, - uint32_t Origin, - bool &IsNewTypeString, - bool &IsNewNameString, - TreeNode *&Result) { - TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString); - TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString); - return NameNode.addLanguageNode(Entry, Origin, Result); -} - -WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) { - if (IsStringNode) - StringIndex = StringCount++; -} - -WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, - uint16_t MinorVersion, - uint32_t Characteristics, - uint32_t Origin) - : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion), - Characteristics(Characteristics), Origin(Origin) { - DataIndex = DataCount++; -} - -std::unique_ptr -WindowsResourceParser::TreeNode::createStringNode() { - return std::unique_ptr(new TreeNode(true)); -} - -std::unique_ptr -WindowsResourceParser::TreeNode::createIDNode() { - return std::unique_ptr(new TreeNode(false)); -} - -std::unique_ptr -WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, - uint16_t MinorVersion, - uint32_t Characteristics, - uint32_t Origin) { - return std::unique_ptr( - new TreeNode(MajorVersion, MinorVersion, Characteristics, Origin)); -} - -WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry, - bool &IsNewTypeString) { - if (Entry.checkTypeString()) - return addNameChild(Entry.getTypeString(), IsNewTypeString); - else - return addIDChild(Entry.getTypeID()); -} - -WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry, - bool &IsNewNameString) { - if (Entry.checkNameString()) - return addNameChild(Entry.getNameString(), IsNewNameString); - else - return addIDChild(Entry.getNameID()); -} - -bool WindowsResourceParser::TreeNode::addLanguageNode( - const ResourceEntryRef &Entry, uint32_t Origin, TreeNode *&Result) { - return addDataChild(Entry.getLanguage(), Entry.getMajorVersion(), - Entry.getMinorVersion(), Entry.getCharacteristics(), - Origin, Result); -} - -bool WindowsResourceParser::TreeNode::addDataChild( - uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics, uint32_t Origin, TreeNode *&Result) { - auto NewChild = - createDataNode(MajorVersion, MinorVersion, Characteristics, Origin); - auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild)); - Result = ElementInserted.first->second.get(); - return ElementInserted.second; -} - -WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild( - uint32_t ID) { - auto Child = IDChildren.find(ID); - if (Child == IDChildren.end()) { - auto NewChild = createIDNode(); - WindowsResourceParser::TreeNode &Node = *NewChild; - IDChildren.emplace(ID, std::move(NewChild)); - return Node; - } else - return *(Child->second); -} - -WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addNameChild(ArrayRef NameRef, - bool &IsNewString) { - std::string NameString; - convertUTF16LEToUTF8String(NameRef, NameString); - - auto Child = StringChildren.find(NameString); - if (Child == StringChildren.end()) { - auto NewChild = createStringNode(); - IsNewString = true; - WindowsResourceParser::TreeNode &Node = *NewChild; - StringChildren.emplace(NameString, std::move(NewChild)); - return Node; - } else - return *(Child->second); -} - -void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, - StringRef Name) const { - ListScope NodeScope(Writer, Name); - for (auto const &Child : StringChildren) { - Child.second->print(Writer, Child.first); - } - for (auto const &Child : IDChildren) { - Child.second->print(Writer, to_string(Child.first)); - } -} - -// This function returns the size of the entire resource tree, including -// directory tables, directory entries, and data entries. It does not include -// the directory strings or the relocations of the .rsrc section. -uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { - uint32_t Size = (IDChildren.size() + StringChildren.size()) * - sizeof(coff_resource_dir_entry); - - // Reached a node pointing to a data entry. - if (IsDataNode) { - Size += sizeof(coff_resource_data_entry); - return Size; - } - - // If the node does not point to data, it must have a directory table pointing - // to other nodes. - Size += sizeof(coff_resource_dir_table); - - for (auto const &Child : StringChildren) { - Size += Child.second->getTreeSize(); - } - for (auto const &Child : IDChildren) { - Size += Child.second->getTreeSize(); - } - return Size; -} - -class WindowsResourceCOFFWriter { -public: - WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, - const WindowsResourceParser &Parser, Error &E); - std::unique_ptr write(uint32_t TimeDateStamp); - -private: - void performFileLayout(); - void performSectionOneLayout(); - void performSectionTwoLayout(); - void writeCOFFHeader(uint32_t TimeDateStamp); - void writeFirstSectionHeader(); - void writeSecondSectionHeader(); - void writeFirstSection(); - void writeSecondSection(); - void writeSymbolTable(); - void writeStringTable(); - void writeDirectoryTree(); - void writeDirectoryStringTable(); - void writeFirstSectionRelocations(); - std::unique_ptr OutputBuffer; - char *BufferStart; - uint64_t CurrentOffset = 0; - COFF::MachineTypes MachineType; - const WindowsResourceParser::TreeNode &Resources; - const ArrayRef> Data; - uint64_t FileSize; - uint32_t SymbolTableOffset; - uint32_t SectionOneSize; - uint32_t SectionOneOffset; - uint32_t SectionOneRelocations; - uint32_t SectionTwoSize; - uint32_t SectionTwoOffset; - const ArrayRef> StringTable; - std::vector StringTableOffsets; - std::vector DataOffsets; - std::vector RelocationAddresses; -}; - -WindowsResourceCOFFWriter::WindowsResourceCOFFWriter( - COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, - Error &E) - : MachineType(MachineType), Resources(Parser.getTree()), - Data(Parser.getData()), StringTable(Parser.getStringTable()) { - performFileLayout(); - - OutputBuffer = WritableMemoryBuffer::getNewMemBuffer( - FileSize, "internal .obj file created from .res files"); -} - -void WindowsResourceCOFFWriter::performFileLayout() { - // Add size of COFF header. - FileSize = COFF::Header16Size; - - // one .rsrc section header for directory tree, another for resource data. - FileSize += 2 * COFF::SectionSize; - - performSectionOneLayout(); - performSectionTwoLayout(); - - // We have reached the address of the symbol table. - SymbolTableOffset = FileSize; - - FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol. - FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section. - FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource. - FileSize += 4; // four null bytes for the string table. -} - -void WindowsResourceCOFFWriter::performSectionOneLayout() { - SectionOneOffset = FileSize; - - SectionOneSize = Resources.getTreeSize(); - uint32_t CurrentStringOffset = SectionOneSize; - uint32_t TotalStringTableSize = 0; - for (auto const &String : StringTable) { - StringTableOffsets.push_back(CurrentStringOffset); - uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t); - CurrentStringOffset += StringSize; - TotalStringTableSize += StringSize; - } - SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t)); - - // account for the relocations of section one. - SectionOneRelocations = FileSize + SectionOneSize; - FileSize += SectionOneSize; - FileSize += - Data.size() * COFF::RelocationSize; // one relocation for each resource. - FileSize = alignTo(FileSize, SECTION_ALIGNMENT); -} - -void WindowsResourceCOFFWriter::performSectionTwoLayout() { - // add size of .rsrc$2 section, which contains all resource data on 8-byte - // alignment. - SectionTwoOffset = FileSize; - SectionTwoSize = 0; - for (auto const &Entry : Data) { - DataOffsets.push_back(SectionTwoSize); - SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t)); - } - FileSize += SectionTwoSize; - FileSize = alignTo(FileSize, SECTION_ALIGNMENT); -} - -std::unique_ptr -WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) { - BufferStart = OutputBuffer->getBufferStart(); - - writeCOFFHeader(TimeDateStamp); - writeFirstSectionHeader(); - writeSecondSectionHeader(); - writeFirstSection(); - writeSecondSection(); - writeSymbolTable(); - writeStringTable(); - - return std::move(OutputBuffer); -} - -void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) { - // Write the COFF header. - auto *Header = reinterpret_cast(BufferStart); - Header->Machine = MachineType; - Header->NumberOfSections = 2; - Header->TimeDateStamp = TimeDateStamp; - Header->PointerToSymbolTable = SymbolTableOffset; - // One symbol for every resource plus 2 for each section and 1 for @feat.00 - Header->NumberOfSymbols = Data.size() + 5; - Header->SizeOfOptionalHeader = 0; - // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it. - Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; -} - -void WindowsResourceCOFFWriter::writeFirstSectionHeader() { - // Write the first section header. - CurrentOffset += sizeof(coff_file_header); - auto *SectionOneHeader = - reinterpret_cast(BufferStart + CurrentOffset); - strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize); - SectionOneHeader->VirtualSize = 0; - SectionOneHeader->VirtualAddress = 0; - SectionOneHeader->SizeOfRawData = SectionOneSize; - SectionOneHeader->PointerToRawData = SectionOneOffset; - SectionOneHeader->PointerToRelocations = SectionOneRelocations; - SectionOneHeader->PointerToLinenumbers = 0; - SectionOneHeader->NumberOfRelocations = Data.size(); - SectionOneHeader->NumberOfLinenumbers = 0; - SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; - SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; -} - -void WindowsResourceCOFFWriter::writeSecondSectionHeader() { - // Write the second section header. - CurrentOffset += sizeof(coff_section); - auto *SectionTwoHeader = - reinterpret_cast(BufferStart + CurrentOffset); - strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize); - SectionTwoHeader->VirtualSize = 0; - SectionTwoHeader->VirtualAddress = 0; - SectionTwoHeader->SizeOfRawData = SectionTwoSize; - SectionTwoHeader->PointerToRawData = SectionTwoOffset; - SectionTwoHeader->PointerToRelocations = 0; - SectionTwoHeader->PointerToLinenumbers = 0; - SectionTwoHeader->NumberOfRelocations = 0; - SectionTwoHeader->NumberOfLinenumbers = 0; - SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; - SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; -} - -void WindowsResourceCOFFWriter::writeFirstSection() { - // Write section one. - CurrentOffset += sizeof(coff_section); - - writeDirectoryTree(); - writeDirectoryStringTable(); - writeFirstSectionRelocations(); - - CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); -} - -void WindowsResourceCOFFWriter::writeSecondSection() { - // Now write the .rsrc$02 section. - for (auto const &RawDataEntry : Data) { - llvm::copy(RawDataEntry, BufferStart + CurrentOffset); - CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t)); - } - - CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); -} - -void WindowsResourceCOFFWriter::writeSymbolTable() { - // Now write the symbol table. - // First, the feat symbol. - auto *Symbol = reinterpret_cast(BufferStart + CurrentOffset); - strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize); - Symbol->Value = 0x11; - Symbol->SectionNumber = 0xffff; - Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; - Symbol->NumberOfAuxSymbols = 0; - CurrentOffset += sizeof(coff_symbol16); - - // Now write the .rsrc1 symbol + aux. - Symbol = reinterpret_cast(BufferStart + CurrentOffset); - strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize); - Symbol->Value = 0; - Symbol->SectionNumber = 1; - Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; - Symbol->NumberOfAuxSymbols = 1; - CurrentOffset += sizeof(coff_symbol16); - auto *Aux = reinterpret_cast(BufferStart + - CurrentOffset); - Aux->Length = SectionOneSize; - Aux->NumberOfRelocations = Data.size(); - Aux->NumberOfLinenumbers = 0; - Aux->CheckSum = 0; - Aux->NumberLowPart = 0; - Aux->Selection = 0; - CurrentOffset += sizeof(coff_aux_section_definition); - - // Now write the .rsrc2 symbol + aux. - Symbol = reinterpret_cast(BufferStart + CurrentOffset); - strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize); - Symbol->Value = 0; - Symbol->SectionNumber = 2; - Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; - Symbol->NumberOfAuxSymbols = 1; - CurrentOffset += sizeof(coff_symbol16); - Aux = reinterpret_cast(BufferStart + - CurrentOffset); - Aux->Length = SectionTwoSize; - Aux->NumberOfRelocations = 0; - Aux->NumberOfLinenumbers = 0; - Aux->CheckSum = 0; - Aux->NumberLowPart = 0; - Aux->Selection = 0; - CurrentOffset += sizeof(coff_aux_section_definition); - - // Now write a symbol for each relocation. - for (unsigned i = 0; i < Data.size(); i++) { - auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr(); - Symbol = reinterpret_cast(BufferStart + CurrentOffset); - memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize); - Symbol->Value = DataOffsets[i]; - Symbol->SectionNumber = 2; - Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; - Symbol->NumberOfAuxSymbols = 0; - CurrentOffset += sizeof(coff_symbol16); - } -} - -void WindowsResourceCOFFWriter::writeStringTable() { - // Just 4 null bytes for the string table. - auto COFFStringTable = reinterpret_cast(BufferStart + CurrentOffset); - memset(COFFStringTable, 0, 4); -} - -void WindowsResourceCOFFWriter::writeDirectoryTree() { - // Traverse parsed resource tree breadth-first and write the corresponding - // COFF objects. - std::queue Queue; - Queue.push(&Resources); - uint32_t NextLevelOffset = - sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() + - Resources.getIDChildren().size()) * - sizeof(coff_resource_dir_entry); - std::vector DataEntriesTreeOrder; - uint32_t CurrentRelativeOffset = 0; - - while (!Queue.empty()) { - auto CurrentNode = Queue.front(); - Queue.pop(); - auto *Table = reinterpret_cast(BufferStart + - CurrentOffset); - Table->Characteristics = CurrentNode->getCharacteristics(); - Table->TimeDateStamp = 0; - Table->MajorVersion = CurrentNode->getMajorVersion(); - Table->MinorVersion = CurrentNode->getMinorVersion(); - auto &IDChildren = CurrentNode->getIDChildren(); - auto &StringChildren = CurrentNode->getStringChildren(); - Table->NumberOfNameEntries = StringChildren.size(); - Table->NumberOfIDEntries = IDChildren.size(); - CurrentOffset += sizeof(coff_resource_dir_table); - CurrentRelativeOffset += sizeof(coff_resource_dir_table); - - // Write the directory entries immediately following each directory table. - for (auto const &Child : StringChildren) { - auto *Entry = reinterpret_cast(BufferStart + - CurrentOffset); - Entry->Identifier.setNameOffset( - StringTableOffsets[Child.second->getStringIndex()]); - if (Child.second->checkIsDataNode()) { - Entry->Offset.DataEntryOffset = NextLevelOffset; - NextLevelOffset += sizeof(coff_resource_data_entry); - DataEntriesTreeOrder.push_back(Child.second.get()); - } else { - Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); - NextLevelOffset += sizeof(coff_resource_dir_table) + - (Child.second->getStringChildren().size() + - Child.second->getIDChildren().size()) * - sizeof(coff_resource_dir_entry); - Queue.push(Child.second.get()); - } - CurrentOffset += sizeof(coff_resource_dir_entry); - CurrentRelativeOffset += sizeof(coff_resource_dir_entry); - } - for (auto const &Child : IDChildren) { - auto *Entry = reinterpret_cast(BufferStart + - CurrentOffset); - Entry->Identifier.ID = Child.first; - if (Child.second->checkIsDataNode()) { - Entry->Offset.DataEntryOffset = NextLevelOffset; - NextLevelOffset += sizeof(coff_resource_data_entry); - DataEntriesTreeOrder.push_back(Child.second.get()); - } else { - Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); - NextLevelOffset += sizeof(coff_resource_dir_table) + - (Child.second->getStringChildren().size() + - Child.second->getIDChildren().size()) * - sizeof(coff_resource_dir_entry); - Queue.push(Child.second.get()); - } - CurrentOffset += sizeof(coff_resource_dir_entry); - CurrentRelativeOffset += sizeof(coff_resource_dir_entry); - } - } - - RelocationAddresses.resize(Data.size()); - // Now write all the resource data entries. - for (auto DataNodes : DataEntriesTreeOrder) { - auto *Entry = reinterpret_cast(BufferStart + - CurrentOffset); - RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset; - Entry->DataRVA = 0; // Set to zero because it is a relocation. - Entry->DataSize = Data[DataNodes->getDataIndex()].size(); - Entry->Codepage = 0; - Entry->Reserved = 0; - CurrentOffset += sizeof(coff_resource_data_entry); - CurrentRelativeOffset += sizeof(coff_resource_data_entry); - } -} - -void WindowsResourceCOFFWriter::writeDirectoryStringTable() { - // Now write the directory string table for .rsrc$01 - uint32_t TotalStringTableSize = 0; - for (auto &String : StringTable) { - uint16_t Length = String.size(); - support::endian::write16le(BufferStart + CurrentOffset, Length); - CurrentOffset += sizeof(uint16_t); - auto *Start = reinterpret_cast(BufferStart + CurrentOffset); - llvm::copy(String, Start); - CurrentOffset += Length * sizeof(UTF16); - TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t); - } - CurrentOffset += - alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize; -} - -void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { - - // Now write the relocations for .rsrc$01 - // Five symbols already in table before we start, @feat.00 and 2 for each - // .rsrc section. - uint32_t NextSymbolIndex = 5; - for (unsigned i = 0; i < Data.size(); i++) { - auto *Reloc = - reinterpret_cast(BufferStart + CurrentOffset); - Reloc->VirtualAddress = RelocationAddresses[i]; - Reloc->SymbolTableIndex = NextSymbolIndex++; - switch (MachineType) { - case COFF::IMAGE_FILE_MACHINE_ARMNT: - Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB; - break; - case COFF::IMAGE_FILE_MACHINE_AMD64: - Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB; - break; - case COFF::IMAGE_FILE_MACHINE_I386: - Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; - break; - case COFF::IMAGE_FILE_MACHINE_ARM64: - Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB; - break; - default: - llvm_unreachable("unknown machine type"); - } - CurrentOffset += sizeof(coff_relocation); - } -} - -Expected> -writeWindowsResourceCOFF(COFF::MachineTypes MachineType, - const WindowsResourceParser &Parser, - uint32_t TimeDateStamp) { - Error E = Error::success(); - WindowsResourceCOFFWriter Writer(MachineType, Parser, E); - if (E) - return std::move(E); - return Writer.write(TimeDateStamp); -} - -} // namespace object -} // namespace llvm -- cgit v1.2.3