1a6bdf751SEric Beckmann //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===// 2a6bdf751SEric Beckmann // 3a6bdf751SEric Beckmann // The LLVM Compiler Infrastructure 4a6bdf751SEric Beckmann // 5a6bdf751SEric Beckmann // This file is distributed under the University of Illinois Open Source 6a6bdf751SEric Beckmann // License. See LICENSE.TXT for details. 7a6bdf751SEric Beckmann // 8a6bdf751SEric Beckmann //===----------------------------------------------------------------------===// 9a6bdf751SEric Beckmann // 10a6bdf751SEric Beckmann // This file implements the .res file class. 11a6bdf751SEric Beckmann // 12a6bdf751SEric Beckmann //===----------------------------------------------------------------------===// 13a6bdf751SEric Beckmann 14a6bdf751SEric Beckmann #include "llvm/Object/WindowsResource.h" 15d9de6389SEric Beckmann #include "llvm/Object/COFF.h" 16d9de6389SEric Beckmann #include "llvm/Support/FileOutputBuffer.h" 17*ea5ff9faSBob Haarman #include "llvm/Support/FormatVariadic.h" 18d9de6389SEric Beckmann #include "llvm/Support/MathExtras.h" 19d9de6389SEric Beckmann #include <ctime> 20d9de6389SEric Beckmann #include <queue> 21a6bdf751SEric Beckmann #include <system_error> 22a6bdf751SEric Beckmann 23d135e8c0SEric Beckmann using namespace llvm; 247687f046SEric Beckmann using namespace object; 25d135e8c0SEric Beckmann 26a6bdf751SEric Beckmann namespace llvm { 27a6bdf751SEric Beckmann namespace object { 28a6bdf751SEric Beckmann 2972fb6a87SEric Beckmann #define RETURN_IF_ERROR(X) \ 3072fb6a87SEric Beckmann if (auto EC = X) \ 3114ea122eSBenjamin Kramer return EC; 3272fb6a87SEric Beckmann 3372fb6a87SEric Beckmann const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); 3472fb6a87SEric Beckmann 35382eaabbSEric Beckmann // COFF files seem to be inconsistent with alignment between sections, just use 36382eaabbSEric Beckmann // 8-byte because it makes everyone happy. 37382eaabbSEric Beckmann const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); 38382eaabbSEric Beckmann 39d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::StringCount = 0; 40d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::DataCount = 0; 41d9de6389SEric Beckmann 42a6bdf751SEric Beckmann WindowsResource::WindowsResource(MemoryBufferRef Source) 43a6bdf751SEric Beckmann : Binary(Binary::ID_WinRes, Source) { 44c8dba240SEric Beckmann size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE; 45a6bdf751SEric Beckmann BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize), 46a6bdf751SEric Beckmann support::little); 47a6bdf751SEric Beckmann } 48a6bdf751SEric Beckmann 49a6bdf751SEric Beckmann Expected<std::unique_ptr<WindowsResource>> 50a6bdf751SEric Beckmann WindowsResource::createWindowsResource(MemoryBufferRef Source) { 51c8dba240SEric Beckmann if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE) 52a6bdf751SEric Beckmann return make_error<GenericBinaryError>( 53a6bdf751SEric Beckmann "File too small to be a resource file", 54a6bdf751SEric Beckmann object_error::invalid_file_type); 55a6bdf751SEric Beckmann std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source)); 56a6bdf751SEric Beckmann return std::move(Ret); 57a6bdf751SEric Beckmann } 58a6bdf751SEric Beckmann 59a6bdf751SEric Beckmann Expected<ResourceEntryRef> WindowsResource::getHeadEntry() { 60b85172f6SEric Beckmann if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix)) 61b85172f6SEric Beckmann return make_error<EmptyResError>(".res contains no entries", 62b85172f6SEric Beckmann object_error::unexpected_eof); 63b85172f6SEric Beckmann return ResourceEntryRef::create(BinaryStreamRef(BBS), this); 64a6bdf751SEric Beckmann } 65a6bdf751SEric Beckmann 66a6bdf751SEric Beckmann ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, 67b85172f6SEric Beckmann const WindowsResource *Owner) 681657f2adSNAKAMURA Takumi : Reader(Ref) {} 69b85172f6SEric Beckmann 70b85172f6SEric Beckmann Expected<ResourceEntryRef> 71b85172f6SEric Beckmann ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) { 72b85172f6SEric Beckmann auto Ref = ResourceEntryRef(BSR, Owner); 73b85172f6SEric Beckmann if (auto E = Ref.loadNext()) 74b85172f6SEric Beckmann return std::move(E); 75b85172f6SEric Beckmann return Ref; 76a6bdf751SEric Beckmann } 77a6bdf751SEric Beckmann 78a6bdf751SEric Beckmann Error ResourceEntryRef::moveNext(bool &End) { 79a6bdf751SEric Beckmann // Reached end of all the entries. 80a6bdf751SEric Beckmann if (Reader.bytesRemaining() == 0) { 81a6bdf751SEric Beckmann End = true; 82a6bdf751SEric Beckmann return Error::success(); 83a6bdf751SEric Beckmann } 84a6bdf751SEric Beckmann RETURN_IF_ERROR(loadNext()); 85a6bdf751SEric Beckmann 86a6bdf751SEric Beckmann return Error::success(); 87a6bdf751SEric Beckmann } 88a6bdf751SEric Beckmann 8972fb6a87SEric Beckmann static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, 9072fb6a87SEric Beckmann ArrayRef<UTF16> &Str, bool &IsString) { 9172fb6a87SEric Beckmann uint16_t IDFlag; 9272fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(IDFlag)); 9372fb6a87SEric Beckmann IsString = IDFlag != 0xffff; 9472fb6a87SEric Beckmann 9572fb6a87SEric Beckmann if (IsString) { 9672fb6a87SEric Beckmann Reader.setOffset( 9772fb6a87SEric Beckmann Reader.getOffset() - 9872fb6a87SEric Beckmann sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. 9972fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readWideString(Str)); 10072fb6a87SEric Beckmann } else 10172fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(ID)); 10272fb6a87SEric Beckmann 10372fb6a87SEric Beckmann return Error::success(); 10472fb6a87SEric Beckmann } 10572fb6a87SEric Beckmann 106a6bdf751SEric Beckmann Error ResourceEntryRef::loadNext() { 107c8dba240SEric Beckmann const WinResHeaderPrefix *Prefix; 108c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.readObject(Prefix)); 10972fb6a87SEric Beckmann 110c8dba240SEric Beckmann if (Prefix->HeaderSize < MIN_HEADER_SIZE) 11172fb6a87SEric Beckmann return make_error<GenericBinaryError>("Header size is too small.", 11272fb6a87SEric Beckmann object_error::parse_failed); 11372fb6a87SEric Beckmann 11472fb6a87SEric Beckmann RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); 11572fb6a87SEric Beckmann 11672fb6a87SEric Beckmann RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); 11772fb6a87SEric Beckmann 118c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT)); 11972fb6a87SEric Beckmann 12072fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readObject(Suffix)); 12172fb6a87SEric Beckmann 122c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize)); 12372fb6a87SEric Beckmann 124c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT)); 12572fb6a87SEric Beckmann 126a6bdf751SEric Beckmann return Error::success(); 127a6bdf751SEric Beckmann } 128a6bdf751SEric Beckmann 129d9de6389SEric Beckmann WindowsResourceParser::WindowsResourceParser() : Root(false) {} 13072fb6a87SEric Beckmann 13172fb6a87SEric Beckmann Error WindowsResourceParser::parse(WindowsResource *WR) { 13272fb6a87SEric Beckmann auto EntryOrErr = WR->getHeadEntry(); 133b85172f6SEric Beckmann if (!EntryOrErr) { 134b85172f6SEric Beckmann auto E = EntryOrErr.takeError(); 135b85172f6SEric Beckmann if (E.isA<EmptyResError>()) { 136b85172f6SEric Beckmann // Check if the .res file contains no entries. In this case we don't have 137b85172f6SEric Beckmann // to throw an error but can rather just return without parsing anything. 138b85172f6SEric Beckmann // This applies for files which have a valid PE header magic and the 139b85172f6SEric Beckmann // mandatory empty null resource entry. Files which do not fit this 140b85172f6SEric Beckmann // criteria would have already been filtered out by 141b85172f6SEric Beckmann // WindowsResource::createWindowsResource(). 142b85172f6SEric Beckmann consumeError(std::move(E)); 143b85172f6SEric Beckmann return Error::success(); 144b85172f6SEric Beckmann } 145b85172f6SEric Beckmann return E; 146b85172f6SEric Beckmann } 14772fb6a87SEric Beckmann 14872fb6a87SEric Beckmann ResourceEntryRef Entry = EntryOrErr.get(); 14972fb6a87SEric Beckmann bool End = false; 15072fb6a87SEric Beckmann while (!End) { 151d9de6389SEric Beckmann Data.push_back(Entry.getData()); 152d9de6389SEric Beckmann 15313017597SEric Beckmann bool IsNewTypeString = false; 15413017597SEric Beckmann bool IsNewNameString = false; 15513017597SEric Beckmann 15613017597SEric Beckmann Root.addEntry(Entry, IsNewTypeString, IsNewNameString); 15713017597SEric Beckmann 15813017597SEric Beckmann if (IsNewTypeString) 159d9de6389SEric Beckmann StringTable.push_back(Entry.getTypeString()); 160d9de6389SEric Beckmann 16113017597SEric Beckmann if (IsNewNameString) 162d9de6389SEric Beckmann StringTable.push_back(Entry.getNameString()); 163d9de6389SEric Beckmann 16472fb6a87SEric Beckmann RETURN_IF_ERROR(Entry.moveNext(End)); 16572fb6a87SEric Beckmann } 16672fb6a87SEric Beckmann 16772fb6a87SEric Beckmann return Error::success(); 16872fb6a87SEric Beckmann } 16972fb6a87SEric Beckmann 170907fb813SEric Beckmann void WindowsResourceParser::printTree(raw_ostream &OS) const { 171907fb813SEric Beckmann ScopedPrinter Writer(OS); 17272fb6a87SEric Beckmann Root.print(Writer, "Resource Tree"); 17372fb6a87SEric Beckmann } 17472fb6a87SEric Beckmann 17513017597SEric Beckmann void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, 17613017597SEric Beckmann bool &IsNewTypeString, 17713017597SEric Beckmann bool &IsNewNameString) { 17813017597SEric Beckmann TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString); 17913017597SEric Beckmann TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString); 18072fb6a87SEric Beckmann NameNode.addLanguageNode(Entry); 18172fb6a87SEric Beckmann } 18272fb6a87SEric Beckmann 183d9de6389SEric Beckmann WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) { 184d9de6389SEric Beckmann if (IsStringNode) 185d9de6389SEric Beckmann StringIndex = StringCount++; 186d9de6389SEric Beckmann } 187d9de6389SEric Beckmann 188d9de6389SEric Beckmann WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, 189d9de6389SEric Beckmann uint16_t MinorVersion, 190d9de6389SEric Beckmann uint32_t Characteristics) 191d9de6389SEric Beckmann : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion), 192d9de6389SEric Beckmann Characteristics(Characteristics) { 193d9de6389SEric Beckmann DataIndex = DataCount++; 194d9de6389SEric Beckmann } 195d9de6389SEric Beckmann 196d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 197d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createStringNode() { 198d9de6389SEric Beckmann return std::unique_ptr<TreeNode>(new TreeNode(true)); 199d9de6389SEric Beckmann } 200d9de6389SEric Beckmann 201d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 202d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createIDNode() { 203d9de6389SEric Beckmann return std::unique_ptr<TreeNode>(new TreeNode(false)); 204d9de6389SEric Beckmann } 205d9de6389SEric Beckmann 206d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 207d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, 208d9de6389SEric Beckmann uint16_t MinorVersion, 209d9de6389SEric Beckmann uint32_t Characteristics) { 210d9de6389SEric Beckmann return std::unique_ptr<TreeNode>( 211d9de6389SEric Beckmann new TreeNode(MajorVersion, MinorVersion, Characteristics)); 212d9de6389SEric Beckmann } 21372fb6a87SEric Beckmann 21472fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 21513017597SEric Beckmann WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry, 21613017597SEric Beckmann bool &IsNewTypeString) { 21772fb6a87SEric Beckmann if (Entry.checkTypeString()) 21813017597SEric Beckmann return addChild(Entry.getTypeString(), IsNewTypeString); 21972fb6a87SEric Beckmann else 22072fb6a87SEric Beckmann return addChild(Entry.getTypeID()); 22172fb6a87SEric Beckmann } 22272fb6a87SEric Beckmann 22372fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 22413017597SEric Beckmann WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry, 22513017597SEric Beckmann bool &IsNewNameString) { 22672fb6a87SEric Beckmann if (Entry.checkNameString()) 22713017597SEric Beckmann return addChild(Entry.getNameString(), IsNewNameString); 22872fb6a87SEric Beckmann else 22972fb6a87SEric Beckmann return addChild(Entry.getNameID()); 23072fb6a87SEric Beckmann } 23172fb6a87SEric Beckmann 23272fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 23372fb6a87SEric Beckmann WindowsResourceParser::TreeNode::addLanguageNode( 23472fb6a87SEric Beckmann const ResourceEntryRef &Entry) { 235d9de6389SEric Beckmann return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(), 236d9de6389SEric Beckmann Entry.getMinorVersion(), Entry.getCharacteristics()); 23772fb6a87SEric Beckmann } 23872fb6a87SEric Beckmann 239d9de6389SEric Beckmann WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild( 240d9de6389SEric Beckmann uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion, 241d9de6389SEric Beckmann uint32_t Characteristics) { 24272fb6a87SEric Beckmann auto Child = IDChildren.find(ID); 24372fb6a87SEric Beckmann if (Child == IDChildren.end()) { 244d9de6389SEric Beckmann auto NewChild = 245d9de6389SEric Beckmann IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics) 246d9de6389SEric Beckmann : createIDNode(); 24772fb6a87SEric Beckmann WindowsResourceParser::TreeNode &Node = *NewChild; 24872fb6a87SEric Beckmann IDChildren.emplace(ID, std::move(NewChild)); 24972fb6a87SEric Beckmann return Node; 25072fb6a87SEric Beckmann } else 25172fb6a87SEric Beckmann return *(Child->second); 25272fb6a87SEric Beckmann } 25372fb6a87SEric Beckmann 25472fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 25513017597SEric Beckmann WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef, 25613017597SEric Beckmann bool &IsNewString) { 25772fb6a87SEric Beckmann std::string NameString; 25872fb6a87SEric Beckmann ArrayRef<UTF16> CorrectedName; 25972fb6a87SEric Beckmann std::vector<UTF16> EndianCorrectedName; 2607687f046SEric Beckmann if (sys::IsBigEndianHost) { 26172fb6a87SEric Beckmann EndianCorrectedName.resize(NameRef.size() + 1); 26272fb6a87SEric Beckmann std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1); 26372fb6a87SEric Beckmann EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; 26472fb6a87SEric Beckmann CorrectedName = makeArrayRef(EndianCorrectedName); 26572fb6a87SEric Beckmann } else 26672fb6a87SEric Beckmann CorrectedName = NameRef; 2677687f046SEric Beckmann convertUTF16ToUTF8String(CorrectedName, NameString); 26872fb6a87SEric Beckmann 26972fb6a87SEric Beckmann auto Child = StringChildren.find(NameString); 27072fb6a87SEric Beckmann if (Child == StringChildren.end()) { 271d9de6389SEric Beckmann auto NewChild = createStringNode(); 27213017597SEric Beckmann IsNewString = true; 27372fb6a87SEric Beckmann WindowsResourceParser::TreeNode &Node = *NewChild; 27472fb6a87SEric Beckmann StringChildren.emplace(NameString, std::move(NewChild)); 27572fb6a87SEric Beckmann return Node; 27672fb6a87SEric Beckmann } else 27772fb6a87SEric Beckmann return *(Child->second); 27872fb6a87SEric Beckmann } 27972fb6a87SEric Beckmann 28072fb6a87SEric Beckmann void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, 28172fb6a87SEric Beckmann StringRef Name) const { 28272fb6a87SEric Beckmann ListScope NodeScope(Writer, Name); 28372fb6a87SEric Beckmann for (auto const &Child : StringChildren) { 28472fb6a87SEric Beckmann Child.second->print(Writer, Child.first); 28572fb6a87SEric Beckmann } 28672fb6a87SEric Beckmann for (auto const &Child : IDChildren) { 287ba395ef4SEric Beckmann Child.second->print(Writer, to_string(Child.first)); 28872fb6a87SEric Beckmann } 28972fb6a87SEric Beckmann } 29072fb6a87SEric Beckmann 291d9de6389SEric Beckmann // This function returns the size of the entire resource tree, including 292d9de6389SEric Beckmann // directory tables, directory entries, and data entries. It does not include 293d9de6389SEric Beckmann // the directory strings or the relocations of the .rsrc section. 294d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { 295d9de6389SEric Beckmann uint32_t Size = (IDChildren.size() + StringChildren.size()) * 2967687f046SEric Beckmann sizeof(coff_resource_dir_entry); 297d9de6389SEric Beckmann 298d9de6389SEric Beckmann // Reached a node pointing to a data entry. 299d9de6389SEric Beckmann if (IsDataNode) { 3007687f046SEric Beckmann Size += sizeof(coff_resource_data_entry); 301d9de6389SEric Beckmann return Size; 302d9de6389SEric Beckmann } 303d9de6389SEric Beckmann 304d9de6389SEric Beckmann // If the node does not point to data, it must have a directory table pointing 305d9de6389SEric Beckmann // to other nodes. 3067687f046SEric Beckmann Size += sizeof(coff_resource_dir_table); 307d9de6389SEric Beckmann 308d9de6389SEric Beckmann for (auto const &Child : StringChildren) { 309d9de6389SEric Beckmann Size += Child.second->getTreeSize(); 310d9de6389SEric Beckmann } 311d9de6389SEric Beckmann for (auto const &Child : IDChildren) { 312d9de6389SEric Beckmann Size += Child.second->getTreeSize(); 313d9de6389SEric Beckmann } 314d9de6389SEric Beckmann return Size; 315d9de6389SEric Beckmann } 316d9de6389SEric Beckmann 317d9de6389SEric Beckmann class WindowsResourceCOFFWriter { 318d9de6389SEric Beckmann public: 319ddcfbf7dSEric Beckmann WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, 320d9de6389SEric Beckmann const WindowsResourceParser &Parser, Error &E); 321ddcfbf7dSEric Beckmann std::unique_ptr<MemoryBuffer> write(); 322d9de6389SEric Beckmann 323d9de6389SEric Beckmann private: 324d9de6389SEric Beckmann void performFileLayout(); 325d9de6389SEric Beckmann void performSectionOneLayout(); 326d9de6389SEric Beckmann void performSectionTwoLayout(); 327d9de6389SEric Beckmann void writeCOFFHeader(); 328d9de6389SEric Beckmann void writeFirstSectionHeader(); 329d9de6389SEric Beckmann void writeSecondSectionHeader(); 330d9de6389SEric Beckmann void writeFirstSection(); 331d9de6389SEric Beckmann void writeSecondSection(); 332d9de6389SEric Beckmann void writeSymbolTable(); 333d9de6389SEric Beckmann void writeStringTable(); 334d9de6389SEric Beckmann void writeDirectoryTree(); 335d9de6389SEric Beckmann void writeDirectoryStringTable(); 336d9de6389SEric Beckmann void writeFirstSectionRelocations(); 337ddcfbf7dSEric Beckmann std::unique_ptr<MemoryBuffer> OutputBuffer; 338d135e8c0SEric Beckmann char *BufferStart; 339382eaabbSEric Beckmann uint64_t CurrentOffset = 0; 3400eafa581SEric Beckmann COFF::MachineTypes MachineType; 341d9de6389SEric Beckmann const WindowsResourceParser::TreeNode &Resources; 342d9de6389SEric Beckmann const ArrayRef<std::vector<uint8_t>> Data; 343d9de6389SEric Beckmann uint64_t FileSize; 344d9de6389SEric Beckmann uint32_t SymbolTableOffset; 345d9de6389SEric Beckmann uint32_t SectionOneSize; 346d9de6389SEric Beckmann uint32_t SectionOneOffset; 347d9de6389SEric Beckmann uint32_t SectionOneRelocations; 348d9de6389SEric Beckmann uint32_t SectionTwoSize; 349d9de6389SEric Beckmann uint32_t SectionTwoOffset; 350d9de6389SEric Beckmann const ArrayRef<std::vector<UTF16>> StringTable; 351d9de6389SEric Beckmann std::vector<uint32_t> StringTableOffsets; 352d9de6389SEric Beckmann std::vector<uint32_t> DataOffsets; 353d9de6389SEric Beckmann std::vector<uint32_t> RelocationAddresses; 354d9de6389SEric Beckmann }; 355d9de6389SEric Beckmann 356d9de6389SEric Beckmann WindowsResourceCOFFWriter::WindowsResourceCOFFWriter( 357ddcfbf7dSEric Beckmann COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, 358ddcfbf7dSEric Beckmann Error &E) 359ddcfbf7dSEric Beckmann : MachineType(MachineType), Resources(Parser.getTree()), 360ddcfbf7dSEric Beckmann Data(Parser.getData()), StringTable(Parser.getStringTable()) { 361d9de6389SEric Beckmann performFileLayout(); 362c8dba240SEric Beckmann 36374b4ded0SBenjamin Kramer OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize); 364d9de6389SEric Beckmann } 365d9de6389SEric Beckmann 366d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performFileLayout() { 367d9de6389SEric Beckmann // Add size of COFF header. 3687687f046SEric Beckmann FileSize = COFF::Header16Size; 369d9de6389SEric Beckmann 370d9de6389SEric Beckmann // one .rsrc section header for directory tree, another for resource data. 3717687f046SEric Beckmann FileSize += 2 * COFF::SectionSize; 372d9de6389SEric Beckmann 373d9de6389SEric Beckmann performSectionOneLayout(); 374d9de6389SEric Beckmann performSectionTwoLayout(); 375d9de6389SEric Beckmann 376d9de6389SEric Beckmann // We have reached the address of the symbol table. 377d9de6389SEric Beckmann SymbolTableOffset = FileSize; 378d9de6389SEric Beckmann 3797687f046SEric Beckmann FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol. 3807687f046SEric Beckmann FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section. 3817687f046SEric Beckmann FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource. 382d9de6389SEric Beckmann FileSize += 4; // four null bytes for the string table. 383d9de6389SEric Beckmann } 384d9de6389SEric Beckmann 385d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionOneLayout() { 386d9de6389SEric Beckmann SectionOneOffset = FileSize; 387d9de6389SEric Beckmann 388d9de6389SEric Beckmann SectionOneSize = Resources.getTreeSize(); 389d9de6389SEric Beckmann uint32_t CurrentStringOffset = SectionOneSize; 390d9de6389SEric Beckmann uint32_t TotalStringTableSize = 0; 391d9de6389SEric Beckmann for (auto const &String : StringTable) { 392d9de6389SEric Beckmann StringTableOffsets.push_back(CurrentStringOffset); 393d9de6389SEric Beckmann uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t); 394d9de6389SEric Beckmann CurrentStringOffset += StringSize; 395d9de6389SEric Beckmann TotalStringTableSize += StringSize; 396d9de6389SEric Beckmann } 397d9de6389SEric Beckmann SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t)); 398d9de6389SEric Beckmann 399d9de6389SEric Beckmann // account for the relocations of section one. 400d9de6389SEric Beckmann SectionOneRelocations = FileSize + SectionOneSize; 401d9de6389SEric Beckmann FileSize += SectionOneSize; 4027687f046SEric Beckmann FileSize += 4037687f046SEric Beckmann Data.size() * COFF::RelocationSize; // one relocation for each resource. 404382eaabbSEric Beckmann FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 405d9de6389SEric Beckmann } 406d9de6389SEric Beckmann 407d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionTwoLayout() { 408d9de6389SEric Beckmann // add size of .rsrc$2 section, which contains all resource data on 8-byte 409d9de6389SEric Beckmann // alignment. 410d9de6389SEric Beckmann SectionTwoOffset = FileSize; 411d9de6389SEric Beckmann SectionTwoSize = 0; 412d9de6389SEric Beckmann for (auto const &Entry : Data) { 413d9de6389SEric Beckmann DataOffsets.push_back(SectionTwoSize); 4147687f046SEric Beckmann SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t)); 415d9de6389SEric Beckmann } 416d9de6389SEric Beckmann FileSize += SectionTwoSize; 417382eaabbSEric Beckmann FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 418d9de6389SEric Beckmann } 419d9de6389SEric Beckmann 420d9de6389SEric Beckmann static std::time_t getTime() { 421d9de6389SEric Beckmann std::time_t Now = time(nullptr); 422d9de6389SEric Beckmann if (Now < 0 || !isUInt<32>(Now)) 423d9de6389SEric Beckmann return UINT32_MAX; 424d9de6389SEric Beckmann return Now; 425d9de6389SEric Beckmann } 426d9de6389SEric Beckmann 427ddcfbf7dSEric Beckmann std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() { 428d135e8c0SEric Beckmann BufferStart = const_cast<char *>(OutputBuffer->getBufferStart()); 429d9de6389SEric Beckmann 430d9de6389SEric Beckmann writeCOFFHeader(); 431d9de6389SEric Beckmann writeFirstSectionHeader(); 432d9de6389SEric Beckmann writeSecondSectionHeader(); 433d9de6389SEric Beckmann writeFirstSection(); 434d9de6389SEric Beckmann writeSecondSection(); 435d9de6389SEric Beckmann writeSymbolTable(); 436d9de6389SEric Beckmann writeStringTable(); 437d9de6389SEric Beckmann 438ddcfbf7dSEric Beckmann return std::move(OutputBuffer); 439d9de6389SEric Beckmann } 440d9de6389SEric Beckmann 441d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeCOFFHeader() { 442d9de6389SEric Beckmann // Write the COFF header. 4437687f046SEric Beckmann auto *Header = reinterpret_cast<coff_file_header *>(BufferStart); 444ba664c1dSMartin Storsjo Header->Machine = MachineType; 445d9de6389SEric Beckmann Header->NumberOfSections = 2; 446d9de6389SEric Beckmann Header->TimeDateStamp = getTime(); 447d9de6389SEric Beckmann Header->PointerToSymbolTable = SymbolTableOffset; 448d9de6389SEric Beckmann // One symbol for every resource plus 2 for each section and @feat.00 449d9de6389SEric Beckmann Header->NumberOfSymbols = Data.size() + 5; 450d9de6389SEric Beckmann Header->SizeOfOptionalHeader = 0; 4517687f046SEric Beckmann Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; 452d9de6389SEric Beckmann } 453d9de6389SEric Beckmann 454d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionHeader() { 455d9de6389SEric Beckmann // Write the first section header. 4567687f046SEric Beckmann CurrentOffset += sizeof(coff_file_header); 4577687f046SEric Beckmann auto *SectionOneHeader = 4587687f046SEric Beckmann reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 4597687f046SEric Beckmann strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize); 460d9de6389SEric Beckmann SectionOneHeader->VirtualSize = 0; 461d9de6389SEric Beckmann SectionOneHeader->VirtualAddress = 0; 462d9de6389SEric Beckmann SectionOneHeader->SizeOfRawData = SectionOneSize; 463d9de6389SEric Beckmann SectionOneHeader->PointerToRawData = SectionOneOffset; 464d9de6389SEric Beckmann SectionOneHeader->PointerToRelocations = SectionOneRelocations; 465d9de6389SEric Beckmann SectionOneHeader->PointerToLinenumbers = 0; 466d9de6389SEric Beckmann SectionOneHeader->NumberOfRelocations = Data.size(); 467d9de6389SEric Beckmann SectionOneHeader->NumberOfLinenumbers = 0; 4687687f046SEric Beckmann SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 4697687f046SEric Beckmann SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 470d9de6389SEric Beckmann } 471d9de6389SEric Beckmann 472d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSectionHeader() { 473d9de6389SEric Beckmann // Write the second section header. 4747687f046SEric Beckmann CurrentOffset += sizeof(coff_section); 4757687f046SEric Beckmann auto *SectionTwoHeader = 4767687f046SEric Beckmann reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 4777687f046SEric Beckmann strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize); 478d9de6389SEric Beckmann SectionTwoHeader->VirtualSize = 0; 479d9de6389SEric Beckmann SectionTwoHeader->VirtualAddress = 0; 480d9de6389SEric Beckmann SectionTwoHeader->SizeOfRawData = SectionTwoSize; 481d9de6389SEric Beckmann SectionTwoHeader->PointerToRawData = SectionTwoOffset; 482d9de6389SEric Beckmann SectionTwoHeader->PointerToRelocations = 0; 483d9de6389SEric Beckmann SectionTwoHeader->PointerToLinenumbers = 0; 484d9de6389SEric Beckmann SectionTwoHeader->NumberOfRelocations = 0; 485d9de6389SEric Beckmann SectionTwoHeader->NumberOfLinenumbers = 0; 4867687f046SEric Beckmann SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 4877687f046SEric Beckmann SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 488d9de6389SEric Beckmann } 489d9de6389SEric Beckmann 490d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSection() { 491d9de6389SEric Beckmann // Write section one. 4927687f046SEric Beckmann CurrentOffset += sizeof(coff_section); 493d9de6389SEric Beckmann 494d9de6389SEric Beckmann writeDirectoryTree(); 495d9de6389SEric Beckmann writeDirectoryStringTable(); 496d9de6389SEric Beckmann writeFirstSectionRelocations(); 497382eaabbSEric Beckmann 498382eaabbSEric Beckmann CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 499d9de6389SEric Beckmann } 500d9de6389SEric Beckmann 501d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSection() { 502d9de6389SEric Beckmann // Now write the .rsrc$02 section. 503d9de6389SEric Beckmann for (auto const &RawDataEntry : Data) { 504382eaabbSEric Beckmann std::copy(RawDataEntry.begin(), RawDataEntry.end(), 505382eaabbSEric Beckmann BufferStart + CurrentOffset); 506382eaabbSEric Beckmann CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t)); 507d9de6389SEric Beckmann } 508382eaabbSEric Beckmann 509382eaabbSEric Beckmann CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 510d9de6389SEric Beckmann } 511d9de6389SEric Beckmann 512d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSymbolTable() { 513d9de6389SEric Beckmann // Now write the symbol table. 514d9de6389SEric Beckmann // First, the feat symbol. 5157687f046SEric Beckmann auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 5167687f046SEric Beckmann strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize); 517d9de6389SEric Beckmann Symbol->Value = 0x11; 518d9de6389SEric Beckmann Symbol->SectionNumber = 0xffff; 5197687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5207687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 521d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 0; 5227687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 523d9de6389SEric Beckmann 524d9de6389SEric Beckmann // Now write the .rsrc1 symbol + aux. 5257687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 5267687f046SEric Beckmann strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize); 527d9de6389SEric Beckmann Symbol->Value = 0; 528d9de6389SEric Beckmann Symbol->SectionNumber = 1; 5297687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5307687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 531d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 1; 5327687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 5337687f046SEric Beckmann auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 5347687f046SEric Beckmann CurrentOffset); 535d9de6389SEric Beckmann Aux->Length = SectionOneSize; 536d9de6389SEric Beckmann Aux->NumberOfRelocations = Data.size(); 537d9de6389SEric Beckmann Aux->NumberOfLinenumbers = 0; 538d9de6389SEric Beckmann Aux->CheckSum = 0; 539d9de6389SEric Beckmann Aux->NumberLowPart = 0; 540d9de6389SEric Beckmann Aux->Selection = 0; 5417687f046SEric Beckmann CurrentOffset += sizeof(coff_aux_section_definition); 542d9de6389SEric Beckmann 543d9de6389SEric Beckmann // Now write the .rsrc2 symbol + aux. 5447687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 5457687f046SEric Beckmann strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize); 546d9de6389SEric Beckmann Symbol->Value = 0; 547d9de6389SEric Beckmann Symbol->SectionNumber = 2; 5487687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5497687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 550d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 1; 5517687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 5527687f046SEric Beckmann Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 5537687f046SEric Beckmann CurrentOffset); 554d9de6389SEric Beckmann Aux->Length = SectionTwoSize; 555d9de6389SEric Beckmann Aux->NumberOfRelocations = 0; 556d9de6389SEric Beckmann Aux->NumberOfLinenumbers = 0; 557d9de6389SEric Beckmann Aux->CheckSum = 0; 558d9de6389SEric Beckmann Aux->NumberLowPart = 0; 559d9de6389SEric Beckmann Aux->Selection = 0; 5607687f046SEric Beckmann CurrentOffset += sizeof(coff_aux_section_definition); 561d9de6389SEric Beckmann 562d9de6389SEric Beckmann // Now write a symbol for each relocation. 563d9de6389SEric Beckmann for (unsigned i = 0; i < Data.size(); i++) { 564*ea5ff9faSBob Haarman auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>(); 5657687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 566*ea5ff9faSBob Haarman memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize); 567d9de6389SEric Beckmann Symbol->Value = DataOffsets[i]; 568e44afc4aSEric Beckmann Symbol->SectionNumber = 2; 5697687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5707687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 571d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 0; 5727687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 573d9de6389SEric Beckmann } 574d9de6389SEric Beckmann } 575d9de6389SEric Beckmann 576d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeStringTable() { 577d9de6389SEric Beckmann // Just 4 null bytes for the string table. 57833866334SEric Beckmann auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset); 57933866334SEric Beckmann memset(COFFStringTable, 0, 4); 580d9de6389SEric Beckmann } 581d9de6389SEric Beckmann 582d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryTree() { 583d9de6389SEric Beckmann // Traverse parsed resource tree breadth-first and write the corresponding 584d9de6389SEric Beckmann // COFF objects. 585d9de6389SEric Beckmann std::queue<const WindowsResourceParser::TreeNode *> Queue; 586d9de6389SEric Beckmann Queue.push(&Resources); 5877687f046SEric Beckmann uint32_t NextLevelOffset = 5887687f046SEric Beckmann sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() + 589d9de6389SEric Beckmann Resources.getIDChildren().size()) * 5907687f046SEric Beckmann sizeof(coff_resource_dir_entry); 591d9de6389SEric Beckmann std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder; 592d9de6389SEric Beckmann uint32_t CurrentRelativeOffset = 0; 593d9de6389SEric Beckmann 594d9de6389SEric Beckmann while (!Queue.empty()) { 595d9de6389SEric Beckmann auto CurrentNode = Queue.front(); 596d9de6389SEric Beckmann Queue.pop(); 5977687f046SEric Beckmann auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart + 5987687f046SEric Beckmann CurrentOffset); 599d9de6389SEric Beckmann Table->Characteristics = CurrentNode->getCharacteristics(); 600d9de6389SEric Beckmann Table->TimeDateStamp = 0; 601d9de6389SEric Beckmann Table->MajorVersion = CurrentNode->getMajorVersion(); 602d9de6389SEric Beckmann Table->MinorVersion = CurrentNode->getMinorVersion(); 603d9de6389SEric Beckmann auto &IDChildren = CurrentNode->getIDChildren(); 604d9de6389SEric Beckmann auto &StringChildren = CurrentNode->getStringChildren(); 605d9de6389SEric Beckmann Table->NumberOfNameEntries = StringChildren.size(); 606d9de6389SEric Beckmann Table->NumberOfIDEntries = IDChildren.size(); 6077687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_table); 6087687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_table); 609d9de6389SEric Beckmann 610d9de6389SEric Beckmann // Write the directory entries immediately following each directory table. 611d9de6389SEric Beckmann for (auto const &Child : StringChildren) { 6127687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 6137687f046SEric Beckmann CurrentOffset); 6147c865f00SEric Beckmann Entry->Identifier.setNameOffset( 6157c865f00SEric Beckmann StringTableOffsets[Child.second->getStringIndex()]); 616d9de6389SEric Beckmann if (Child.second->checkIsDataNode()) { 617d9de6389SEric Beckmann Entry->Offset.DataEntryOffset = NextLevelOffset; 6187687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_data_entry); 619d9de6389SEric Beckmann DataEntriesTreeOrder.push_back(Child.second.get()); 620d9de6389SEric Beckmann } else { 621d9de6389SEric Beckmann Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 6227687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_dir_table) + 623d9de6389SEric Beckmann (Child.second->getStringChildren().size() + 624d9de6389SEric Beckmann Child.second->getIDChildren().size()) * 6257687f046SEric Beckmann sizeof(coff_resource_dir_entry); 626d9de6389SEric Beckmann Queue.push(Child.second.get()); 627d9de6389SEric Beckmann } 6287687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_entry); 6297687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 630d9de6389SEric Beckmann } 631d9de6389SEric Beckmann for (auto const &Child : IDChildren) { 6327687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 6337687f046SEric Beckmann CurrentOffset); 634d9de6389SEric Beckmann Entry->Identifier.ID = Child.first; 635d9de6389SEric Beckmann if (Child.second->checkIsDataNode()) { 636d9de6389SEric Beckmann Entry->Offset.DataEntryOffset = NextLevelOffset; 6377687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_data_entry); 638d9de6389SEric Beckmann DataEntriesTreeOrder.push_back(Child.second.get()); 639d9de6389SEric Beckmann } else { 640d9de6389SEric Beckmann Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 6417687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_dir_table) + 642d9de6389SEric Beckmann (Child.second->getStringChildren().size() + 643d9de6389SEric Beckmann Child.second->getIDChildren().size()) * 6447687f046SEric Beckmann sizeof(coff_resource_dir_entry); 645d9de6389SEric Beckmann Queue.push(Child.second.get()); 646d9de6389SEric Beckmann } 6477687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_entry); 6487687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 649d9de6389SEric Beckmann } 650d9de6389SEric Beckmann } 651d9de6389SEric Beckmann 652d9de6389SEric Beckmann RelocationAddresses.resize(Data.size()); 653d9de6389SEric Beckmann // Now write all the resource data entries. 654d9de6389SEric Beckmann for (auto DataNodes : DataEntriesTreeOrder) { 6557687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart + 6567687f046SEric Beckmann CurrentOffset); 657d9de6389SEric Beckmann RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset; 658d9de6389SEric Beckmann Entry->DataRVA = 0; // Set to zero because it is a relocation. 659d9de6389SEric Beckmann Entry->DataSize = Data[DataNodes->getDataIndex()].size(); 660d9de6389SEric Beckmann Entry->Codepage = 0; 661d9de6389SEric Beckmann Entry->Reserved = 0; 6627687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_data_entry); 6637687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_data_entry); 664d9de6389SEric Beckmann } 665d9de6389SEric Beckmann } 666d9de6389SEric Beckmann 667d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryStringTable() { 668d9de6389SEric Beckmann // Now write the directory string table for .rsrc$01 669d9de6389SEric Beckmann uint32_t TotalStringTableSize = 0; 6700096d78bSEric Beckmann for (auto &String : StringTable) { 671d9de6389SEric Beckmann uint16_t Length = String.size(); 6721f76ca5aSEric Beckmann support::endian::write16le(BufferStart + CurrentOffset, Length); 673382eaabbSEric Beckmann CurrentOffset += sizeof(uint16_t); 674382eaabbSEric Beckmann auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset); 675d9de6389SEric Beckmann std::copy(String.begin(), String.end(), Start); 676382eaabbSEric Beckmann CurrentOffset += Length * sizeof(UTF16); 677d9de6389SEric Beckmann TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t); 678d9de6389SEric Beckmann } 679382eaabbSEric Beckmann CurrentOffset += 680d9de6389SEric Beckmann alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize; 681d9de6389SEric Beckmann } 682d9de6389SEric Beckmann 683d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { 684d9de6389SEric Beckmann 685d9de6389SEric Beckmann // Now write the relocations for .rsrc$01 686d9de6389SEric Beckmann // Five symbols already in table before we start, @feat.00 and 2 for each 687d9de6389SEric Beckmann // .rsrc section. 688d9de6389SEric Beckmann uint32_t NextSymbolIndex = 5; 689d9de6389SEric Beckmann for (unsigned i = 0; i < Data.size(); i++) { 6907687f046SEric Beckmann auto *Reloc = 6917687f046SEric Beckmann reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset); 692d9de6389SEric Beckmann Reloc->VirtualAddress = RelocationAddresses[i]; 693d9de6389SEric Beckmann Reloc->SymbolTableIndex = NextSymbolIndex++; 694d9de6389SEric Beckmann switch (MachineType) { 695d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_ARMNT: 6967687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB; 697d9de6389SEric Beckmann break; 698d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_AMD64: 6997687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB; 700d9de6389SEric Beckmann break; 701d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_I386: 7027687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; 703d9de6389SEric Beckmann break; 704ba664c1dSMartin Storsjo case COFF::IMAGE_FILE_MACHINE_ARM64: 705ba664c1dSMartin Storsjo Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB; 706ba664c1dSMartin Storsjo break; 707d9de6389SEric Beckmann default: 708ba664c1dSMartin Storsjo llvm_unreachable("unknown machine type"); 709d9de6389SEric Beckmann } 7107687f046SEric Beckmann CurrentOffset += sizeof(coff_relocation); 711d9de6389SEric Beckmann } 712d9de6389SEric Beckmann } 713d9de6389SEric Beckmann 714ddcfbf7dSEric Beckmann Expected<std::unique_ptr<MemoryBuffer>> 715ddcfbf7dSEric Beckmann writeWindowsResourceCOFF(COFF::MachineTypes MachineType, 716d9de6389SEric Beckmann const WindowsResourceParser &Parser) { 717d9de6389SEric Beckmann Error E = Error::success(); 718ddcfbf7dSEric Beckmann WindowsResourceCOFFWriter Writer(MachineType, Parser, E); 719d9de6389SEric Beckmann if (E) 720ddcfbf7dSEric Beckmann return std::move(E); 721d9de6389SEric Beckmann return Writer.write(); 722d9de6389SEric Beckmann } 723d9de6389SEric Beckmann 724a6bdf751SEric Beckmann } // namespace object 725a6bdf751SEric Beckmann } // namespace llvm 726