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" 17d9de6389SEric Beckmann #include "llvm/Support/MathExtras.h" 18d9de6389SEric Beckmann #include <ctime> 19d9de6389SEric Beckmann #include <queue> 20ba395ef4SEric Beckmann #include <sstream> 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 39f1c3beecSDavid Blaikie static const size_t ResourceMagicSize = 16; 40a6bdf751SEric Beckmann 41f1c3beecSDavid Blaikie static const size_t NullEntrySize = 16; 42a6bdf751SEric Beckmann 43d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::StringCount = 0; 44d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::DataCount = 0; 45d9de6389SEric Beckmann 46a6bdf751SEric Beckmann WindowsResource::WindowsResource(MemoryBufferRef Source) 47a6bdf751SEric Beckmann : Binary(Binary::ID_WinRes, Source) { 48f1c3beecSDavid Blaikie size_t LeadingSize = ResourceMagicSize + NullEntrySize; 49a6bdf751SEric Beckmann BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize), 50a6bdf751SEric Beckmann support::little); 51a6bdf751SEric Beckmann } 52a6bdf751SEric Beckmann 53a6bdf751SEric Beckmann Expected<std::unique_ptr<WindowsResource>> 54a6bdf751SEric Beckmann WindowsResource::createWindowsResource(MemoryBufferRef Source) { 55f1c3beecSDavid Blaikie if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize) 56a6bdf751SEric Beckmann return make_error<GenericBinaryError>( 57a6bdf751SEric Beckmann "File too small to be a resource file", 58a6bdf751SEric Beckmann object_error::invalid_file_type); 59a6bdf751SEric Beckmann std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source)); 60a6bdf751SEric Beckmann return std::move(Ret); 61a6bdf751SEric Beckmann } 62a6bdf751SEric Beckmann 63a6bdf751SEric Beckmann Expected<ResourceEntryRef> WindowsResource::getHeadEntry() { 64a6bdf751SEric Beckmann Error Err = Error::success(); 65a6bdf751SEric Beckmann auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err); 66a6bdf751SEric Beckmann if (Err) 67a6bdf751SEric Beckmann return std::move(Err); 68a6bdf751SEric Beckmann return Ref; 69a6bdf751SEric Beckmann } 70a6bdf751SEric Beckmann 71a6bdf751SEric Beckmann ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, 72a6bdf751SEric Beckmann const WindowsResource *Owner, Error &Err) 73a6bdf751SEric Beckmann : Reader(Ref), OwningRes(Owner) { 74a6bdf751SEric Beckmann if (loadNext()) 75907fb813SEric Beckmann Err = make_error<GenericBinaryError>("Could not read first entry.\n", 76a6bdf751SEric Beckmann object_error::unexpected_eof); 77a6bdf751SEric Beckmann } 78a6bdf751SEric Beckmann 79a6bdf751SEric Beckmann Error ResourceEntryRef::moveNext(bool &End) { 80a6bdf751SEric Beckmann // Reached end of all the entries. 81a6bdf751SEric Beckmann if (Reader.bytesRemaining() == 0) { 82a6bdf751SEric Beckmann End = true; 83a6bdf751SEric Beckmann return Error::success(); 84a6bdf751SEric Beckmann } 85a6bdf751SEric Beckmann RETURN_IF_ERROR(loadNext()); 86a6bdf751SEric Beckmann 87a6bdf751SEric Beckmann return Error::success(); 88a6bdf751SEric Beckmann } 89a6bdf751SEric Beckmann 9072fb6a87SEric Beckmann static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, 9172fb6a87SEric Beckmann ArrayRef<UTF16> &Str, bool &IsString) { 9272fb6a87SEric Beckmann uint16_t IDFlag; 9372fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(IDFlag)); 9472fb6a87SEric Beckmann IsString = IDFlag != 0xffff; 9572fb6a87SEric Beckmann 9672fb6a87SEric Beckmann if (IsString) { 9772fb6a87SEric Beckmann Reader.setOffset( 9872fb6a87SEric Beckmann Reader.getOffset() - 9972fb6a87SEric Beckmann sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. 10072fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readWideString(Str)); 10172fb6a87SEric Beckmann } else 10272fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(ID)); 10372fb6a87SEric Beckmann 10472fb6a87SEric Beckmann return Error::success(); 10572fb6a87SEric Beckmann } 10672fb6a87SEric Beckmann 107a6bdf751SEric Beckmann Error ResourceEntryRef::loadNext() { 108a6bdf751SEric Beckmann uint32_t DataSize; 109a6bdf751SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(DataSize)); 110a6bdf751SEric Beckmann uint32_t HeaderSize; 111a6bdf751SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(HeaderSize)); 11272fb6a87SEric Beckmann 11372fb6a87SEric Beckmann if (HeaderSize < MIN_HEADER_SIZE) 11472fb6a87SEric Beckmann return make_error<GenericBinaryError>("Header size is too small.", 11572fb6a87SEric Beckmann object_error::parse_failed); 11672fb6a87SEric Beckmann 11772fb6a87SEric Beckmann RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); 11872fb6a87SEric Beckmann 11972fb6a87SEric Beckmann RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); 12072fb6a87SEric Beckmann 121a6bdf751SEric Beckmann RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); 12272fb6a87SEric Beckmann 12372fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readObject(Suffix)); 12472fb6a87SEric Beckmann 12572fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readArray(Data, DataSize)); 12672fb6a87SEric Beckmann 12772fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); 12872fb6a87SEric Beckmann 129a6bdf751SEric Beckmann return Error::success(); 130a6bdf751SEric Beckmann } 131a6bdf751SEric Beckmann 132d9de6389SEric Beckmann WindowsResourceParser::WindowsResourceParser() : Root(false) {} 13372fb6a87SEric Beckmann 13472fb6a87SEric Beckmann Error WindowsResourceParser::parse(WindowsResource *WR) { 13572fb6a87SEric Beckmann auto EntryOrErr = WR->getHeadEntry(); 13672fb6a87SEric Beckmann if (!EntryOrErr) 13772fb6a87SEric Beckmann return EntryOrErr.takeError(); 13872fb6a87SEric Beckmann 13972fb6a87SEric Beckmann ResourceEntryRef Entry = EntryOrErr.get(); 14072fb6a87SEric Beckmann bool End = false; 14172fb6a87SEric Beckmann while (!End) { 142d9de6389SEric Beckmann Data.push_back(Entry.getData()); 143d9de6389SEric Beckmann 14413017597SEric Beckmann bool IsNewTypeString = false; 14513017597SEric Beckmann bool IsNewNameString = false; 14613017597SEric Beckmann 14713017597SEric Beckmann Root.addEntry(Entry, IsNewTypeString, IsNewNameString); 14813017597SEric Beckmann 14913017597SEric Beckmann if (IsNewTypeString) 150d9de6389SEric Beckmann StringTable.push_back(Entry.getTypeString()); 151d9de6389SEric Beckmann 15213017597SEric Beckmann if (IsNewNameString) 153d9de6389SEric Beckmann StringTable.push_back(Entry.getNameString()); 154d9de6389SEric Beckmann 15572fb6a87SEric Beckmann RETURN_IF_ERROR(Entry.moveNext(End)); 15672fb6a87SEric Beckmann } 15772fb6a87SEric Beckmann 15872fb6a87SEric Beckmann return Error::success(); 15972fb6a87SEric Beckmann } 16072fb6a87SEric Beckmann 161907fb813SEric Beckmann void WindowsResourceParser::printTree(raw_ostream &OS) const { 162907fb813SEric Beckmann ScopedPrinter Writer(OS); 16372fb6a87SEric Beckmann Root.print(Writer, "Resource Tree"); 16472fb6a87SEric Beckmann } 16572fb6a87SEric Beckmann 16613017597SEric Beckmann void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, 16713017597SEric Beckmann bool &IsNewTypeString, 16813017597SEric Beckmann bool &IsNewNameString) { 16913017597SEric Beckmann TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString); 17013017597SEric Beckmann TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString); 17172fb6a87SEric Beckmann NameNode.addLanguageNode(Entry); 17272fb6a87SEric Beckmann } 17372fb6a87SEric Beckmann 174d9de6389SEric Beckmann WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) { 175d9de6389SEric Beckmann if (IsStringNode) 176d9de6389SEric Beckmann StringIndex = StringCount++; 177d9de6389SEric Beckmann } 178d9de6389SEric Beckmann 179d9de6389SEric Beckmann WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, 180d9de6389SEric Beckmann uint16_t MinorVersion, 181d9de6389SEric Beckmann uint32_t Characteristics) 182d9de6389SEric Beckmann : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion), 183d9de6389SEric Beckmann Characteristics(Characteristics) { 184d9de6389SEric Beckmann DataIndex = DataCount++; 185d9de6389SEric Beckmann } 186d9de6389SEric Beckmann 187d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 188d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createStringNode() { 189d9de6389SEric Beckmann return std::unique_ptr<TreeNode>(new TreeNode(true)); 190d9de6389SEric Beckmann } 191d9de6389SEric Beckmann 192d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 193d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createIDNode() { 194d9de6389SEric Beckmann return std::unique_ptr<TreeNode>(new TreeNode(false)); 195d9de6389SEric Beckmann } 196d9de6389SEric Beckmann 197d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 198d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, 199d9de6389SEric Beckmann uint16_t MinorVersion, 200d9de6389SEric Beckmann uint32_t Characteristics) { 201d9de6389SEric Beckmann return std::unique_ptr<TreeNode>( 202d9de6389SEric Beckmann new TreeNode(MajorVersion, MinorVersion, Characteristics)); 203d9de6389SEric Beckmann } 20472fb6a87SEric Beckmann 20572fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 20613017597SEric Beckmann WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry, 20713017597SEric Beckmann bool &IsNewTypeString) { 20872fb6a87SEric Beckmann if (Entry.checkTypeString()) 20913017597SEric Beckmann return addChild(Entry.getTypeString(), IsNewTypeString); 21072fb6a87SEric Beckmann else 21172fb6a87SEric Beckmann return addChild(Entry.getTypeID()); 21272fb6a87SEric Beckmann } 21372fb6a87SEric Beckmann 21472fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 21513017597SEric Beckmann WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry, 21613017597SEric Beckmann bool &IsNewNameString) { 21772fb6a87SEric Beckmann if (Entry.checkNameString()) 21813017597SEric Beckmann return addChild(Entry.getNameString(), IsNewNameString); 21972fb6a87SEric Beckmann else 22072fb6a87SEric Beckmann return addChild(Entry.getNameID()); 22172fb6a87SEric Beckmann } 22272fb6a87SEric Beckmann 22372fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 22472fb6a87SEric Beckmann WindowsResourceParser::TreeNode::addLanguageNode( 22572fb6a87SEric Beckmann const ResourceEntryRef &Entry) { 226d9de6389SEric Beckmann return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(), 227d9de6389SEric Beckmann Entry.getMinorVersion(), Entry.getCharacteristics()); 22872fb6a87SEric Beckmann } 22972fb6a87SEric Beckmann 230d9de6389SEric Beckmann WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild( 231d9de6389SEric Beckmann uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion, 232d9de6389SEric Beckmann uint32_t Characteristics) { 23372fb6a87SEric Beckmann auto Child = IDChildren.find(ID); 23472fb6a87SEric Beckmann if (Child == IDChildren.end()) { 235d9de6389SEric Beckmann auto NewChild = 236d9de6389SEric Beckmann IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics) 237d9de6389SEric Beckmann : createIDNode(); 23872fb6a87SEric Beckmann WindowsResourceParser::TreeNode &Node = *NewChild; 23972fb6a87SEric Beckmann IDChildren.emplace(ID, std::move(NewChild)); 24072fb6a87SEric Beckmann return Node; 24172fb6a87SEric Beckmann } else 24272fb6a87SEric Beckmann return *(Child->second); 24372fb6a87SEric Beckmann } 24472fb6a87SEric Beckmann 24572fb6a87SEric Beckmann WindowsResourceParser::TreeNode & 24613017597SEric Beckmann WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef, 24713017597SEric Beckmann bool &IsNewString) { 24872fb6a87SEric Beckmann std::string NameString; 24972fb6a87SEric Beckmann ArrayRef<UTF16> CorrectedName; 25072fb6a87SEric Beckmann std::vector<UTF16> EndianCorrectedName; 2517687f046SEric Beckmann if (sys::IsBigEndianHost) { 25272fb6a87SEric Beckmann EndianCorrectedName.resize(NameRef.size() + 1); 25372fb6a87SEric Beckmann std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1); 25472fb6a87SEric Beckmann EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; 25572fb6a87SEric Beckmann CorrectedName = makeArrayRef(EndianCorrectedName); 25672fb6a87SEric Beckmann } else 25772fb6a87SEric Beckmann CorrectedName = NameRef; 2587687f046SEric Beckmann convertUTF16ToUTF8String(CorrectedName, NameString); 25972fb6a87SEric Beckmann 26072fb6a87SEric Beckmann auto Child = StringChildren.find(NameString); 26172fb6a87SEric Beckmann if (Child == StringChildren.end()) { 262d9de6389SEric Beckmann auto NewChild = createStringNode(); 26313017597SEric Beckmann IsNewString = true; 26472fb6a87SEric Beckmann WindowsResourceParser::TreeNode &Node = *NewChild; 26572fb6a87SEric Beckmann StringChildren.emplace(NameString, std::move(NewChild)); 26672fb6a87SEric Beckmann return Node; 26772fb6a87SEric Beckmann } else 26872fb6a87SEric Beckmann return *(Child->second); 26972fb6a87SEric Beckmann } 27072fb6a87SEric Beckmann 27172fb6a87SEric Beckmann void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, 27272fb6a87SEric Beckmann StringRef Name) const { 27372fb6a87SEric Beckmann ListScope NodeScope(Writer, Name); 27472fb6a87SEric Beckmann for (auto const &Child : StringChildren) { 27572fb6a87SEric Beckmann Child.second->print(Writer, Child.first); 27672fb6a87SEric Beckmann } 27772fb6a87SEric Beckmann for (auto const &Child : IDChildren) { 278ba395ef4SEric Beckmann Child.second->print(Writer, to_string(Child.first)); 27972fb6a87SEric Beckmann } 28072fb6a87SEric Beckmann } 28172fb6a87SEric Beckmann 282d9de6389SEric Beckmann // This function returns the size of the entire resource tree, including 283d9de6389SEric Beckmann // directory tables, directory entries, and data entries. It does not include 284d9de6389SEric Beckmann // the directory strings or the relocations of the .rsrc section. 285d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { 286d9de6389SEric Beckmann uint32_t Size = (IDChildren.size() + StringChildren.size()) * 2877687f046SEric Beckmann sizeof(coff_resource_dir_entry); 288d9de6389SEric Beckmann 289d9de6389SEric Beckmann // Reached a node pointing to a data entry. 290d9de6389SEric Beckmann if (IsDataNode) { 2917687f046SEric Beckmann Size += sizeof(coff_resource_data_entry); 292d9de6389SEric Beckmann return Size; 293d9de6389SEric Beckmann } 294d9de6389SEric Beckmann 295d9de6389SEric Beckmann // If the node does not point to data, it must have a directory table pointing 296d9de6389SEric Beckmann // to other nodes. 2977687f046SEric Beckmann Size += sizeof(coff_resource_dir_table); 298d9de6389SEric Beckmann 299d9de6389SEric Beckmann for (auto const &Child : StringChildren) { 300d9de6389SEric Beckmann Size += Child.second->getTreeSize(); 301d9de6389SEric Beckmann } 302d9de6389SEric Beckmann for (auto const &Child : IDChildren) { 303d9de6389SEric Beckmann Size += Child.second->getTreeSize(); 304d9de6389SEric Beckmann } 305d9de6389SEric Beckmann return Size; 306d9de6389SEric Beckmann } 307d9de6389SEric Beckmann 308d9de6389SEric Beckmann class WindowsResourceCOFFWriter { 309d9de6389SEric Beckmann public: 310*ddcfbf7dSEric Beckmann WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, 311d9de6389SEric Beckmann const WindowsResourceParser &Parser, Error &E); 312*ddcfbf7dSEric Beckmann std::unique_ptr<MemoryBuffer> write(); 313d9de6389SEric Beckmann 314d9de6389SEric Beckmann private: 315d9de6389SEric Beckmann void performFileLayout(); 316d9de6389SEric Beckmann void performSectionOneLayout(); 317d9de6389SEric Beckmann void performSectionTwoLayout(); 318d9de6389SEric Beckmann void writeCOFFHeader(); 319d9de6389SEric Beckmann void writeFirstSectionHeader(); 320d9de6389SEric Beckmann void writeSecondSectionHeader(); 321d9de6389SEric Beckmann void writeFirstSection(); 322d9de6389SEric Beckmann void writeSecondSection(); 323d9de6389SEric Beckmann void writeSymbolTable(); 324d9de6389SEric Beckmann void writeStringTable(); 325d9de6389SEric Beckmann void writeDirectoryTree(); 326d9de6389SEric Beckmann void writeDirectoryStringTable(); 327d9de6389SEric Beckmann void writeFirstSectionRelocations(); 328*ddcfbf7dSEric Beckmann std::unique_ptr<MemoryBuffer> OutputBuffer; 329d135e8c0SEric Beckmann char *BufferStart; 330382eaabbSEric Beckmann uint64_t CurrentOffset = 0; 331d135e8c0SEric Beckmann COFF::MachineTypes MachineType; 332d9de6389SEric Beckmann const WindowsResourceParser::TreeNode &Resources; 333d9de6389SEric Beckmann const ArrayRef<std::vector<uint8_t>> Data; 334d9de6389SEric Beckmann uint64_t FileSize; 335d9de6389SEric Beckmann uint32_t SymbolTableOffset; 336d9de6389SEric Beckmann uint32_t SectionOneSize; 337d9de6389SEric Beckmann uint32_t SectionOneOffset; 338d9de6389SEric Beckmann uint32_t SectionOneRelocations; 339d9de6389SEric Beckmann uint32_t SectionTwoSize; 340d9de6389SEric Beckmann uint32_t SectionTwoOffset; 341d9de6389SEric Beckmann const ArrayRef<std::vector<UTF16>> StringTable; 342d9de6389SEric Beckmann std::vector<uint32_t> StringTableOffsets; 343d9de6389SEric Beckmann std::vector<uint32_t> DataOffsets; 344d9de6389SEric Beckmann std::vector<uint32_t> RelocationAddresses; 345d9de6389SEric Beckmann }; 346d9de6389SEric Beckmann 347d9de6389SEric Beckmann WindowsResourceCOFFWriter::WindowsResourceCOFFWriter( 348*ddcfbf7dSEric Beckmann COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, 349*ddcfbf7dSEric Beckmann Error &E) 350*ddcfbf7dSEric Beckmann : MachineType(MachineType), Resources(Parser.getTree()), 351*ddcfbf7dSEric Beckmann Data(Parser.getData()), StringTable(Parser.getStringTable()) { 352d9de6389SEric Beckmann performFileLayout(); 353d9de6389SEric Beckmann 35474b4ded0SBenjamin Kramer OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize); 355d9de6389SEric Beckmann } 356d9de6389SEric Beckmann 357d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performFileLayout() { 358d9de6389SEric Beckmann // Add size of COFF header. 3597687f046SEric Beckmann FileSize = COFF::Header16Size; 360d9de6389SEric Beckmann 361d9de6389SEric Beckmann // one .rsrc section header for directory tree, another for resource data. 3627687f046SEric Beckmann FileSize += 2 * COFF::SectionSize; 363d9de6389SEric Beckmann 364d9de6389SEric Beckmann performSectionOneLayout(); 365d9de6389SEric Beckmann performSectionTwoLayout(); 366d9de6389SEric Beckmann 367d9de6389SEric Beckmann // We have reached the address of the symbol table. 368d9de6389SEric Beckmann SymbolTableOffset = FileSize; 369d9de6389SEric Beckmann 3707687f046SEric Beckmann FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol. 3717687f046SEric Beckmann FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section. 3727687f046SEric Beckmann FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource. 373d9de6389SEric Beckmann FileSize += 4; // four null bytes for the string table. 374d9de6389SEric Beckmann } 375d9de6389SEric Beckmann 376d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionOneLayout() { 377d9de6389SEric Beckmann SectionOneOffset = FileSize; 378d9de6389SEric Beckmann 379d9de6389SEric Beckmann SectionOneSize = Resources.getTreeSize(); 380d9de6389SEric Beckmann uint32_t CurrentStringOffset = SectionOneSize; 381d9de6389SEric Beckmann uint32_t TotalStringTableSize = 0; 382d9de6389SEric Beckmann for (auto const &String : StringTable) { 383d9de6389SEric Beckmann StringTableOffsets.push_back(CurrentStringOffset); 384d9de6389SEric Beckmann uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t); 385d9de6389SEric Beckmann CurrentStringOffset += StringSize; 386d9de6389SEric Beckmann TotalStringTableSize += StringSize; 387d9de6389SEric Beckmann } 388d9de6389SEric Beckmann SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t)); 389d9de6389SEric Beckmann 390d9de6389SEric Beckmann // account for the relocations of section one. 391d9de6389SEric Beckmann SectionOneRelocations = FileSize + SectionOneSize; 392d9de6389SEric Beckmann FileSize += SectionOneSize; 3937687f046SEric Beckmann FileSize += 3947687f046SEric Beckmann Data.size() * COFF::RelocationSize; // one relocation for each resource. 395382eaabbSEric Beckmann FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 396d9de6389SEric Beckmann } 397d9de6389SEric Beckmann 398d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionTwoLayout() { 399d9de6389SEric Beckmann // add size of .rsrc$2 section, which contains all resource data on 8-byte 400d9de6389SEric Beckmann // alignment. 401d9de6389SEric Beckmann SectionTwoOffset = FileSize; 402d9de6389SEric Beckmann SectionTwoSize = 0; 403d9de6389SEric Beckmann for (auto const &Entry : Data) { 404d9de6389SEric Beckmann DataOffsets.push_back(SectionTwoSize); 4057687f046SEric Beckmann SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t)); 406d9de6389SEric Beckmann } 407d9de6389SEric Beckmann FileSize += SectionTwoSize; 408382eaabbSEric Beckmann FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 409d9de6389SEric Beckmann } 410d9de6389SEric Beckmann 411d9de6389SEric Beckmann static std::time_t getTime() { 412d9de6389SEric Beckmann std::time_t Now = time(nullptr); 413d9de6389SEric Beckmann if (Now < 0 || !isUInt<32>(Now)) 414d9de6389SEric Beckmann return UINT32_MAX; 415d9de6389SEric Beckmann return Now; 416d9de6389SEric Beckmann } 417d9de6389SEric Beckmann 418*ddcfbf7dSEric Beckmann std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() { 419d135e8c0SEric Beckmann BufferStart = const_cast<char *>(OutputBuffer->getBufferStart()); 420d9de6389SEric Beckmann 421d9de6389SEric Beckmann writeCOFFHeader(); 422d9de6389SEric Beckmann writeFirstSectionHeader(); 423d9de6389SEric Beckmann writeSecondSectionHeader(); 424d9de6389SEric Beckmann writeFirstSection(); 425d9de6389SEric Beckmann writeSecondSection(); 426d9de6389SEric Beckmann writeSymbolTable(); 427d9de6389SEric Beckmann writeStringTable(); 428d9de6389SEric Beckmann 429*ddcfbf7dSEric Beckmann return std::move(OutputBuffer); 430d9de6389SEric Beckmann } 431d9de6389SEric Beckmann 432d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeCOFFHeader() { 433d9de6389SEric Beckmann // Write the COFF header. 4347687f046SEric Beckmann auto *Header = reinterpret_cast<coff_file_header *>(BufferStart); 435d9de6389SEric Beckmann switch (MachineType) { 436d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_ARMNT: 4377687f046SEric Beckmann Header->Machine = COFF::IMAGE_FILE_MACHINE_ARMNT; 438d9de6389SEric Beckmann break; 439d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_AMD64: 4407687f046SEric Beckmann Header->Machine = COFF::IMAGE_FILE_MACHINE_AMD64; 441d9de6389SEric Beckmann break; 442d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_I386: 4437687f046SEric Beckmann Header->Machine = COFF::IMAGE_FILE_MACHINE_I386; 444d9de6389SEric Beckmann break; 445d9de6389SEric Beckmann default: 4467687f046SEric Beckmann Header->Machine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; 447d9de6389SEric Beckmann } 448d9de6389SEric Beckmann Header->NumberOfSections = 2; 449d9de6389SEric Beckmann Header->TimeDateStamp = getTime(); 450d9de6389SEric Beckmann Header->PointerToSymbolTable = SymbolTableOffset; 451d9de6389SEric Beckmann // One symbol for every resource plus 2 for each section and @feat.00 452d9de6389SEric Beckmann Header->NumberOfSymbols = Data.size() + 5; 453d9de6389SEric Beckmann Header->SizeOfOptionalHeader = 0; 4547687f046SEric Beckmann Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; 455d9de6389SEric Beckmann } 456d9de6389SEric Beckmann 457d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionHeader() { 458d9de6389SEric Beckmann // Write the first section header. 4597687f046SEric Beckmann CurrentOffset += sizeof(coff_file_header); 4607687f046SEric Beckmann auto *SectionOneHeader = 4617687f046SEric Beckmann reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 4627687f046SEric Beckmann strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize); 463d9de6389SEric Beckmann SectionOneHeader->VirtualSize = 0; 464d9de6389SEric Beckmann SectionOneHeader->VirtualAddress = 0; 465d9de6389SEric Beckmann SectionOneHeader->SizeOfRawData = SectionOneSize; 466d9de6389SEric Beckmann SectionOneHeader->PointerToRawData = SectionOneOffset; 467d9de6389SEric Beckmann SectionOneHeader->PointerToRelocations = SectionOneRelocations; 468d9de6389SEric Beckmann SectionOneHeader->PointerToLinenumbers = 0; 469d9de6389SEric Beckmann SectionOneHeader->NumberOfRelocations = Data.size(); 470d9de6389SEric Beckmann SectionOneHeader->NumberOfLinenumbers = 0; 4717687f046SEric Beckmann SectionOneHeader->Characteristics = COFF::IMAGE_SCN_ALIGN_1BYTES; 4727687f046SEric Beckmann SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 4737687f046SEric Beckmann SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 4747687f046SEric Beckmann SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 475d9de6389SEric Beckmann } 476d9de6389SEric Beckmann 477d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSectionHeader() { 478d9de6389SEric Beckmann // Write the second section header. 4797687f046SEric Beckmann CurrentOffset += sizeof(coff_section); 4807687f046SEric Beckmann auto *SectionTwoHeader = 4817687f046SEric Beckmann reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 4827687f046SEric Beckmann strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize); 483d9de6389SEric Beckmann SectionTwoHeader->VirtualSize = 0; 484d9de6389SEric Beckmann SectionTwoHeader->VirtualAddress = 0; 485d9de6389SEric Beckmann SectionTwoHeader->SizeOfRawData = SectionTwoSize; 486d9de6389SEric Beckmann SectionTwoHeader->PointerToRawData = SectionTwoOffset; 487d9de6389SEric Beckmann SectionTwoHeader->PointerToRelocations = 0; 488d9de6389SEric Beckmann SectionTwoHeader->PointerToLinenumbers = 0; 489d9de6389SEric Beckmann SectionTwoHeader->NumberOfRelocations = 0; 490d9de6389SEric Beckmann SectionTwoHeader->NumberOfLinenumbers = 0; 4917687f046SEric Beckmann SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 4927687f046SEric Beckmann SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 493d9de6389SEric Beckmann } 494d9de6389SEric Beckmann 495d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSection() { 496d9de6389SEric Beckmann // Write section one. 4977687f046SEric Beckmann CurrentOffset += sizeof(coff_section); 498d9de6389SEric Beckmann 499d9de6389SEric Beckmann writeDirectoryTree(); 500d9de6389SEric Beckmann writeDirectoryStringTable(); 501d9de6389SEric Beckmann writeFirstSectionRelocations(); 502382eaabbSEric Beckmann 503382eaabbSEric Beckmann CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 504d9de6389SEric Beckmann } 505d9de6389SEric Beckmann 506d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSection() { 507d9de6389SEric Beckmann // Now write the .rsrc$02 section. 508d9de6389SEric Beckmann for (auto const &RawDataEntry : Data) { 509382eaabbSEric Beckmann std::copy(RawDataEntry.begin(), RawDataEntry.end(), 510382eaabbSEric Beckmann BufferStart + CurrentOffset); 511382eaabbSEric Beckmann CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t)); 512d9de6389SEric Beckmann } 513382eaabbSEric Beckmann 514382eaabbSEric Beckmann CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 515d9de6389SEric Beckmann } 516d9de6389SEric Beckmann 517d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSymbolTable() { 518d9de6389SEric Beckmann // Now write the symbol table. 519d9de6389SEric Beckmann // First, the feat symbol. 5207687f046SEric Beckmann auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 5217687f046SEric Beckmann strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize); 522d9de6389SEric Beckmann Symbol->Value = 0x11; 523d9de6389SEric Beckmann Symbol->SectionNumber = 0xffff; 5247687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5257687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 526d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 0; 5277687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 528d9de6389SEric Beckmann 529d9de6389SEric Beckmann // Now write the .rsrc1 symbol + aux. 5307687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 5317687f046SEric Beckmann strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize); 532d9de6389SEric Beckmann Symbol->Value = 0; 533d9de6389SEric Beckmann Symbol->SectionNumber = 1; 5347687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5357687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 536d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 1; 5377687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 5387687f046SEric Beckmann auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 5397687f046SEric Beckmann CurrentOffset); 540d9de6389SEric Beckmann Aux->Length = SectionOneSize; 541d9de6389SEric Beckmann Aux->NumberOfRelocations = Data.size(); 542d9de6389SEric Beckmann Aux->NumberOfLinenumbers = 0; 543d9de6389SEric Beckmann Aux->CheckSum = 0; 544d9de6389SEric Beckmann Aux->NumberLowPart = 0; 545d9de6389SEric Beckmann Aux->Selection = 0; 5467687f046SEric Beckmann CurrentOffset += sizeof(coff_aux_section_definition); 547d9de6389SEric Beckmann 548d9de6389SEric Beckmann // Now write the .rsrc2 symbol + aux. 5497687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 5507687f046SEric Beckmann strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize); 551d9de6389SEric Beckmann Symbol->Value = 0; 552d9de6389SEric Beckmann Symbol->SectionNumber = 2; 5537687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5547687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 555d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 1; 5567687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 5577687f046SEric Beckmann Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 5587687f046SEric Beckmann CurrentOffset); 559d9de6389SEric Beckmann Aux->Length = SectionTwoSize; 560d9de6389SEric Beckmann Aux->NumberOfRelocations = 0; 561d9de6389SEric Beckmann Aux->NumberOfLinenumbers = 0; 562d9de6389SEric Beckmann Aux->CheckSum = 0; 563d9de6389SEric Beckmann Aux->NumberLowPart = 0; 564d9de6389SEric Beckmann Aux->Selection = 0; 5657687f046SEric Beckmann CurrentOffset += sizeof(coff_aux_section_definition); 566d9de6389SEric Beckmann 567d9de6389SEric Beckmann // Now write a symbol for each relocation. 568d9de6389SEric Beckmann for (unsigned i = 0; i < Data.size(); i++) { 569d9de6389SEric Beckmann char RelocationName[9]; 570d9de6389SEric Beckmann sprintf(RelocationName, "$R%06X", DataOffsets[i]); 5717687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 5727687f046SEric Beckmann strncpy(Symbol->Name.ShortName, RelocationName, (size_t)COFF::NameSize); 573d9de6389SEric Beckmann Symbol->Value = DataOffsets[i]; 574d9de6389SEric Beckmann Symbol->SectionNumber = 1; 5757687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5767687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 577d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 0; 5787687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 579d9de6389SEric Beckmann } 580d9de6389SEric Beckmann } 581d9de6389SEric Beckmann 582d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeStringTable() { 583d9de6389SEric Beckmann // Just 4 null bytes for the string table. 58433866334SEric Beckmann auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset); 58533866334SEric Beckmann memset(COFFStringTable, 0, 4); 586d9de6389SEric Beckmann } 587d9de6389SEric Beckmann 588d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryTree() { 589d9de6389SEric Beckmann // Traverse parsed resource tree breadth-first and write the corresponding 590d9de6389SEric Beckmann // COFF objects. 591d9de6389SEric Beckmann std::queue<const WindowsResourceParser::TreeNode *> Queue; 592d9de6389SEric Beckmann Queue.push(&Resources); 5937687f046SEric Beckmann uint32_t NextLevelOffset = 5947687f046SEric Beckmann sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() + 595d9de6389SEric Beckmann Resources.getIDChildren().size()) * 5967687f046SEric Beckmann sizeof(coff_resource_dir_entry); 597d9de6389SEric Beckmann std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder; 598d9de6389SEric Beckmann uint32_t CurrentRelativeOffset = 0; 599d9de6389SEric Beckmann 600d9de6389SEric Beckmann while (!Queue.empty()) { 601d9de6389SEric Beckmann auto CurrentNode = Queue.front(); 602d9de6389SEric Beckmann Queue.pop(); 6037687f046SEric Beckmann auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart + 6047687f046SEric Beckmann CurrentOffset); 605d9de6389SEric Beckmann Table->Characteristics = CurrentNode->getCharacteristics(); 606d9de6389SEric Beckmann Table->TimeDateStamp = 0; 607d9de6389SEric Beckmann Table->MajorVersion = CurrentNode->getMajorVersion(); 608d9de6389SEric Beckmann Table->MinorVersion = CurrentNode->getMinorVersion(); 609d9de6389SEric Beckmann auto &IDChildren = CurrentNode->getIDChildren(); 610d9de6389SEric Beckmann auto &StringChildren = CurrentNode->getStringChildren(); 611d9de6389SEric Beckmann Table->NumberOfNameEntries = StringChildren.size(); 612d9de6389SEric Beckmann Table->NumberOfIDEntries = IDChildren.size(); 6137687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_table); 6147687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_table); 615d9de6389SEric Beckmann 616d9de6389SEric Beckmann // Write the directory entries immediately following each directory table. 617d9de6389SEric Beckmann for (auto const &Child : StringChildren) { 6187687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 6197687f046SEric Beckmann CurrentOffset); 620d9de6389SEric Beckmann Entry->Identifier.NameOffset = 621d9de6389SEric Beckmann StringTableOffsets[Child.second->getStringIndex()]; 622d9de6389SEric Beckmann if (Child.second->checkIsDataNode()) { 623d9de6389SEric Beckmann Entry->Offset.DataEntryOffset = NextLevelOffset; 6247687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_data_entry); 625d9de6389SEric Beckmann DataEntriesTreeOrder.push_back(Child.second.get()); 626d9de6389SEric Beckmann } else { 627d9de6389SEric Beckmann Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 6287687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_dir_table) + 629d9de6389SEric Beckmann (Child.second->getStringChildren().size() + 630d9de6389SEric Beckmann Child.second->getIDChildren().size()) * 6317687f046SEric Beckmann sizeof(coff_resource_dir_entry); 632d9de6389SEric Beckmann Queue.push(Child.second.get()); 633d9de6389SEric Beckmann } 6347687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_entry); 6357687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 636d9de6389SEric Beckmann } 637d9de6389SEric Beckmann for (auto const &Child : IDChildren) { 6387687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 6397687f046SEric Beckmann CurrentOffset); 640d9de6389SEric Beckmann Entry->Identifier.ID = Child.first; 641d9de6389SEric Beckmann if (Child.second->checkIsDataNode()) { 642d9de6389SEric Beckmann Entry->Offset.DataEntryOffset = NextLevelOffset; 6437687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_data_entry); 644d9de6389SEric Beckmann DataEntriesTreeOrder.push_back(Child.second.get()); 645d9de6389SEric Beckmann } else { 646d9de6389SEric Beckmann Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 6477687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_dir_table) + 648d9de6389SEric Beckmann (Child.second->getStringChildren().size() + 649d9de6389SEric Beckmann Child.second->getIDChildren().size()) * 6507687f046SEric Beckmann sizeof(coff_resource_dir_entry); 651d9de6389SEric Beckmann Queue.push(Child.second.get()); 652d9de6389SEric Beckmann } 6537687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_entry); 6547687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 655d9de6389SEric Beckmann } 656d9de6389SEric Beckmann } 657d9de6389SEric Beckmann 658d9de6389SEric Beckmann RelocationAddresses.resize(Data.size()); 659d9de6389SEric Beckmann // Now write all the resource data entries. 660d9de6389SEric Beckmann for (auto DataNodes : DataEntriesTreeOrder) { 6617687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart + 6627687f046SEric Beckmann CurrentOffset); 663d9de6389SEric Beckmann RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset; 664d9de6389SEric Beckmann Entry->DataRVA = 0; // Set to zero because it is a relocation. 665d9de6389SEric Beckmann Entry->DataSize = Data[DataNodes->getDataIndex()].size(); 666d9de6389SEric Beckmann Entry->Codepage = 0; 667d9de6389SEric Beckmann Entry->Reserved = 0; 6687687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_data_entry); 6697687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_data_entry); 670d9de6389SEric Beckmann } 671d9de6389SEric Beckmann } 672d9de6389SEric Beckmann 673d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryStringTable() { 674d9de6389SEric Beckmann // Now write the directory string table for .rsrc$01 675d9de6389SEric Beckmann uint32_t TotalStringTableSize = 0; 6760096d78bSEric Beckmann for (auto &String : StringTable) { 677d9de6389SEric Beckmann uint16_t Length = String.size(); 6781f76ca5aSEric Beckmann support::endian::write16le(BufferStart + CurrentOffset, Length); 679382eaabbSEric Beckmann CurrentOffset += sizeof(uint16_t); 680382eaabbSEric Beckmann auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset); 681d9de6389SEric Beckmann std::copy(String.begin(), String.end(), Start); 682382eaabbSEric Beckmann CurrentOffset += Length * sizeof(UTF16); 683d9de6389SEric Beckmann TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t); 684d9de6389SEric Beckmann } 685382eaabbSEric Beckmann CurrentOffset += 686d9de6389SEric Beckmann alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize; 687d9de6389SEric Beckmann } 688d9de6389SEric Beckmann 689d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { 690d9de6389SEric Beckmann 691d9de6389SEric Beckmann // Now write the relocations for .rsrc$01 692d9de6389SEric Beckmann // Five symbols already in table before we start, @feat.00 and 2 for each 693d9de6389SEric Beckmann // .rsrc section. 694d9de6389SEric Beckmann uint32_t NextSymbolIndex = 5; 695d9de6389SEric Beckmann for (unsigned i = 0; i < Data.size(); i++) { 6967687f046SEric Beckmann auto *Reloc = 6977687f046SEric Beckmann reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset); 698d9de6389SEric Beckmann Reloc->VirtualAddress = RelocationAddresses[i]; 699d9de6389SEric Beckmann Reloc->SymbolTableIndex = NextSymbolIndex++; 700d9de6389SEric Beckmann switch (MachineType) { 701d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_ARMNT: 7027687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB; 703d9de6389SEric Beckmann break; 704d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_AMD64: 7057687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB; 706d9de6389SEric Beckmann break; 707d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_I386: 7087687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; 709d9de6389SEric Beckmann break; 710d9de6389SEric Beckmann default: 711d9de6389SEric Beckmann Reloc->Type = 0; 712d9de6389SEric Beckmann } 7137687f046SEric Beckmann CurrentOffset += sizeof(coff_relocation); 714d9de6389SEric Beckmann } 715d9de6389SEric Beckmann } 716d9de6389SEric Beckmann 717*ddcfbf7dSEric Beckmann Expected<std::unique_ptr<MemoryBuffer>> 718*ddcfbf7dSEric Beckmann writeWindowsResourceCOFF(COFF::MachineTypes MachineType, 719d9de6389SEric Beckmann const WindowsResourceParser &Parser) { 720d9de6389SEric Beckmann Error E = Error::success(); 721*ddcfbf7dSEric Beckmann WindowsResourceCOFFWriter Writer(MachineType, Parser, E); 722d9de6389SEric Beckmann if (E) 723*ddcfbf7dSEric Beckmann return std::move(E); 724d9de6389SEric Beckmann return Writer.write(); 725d9de6389SEric Beckmann } 726d9de6389SEric Beckmann 727a6bdf751SEric Beckmann } // namespace object 728a6bdf751SEric Beckmann } // namespace llvm 729