10b57cec5SDimitry Andric //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the .res file class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/Object/WindowsResource.h" 140b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 15*0fca6ea1SDimitry Andric #include "llvm/Object/WindowsMachineFlag.h" 160b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h" 170b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 180b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h" 190b57cec5SDimitry Andric #include <ctime> 200b57cec5SDimitry Andric #include <queue> 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 230b57cec5SDimitry Andric using namespace object; 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace llvm { 260b57cec5SDimitry Andric namespace object { 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #define RETURN_IF_ERROR(X) \ 290b57cec5SDimitry Andric if (auto EC = X) \ 300b57cec5SDimitry Andric return EC; 310b57cec5SDimitry Andric 328bcb0991SDimitry Andric #define UNWRAP_REF_OR_RETURN(Name, Expr) \ 338bcb0991SDimitry Andric auto Name##OrErr = Expr; \ 348bcb0991SDimitry Andric if (!Name##OrErr) \ 358bcb0991SDimitry Andric return Name##OrErr.takeError(); \ 368bcb0991SDimitry Andric const auto &Name = *Name##OrErr; 378bcb0991SDimitry Andric 388bcb0991SDimitry Andric #define UNWRAP_OR_RETURN(Name, Expr) \ 398bcb0991SDimitry Andric auto Name##OrErr = Expr; \ 408bcb0991SDimitry Andric if (!Name##OrErr) \ 418bcb0991SDimitry Andric return Name##OrErr.takeError(); \ 428bcb0991SDimitry Andric auto Name = *Name##OrErr; 438bcb0991SDimitry Andric 440b57cec5SDimitry Andric const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric // COFF files seem to be inconsistent with alignment between sections, just use 470b57cec5SDimitry Andric // 8-byte because it makes everyone happy. 480b57cec5SDimitry Andric const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric WindowsResource::WindowsResource(MemoryBufferRef Source) 510b57cec5SDimitry Andric : Binary(Binary::ID_WinRes, Source) { 520b57cec5SDimitry Andric size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE; 530b57cec5SDimitry Andric BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize), 545f757f3fSDimitry Andric llvm::endianness::little); 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // static 580b57cec5SDimitry Andric Expected<std::unique_ptr<WindowsResource>> 590b57cec5SDimitry Andric WindowsResource::createWindowsResource(MemoryBufferRef Source) { 600b57cec5SDimitry Andric if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE) 610b57cec5SDimitry Andric return make_error<GenericBinaryError>( 620b57cec5SDimitry Andric Source.getBufferIdentifier() + ": too small to be a resource file", 630b57cec5SDimitry Andric object_error::invalid_file_type); 640b57cec5SDimitry Andric std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source)); 650b57cec5SDimitry Andric return std::move(Ret); 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric Expected<ResourceEntryRef> WindowsResource::getHeadEntry() { 690b57cec5SDimitry Andric if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix)) 700b57cec5SDimitry Andric return make_error<EmptyResError>(getFileName() + " contains no entries", 710b57cec5SDimitry Andric object_error::unexpected_eof); 720b57cec5SDimitry Andric return ResourceEntryRef::create(BinaryStreamRef(BBS), this); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, 760b57cec5SDimitry Andric const WindowsResource *Owner) 770b57cec5SDimitry Andric : Reader(Ref), Owner(Owner) {} 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric Expected<ResourceEntryRef> 800b57cec5SDimitry Andric ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) { 810b57cec5SDimitry Andric auto Ref = ResourceEntryRef(BSR, Owner); 820b57cec5SDimitry Andric if (auto E = Ref.loadNext()) 83*0fca6ea1SDimitry Andric return E; 840b57cec5SDimitry Andric return Ref; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric Error ResourceEntryRef::moveNext(bool &End) { 880b57cec5SDimitry Andric // Reached end of all the entries. 890b57cec5SDimitry Andric if (Reader.bytesRemaining() == 0) { 900b57cec5SDimitry Andric End = true; 910b57cec5SDimitry Andric return Error::success(); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric RETURN_IF_ERROR(loadNext()); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric return Error::success(); 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, 990b57cec5SDimitry Andric ArrayRef<UTF16> &Str, bool &IsString) { 1000b57cec5SDimitry Andric uint16_t IDFlag; 1010b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readInteger(IDFlag)); 1020b57cec5SDimitry Andric IsString = IDFlag != 0xffff; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric if (IsString) { 1050b57cec5SDimitry Andric Reader.setOffset( 1060b57cec5SDimitry Andric Reader.getOffset() - 1070b57cec5SDimitry Andric sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. 1080b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readWideString(Str)); 1090b57cec5SDimitry Andric } else 1100b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readInteger(ID)); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric return Error::success(); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric Error ResourceEntryRef::loadNext() { 1160b57cec5SDimitry Andric const WinResHeaderPrefix *Prefix; 1170b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Prefix)); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric if (Prefix->HeaderSize < MIN_HEADER_SIZE) 1200b57cec5SDimitry Andric return make_error<GenericBinaryError>(Owner->getFileName() + 1210b57cec5SDimitry Andric ": header size too small", 1220b57cec5SDimitry Andric object_error::parse_failed); 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT)); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Suffix)); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize)); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT)); 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric return Error::success(); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1398bcb0991SDimitry Andric WindowsResourceParser::WindowsResourceParser(bool MinGW) 1408bcb0991SDimitry Andric : Root(false), MinGW(MinGW) {} 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) { 1430b57cec5SDimitry Andric switch (TypeID) { 1440b57cec5SDimitry Andric case 1: OS << "CURSOR (ID 1)"; break; 1450b57cec5SDimitry Andric case 2: OS << "BITMAP (ID 2)"; break; 1460b57cec5SDimitry Andric case 3: OS << "ICON (ID 3)"; break; 1470b57cec5SDimitry Andric case 4: OS << "MENU (ID 4)"; break; 1480b57cec5SDimitry Andric case 5: OS << "DIALOG (ID 5)"; break; 1490b57cec5SDimitry Andric case 6: OS << "STRINGTABLE (ID 6)"; break; 1500b57cec5SDimitry Andric case 7: OS << "FONTDIR (ID 7)"; break; 1510b57cec5SDimitry Andric case 8: OS << "FONT (ID 8)"; break; 1520b57cec5SDimitry Andric case 9: OS << "ACCELERATOR (ID 9)"; break; 1530b57cec5SDimitry Andric case 10: OS << "RCDATA (ID 10)"; break; 1540b57cec5SDimitry Andric case 11: OS << "MESSAGETABLE (ID 11)"; break; 1550b57cec5SDimitry Andric case 12: OS << "GROUP_CURSOR (ID 12)"; break; 1560b57cec5SDimitry Andric case 14: OS << "GROUP_ICON (ID 14)"; break; 1570b57cec5SDimitry Andric case 16: OS << "VERSIONINFO (ID 16)"; break; 1580b57cec5SDimitry Andric case 17: OS << "DLGINCLUDE (ID 17)"; break; 1590b57cec5SDimitry Andric case 19: OS << "PLUGPLAY (ID 19)"; break; 1600b57cec5SDimitry Andric case 20: OS << "VXD (ID 20)"; break; 1610b57cec5SDimitry Andric case 21: OS << "ANICURSOR (ID 21)"; break; 1620b57cec5SDimitry Andric case 22: OS << "ANIICON (ID 22)"; break; 1630b57cec5SDimitry Andric case 23: OS << "HTML (ID 23)"; break; 1640b57cec5SDimitry Andric case 24: OS << "MANIFEST (ID 24)"; break; 1650b57cec5SDimitry Andric default: OS << "ID " << TypeID; break; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) { 1700b57cec5SDimitry Andric if (!sys::IsBigEndianHost) 1710b57cec5SDimitry Andric return convertUTF16ToUTF8String(Src, Out); 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric std::vector<UTF16> EndianCorrectedSrc; 1740b57cec5SDimitry Andric EndianCorrectedSrc.resize(Src.size() + 1); 1750b57cec5SDimitry Andric llvm::copy(Src, EndianCorrectedSrc.begin() + 1); 1760b57cec5SDimitry Andric EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; 177bdd1243dSDimitry Andric return convertUTF16ToUTF8String(ArrayRef(EndianCorrectedSrc), Out); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric static std::string makeDuplicateResourceError( 1810b57cec5SDimitry Andric const ResourceEntryRef &Entry, StringRef File1, StringRef File2) { 1820b57cec5SDimitry Andric std::string Ret; 1830b57cec5SDimitry Andric raw_string_ostream OS(Ret); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric OS << "duplicate resource:"; 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric OS << " type "; 1880b57cec5SDimitry Andric if (Entry.checkTypeString()) { 1890b57cec5SDimitry Andric std::string UTF8; 1900b57cec5SDimitry Andric if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8)) 1910b57cec5SDimitry Andric UTF8 = "(failed conversion from UTF16)"; 1920b57cec5SDimitry Andric OS << '\"' << UTF8 << '\"'; 1930b57cec5SDimitry Andric } else 1940b57cec5SDimitry Andric printResourceTypeName(Entry.getTypeID(), OS); 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric OS << "/name "; 1970b57cec5SDimitry Andric if (Entry.checkNameString()) { 1980b57cec5SDimitry Andric std::string UTF8; 1990b57cec5SDimitry Andric if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8)) 2000b57cec5SDimitry Andric UTF8 = "(failed conversion from UTF16)"; 2010b57cec5SDimitry Andric OS << '\"' << UTF8 << '\"'; 2020b57cec5SDimitry Andric } else { 2030b57cec5SDimitry Andric OS << "ID " << Entry.getNameID(); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in " 2070b57cec5SDimitry Andric << File2; 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric return OS.str(); 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2128bcb0991SDimitry Andric static void printStringOrID(const WindowsResourceParser::StringOrID &S, 2138bcb0991SDimitry Andric raw_string_ostream &OS, bool IsType, bool IsID) { 2148bcb0991SDimitry Andric if (S.IsString) { 2158bcb0991SDimitry Andric std::string UTF8; 2168bcb0991SDimitry Andric if (!convertUTF16LEToUTF8String(S.String, UTF8)) 2178bcb0991SDimitry Andric UTF8 = "(failed conversion from UTF16)"; 2188bcb0991SDimitry Andric OS << '\"' << UTF8 << '\"'; 2198bcb0991SDimitry Andric } else if (IsType) 2208bcb0991SDimitry Andric printResourceTypeName(S.ID, OS); 2218bcb0991SDimitry Andric else if (IsID) 2228bcb0991SDimitry Andric OS << "ID " << S.ID; 2238bcb0991SDimitry Andric else 2248bcb0991SDimitry Andric OS << S.ID; 2258bcb0991SDimitry Andric } 2268bcb0991SDimitry Andric 2278bcb0991SDimitry Andric static std::string makeDuplicateResourceError( 2288bcb0991SDimitry Andric const std::vector<WindowsResourceParser::StringOrID> &Context, 2298bcb0991SDimitry Andric StringRef File1, StringRef File2) { 2308bcb0991SDimitry Andric std::string Ret; 2318bcb0991SDimitry Andric raw_string_ostream OS(Ret); 2328bcb0991SDimitry Andric 2338bcb0991SDimitry Andric OS << "duplicate resource:"; 2348bcb0991SDimitry Andric 2358bcb0991SDimitry Andric if (Context.size() >= 1) { 2368bcb0991SDimitry Andric OS << " type "; 2378bcb0991SDimitry Andric printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true); 2388bcb0991SDimitry Andric } 2398bcb0991SDimitry Andric 2408bcb0991SDimitry Andric if (Context.size() >= 2) { 2418bcb0991SDimitry Andric OS << "/name "; 2428bcb0991SDimitry Andric printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true); 2438bcb0991SDimitry Andric } 2448bcb0991SDimitry Andric 2458bcb0991SDimitry Andric if (Context.size() >= 3) { 2468bcb0991SDimitry Andric OS << "/language "; 2478bcb0991SDimitry Andric printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false); 2488bcb0991SDimitry Andric } 2498bcb0991SDimitry Andric OS << ", in " << File1 << " and in " << File2; 2508bcb0991SDimitry Andric 2518bcb0991SDimitry Andric return OS.str(); 2528bcb0991SDimitry Andric } 2538bcb0991SDimitry Andric 2548bcb0991SDimitry Andric // MinGW specific. Remove default manifests (with language zero) if there are 2558bcb0991SDimitry Andric // other manifests present, and report an error if there are more than one 2568bcb0991SDimitry Andric // manifest with a non-zero language code. 2578bcb0991SDimitry Andric // GCC has the concept of a default manifest resource object, which gets 2588bcb0991SDimitry Andric // linked in implicitly if present. This default manifest has got language 2598bcb0991SDimitry Andric // id zero, and should be dropped silently if there's another manifest present. 2608bcb0991SDimitry Andric // If the user resources surprisignly had a manifest with language id zero, 2618bcb0991SDimitry Andric // we should also ignore the duplicate default manifest. 2628bcb0991SDimitry Andric void WindowsResourceParser::cleanUpManifests( 2638bcb0991SDimitry Andric std::vector<std::string> &Duplicates) { 2648bcb0991SDimitry Andric auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24); 2658bcb0991SDimitry Andric if (TypeIt == Root.IDChildren.end()) 2668bcb0991SDimitry Andric return; 2678bcb0991SDimitry Andric 2688bcb0991SDimitry Andric TreeNode *TypeNode = TypeIt->second.get(); 2698bcb0991SDimitry Andric auto NameIt = 2708bcb0991SDimitry Andric TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1); 2718bcb0991SDimitry Andric if (NameIt == TypeNode->IDChildren.end()) 2728bcb0991SDimitry Andric return; 2738bcb0991SDimitry Andric 2748bcb0991SDimitry Andric TreeNode *NameNode = NameIt->second.get(); 2758bcb0991SDimitry Andric if (NameNode->IDChildren.size() <= 1) 2768bcb0991SDimitry Andric return; // None or one manifest present, all good. 2778bcb0991SDimitry Andric 2788bcb0991SDimitry Andric // If we have more than one manifest, drop the language zero one if present, 2798bcb0991SDimitry Andric // and check again. 2808bcb0991SDimitry Andric auto LangZeroIt = NameNode->IDChildren.find(0); 2818bcb0991SDimitry Andric if (LangZeroIt != NameNode->IDChildren.end() && 2828bcb0991SDimitry Andric LangZeroIt->second->IsDataNode) { 2838bcb0991SDimitry Andric uint32_t RemovedIndex = LangZeroIt->second->DataIndex; 2848bcb0991SDimitry Andric NameNode->IDChildren.erase(LangZeroIt); 2858bcb0991SDimitry Andric Data.erase(Data.begin() + RemovedIndex); 2868bcb0991SDimitry Andric Root.shiftDataIndexDown(RemovedIndex); 2878bcb0991SDimitry Andric 2888bcb0991SDimitry Andric // If we're now down to one manifest, all is good. 2898bcb0991SDimitry Andric if (NameNode->IDChildren.size() <= 1) 2908bcb0991SDimitry Andric return; 2918bcb0991SDimitry Andric } 2928bcb0991SDimitry Andric 2938bcb0991SDimitry Andric // More than one non-language-zero manifest 2948bcb0991SDimitry Andric auto FirstIt = NameNode->IDChildren.begin(); 2958bcb0991SDimitry Andric uint32_t FirstLang = FirstIt->first; 2968bcb0991SDimitry Andric TreeNode *FirstNode = FirstIt->second.get(); 2978bcb0991SDimitry Andric auto LastIt = NameNode->IDChildren.rbegin(); 2988bcb0991SDimitry Andric uint32_t LastLang = LastIt->first; 2998bcb0991SDimitry Andric TreeNode *LastNode = LastIt->second.get(); 3008bcb0991SDimitry Andric Duplicates.push_back( 3018bcb0991SDimitry Andric ("duplicate non-default manifests with languages " + Twine(FirstLang) + 3028bcb0991SDimitry Andric " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) + 3038bcb0991SDimitry Andric " in " + InputFilenames[LastNode->Origin]) 3048bcb0991SDimitry Andric .str()); 3058bcb0991SDimitry Andric } 3068bcb0991SDimitry Andric 3078bcb0991SDimitry Andric // Ignore duplicates of manifests with language zero (the default manifest), 3088bcb0991SDimitry Andric // in case the user has provided a manifest with that language id. See 3098bcb0991SDimitry Andric // the function comment above for context. Only returns true if MinGW is set 3108bcb0991SDimitry Andric // to true. 3118bcb0991SDimitry Andric bool WindowsResourceParser::shouldIgnoreDuplicate( 3128bcb0991SDimitry Andric const ResourceEntryRef &Entry) const { 3138bcb0991SDimitry Andric return MinGW && !Entry.checkTypeString() && 3148bcb0991SDimitry Andric Entry.getTypeID() == /* RT_MANIFEST */ 24 && 3158bcb0991SDimitry Andric !Entry.checkNameString() && 3168bcb0991SDimitry Andric Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 && 3178bcb0991SDimitry Andric Entry.getLanguage() == 0; 3188bcb0991SDimitry Andric } 3198bcb0991SDimitry Andric 3208bcb0991SDimitry Andric bool WindowsResourceParser::shouldIgnoreDuplicate( 3218bcb0991SDimitry Andric const std::vector<StringOrID> &Context) const { 3228bcb0991SDimitry Andric return MinGW && Context.size() == 3 && !Context[0].IsString && 3238bcb0991SDimitry Andric Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString && 3248bcb0991SDimitry Andric Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 && 3258bcb0991SDimitry Andric !Context[2].IsString && Context[2].ID == 0; 3268bcb0991SDimitry Andric } 3278bcb0991SDimitry Andric 3280b57cec5SDimitry Andric Error WindowsResourceParser::parse(WindowsResource *WR, 3290b57cec5SDimitry Andric std::vector<std::string> &Duplicates) { 3300b57cec5SDimitry Andric auto EntryOrErr = WR->getHeadEntry(); 3310b57cec5SDimitry Andric if (!EntryOrErr) { 3320b57cec5SDimitry Andric auto E = EntryOrErr.takeError(); 3330b57cec5SDimitry Andric if (E.isA<EmptyResError>()) { 3340b57cec5SDimitry Andric // Check if the .res file contains no entries. In this case we don't have 3350b57cec5SDimitry Andric // to throw an error but can rather just return without parsing anything. 3360b57cec5SDimitry Andric // This applies for files which have a valid PE header magic and the 3370b57cec5SDimitry Andric // mandatory empty null resource entry. Files which do not fit this 3380b57cec5SDimitry Andric // criteria would have already been filtered out by 3390b57cec5SDimitry Andric // WindowsResource::createWindowsResource(). 3400b57cec5SDimitry Andric consumeError(std::move(E)); 3410b57cec5SDimitry Andric return Error::success(); 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric return E; 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric ResourceEntryRef Entry = EntryOrErr.get(); 3478bcb0991SDimitry Andric uint32_t Origin = InputFilenames.size(); 3485ffd83dbSDimitry Andric InputFilenames.push_back(std::string(WR->getFileName())); 3490b57cec5SDimitry Andric bool End = false; 3500b57cec5SDimitry Andric while (!End) { 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric TreeNode *Node; 3538bcb0991SDimitry Andric bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node); 3540b57cec5SDimitry Andric if (!IsNewNode) { 3558bcb0991SDimitry Andric if (!shouldIgnoreDuplicate(Entry)) 3560b57cec5SDimitry Andric Duplicates.push_back(makeDuplicateResourceError( 3570b57cec5SDimitry Andric Entry, InputFilenames[Node->Origin], WR->getFileName())); 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric RETURN_IF_ERROR(Entry.moveNext(End)); 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric return Error::success(); 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric 3668bcb0991SDimitry Andric Error WindowsResourceParser::parse(ResourceSectionRef &RSR, StringRef Filename, 3678bcb0991SDimitry Andric std::vector<std::string> &Duplicates) { 3688bcb0991SDimitry Andric UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable()); 3698bcb0991SDimitry Andric uint32_t Origin = InputFilenames.size(); 3705ffd83dbSDimitry Andric InputFilenames.push_back(std::string(Filename)); 3718bcb0991SDimitry Andric std::vector<StringOrID> Context; 3728bcb0991SDimitry Andric return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates); 3738bcb0991SDimitry Andric } 3748bcb0991SDimitry Andric 3750b57cec5SDimitry Andric void WindowsResourceParser::printTree(raw_ostream &OS) const { 3760b57cec5SDimitry Andric ScopedPrinter Writer(OS); 3770b57cec5SDimitry Andric Root.print(Writer, "Resource Tree"); 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3808bcb0991SDimitry Andric bool WindowsResourceParser::TreeNode::addEntry( 3818bcb0991SDimitry Andric const ResourceEntryRef &Entry, uint32_t Origin, 3828bcb0991SDimitry Andric std::vector<std::vector<uint8_t>> &Data, 3838bcb0991SDimitry Andric std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) { 3848bcb0991SDimitry Andric TreeNode &TypeNode = addTypeNode(Entry, StringTable); 3858bcb0991SDimitry Andric TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable); 3868bcb0991SDimitry Andric return NameNode.addLanguageNode(Entry, Origin, Data, Result); 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric 3898bcb0991SDimitry Andric Error WindowsResourceParser::addChildren(TreeNode &Node, 3908bcb0991SDimitry Andric ResourceSectionRef &RSR, 3918bcb0991SDimitry Andric const coff_resource_dir_table &Table, 3928bcb0991SDimitry Andric uint32_t Origin, 3938bcb0991SDimitry Andric std::vector<StringOrID> &Context, 3948bcb0991SDimitry Andric std::vector<std::string> &Duplicates) { 3958bcb0991SDimitry Andric 3968bcb0991SDimitry Andric for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries; 3978bcb0991SDimitry Andric i++) { 3988bcb0991SDimitry Andric UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i)); 3998bcb0991SDimitry Andric TreeNode *Child; 4008bcb0991SDimitry Andric 4018bcb0991SDimitry Andric if (Entry.Offset.isSubDir()) { 4028bcb0991SDimitry Andric 4038bcb0991SDimitry Andric // Create a new subdirectory and recurse 4048bcb0991SDimitry Andric if (i < Table.NumberOfNameEntries) { 4058bcb0991SDimitry Andric UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry)); 4068bcb0991SDimitry Andric Child = &Node.addNameChild(NameString, StringTable); 4078bcb0991SDimitry Andric Context.push_back(StringOrID(NameString)); 4088bcb0991SDimitry Andric } else { 4098bcb0991SDimitry Andric Child = &Node.addIDChild(Entry.Identifier.ID); 4108bcb0991SDimitry Andric Context.push_back(StringOrID(Entry.Identifier.ID)); 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric 4138bcb0991SDimitry Andric UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry)); 4148bcb0991SDimitry Andric Error E = 4158bcb0991SDimitry Andric addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates); 4168bcb0991SDimitry Andric if (E) 4178bcb0991SDimitry Andric return E; 4188bcb0991SDimitry Andric Context.pop_back(); 4198bcb0991SDimitry Andric 4208bcb0991SDimitry Andric } else { 4218bcb0991SDimitry Andric 4228bcb0991SDimitry Andric // Data leaves are supposed to have a numeric ID as identifier (language). 4238bcb0991SDimitry Andric if (Table.NumberOfNameEntries > 0) 4248bcb0991SDimitry Andric return createStringError(object_error::parse_failed, 4258bcb0991SDimitry Andric "unexpected string key for data object"); 4268bcb0991SDimitry Andric 4278bcb0991SDimitry Andric // Try adding a data leaf 4288bcb0991SDimitry Andric UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry)); 4298bcb0991SDimitry Andric TreeNode *Child; 4308bcb0991SDimitry Andric Context.push_back(StringOrID(Entry.Identifier.ID)); 4318bcb0991SDimitry Andric bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion, 4328bcb0991SDimitry Andric Table.MinorVersion, Table.Characteristics, 4338bcb0991SDimitry Andric Origin, Data.size(), Child); 4348bcb0991SDimitry Andric if (Added) { 4358bcb0991SDimitry Andric UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry)); 4368bcb0991SDimitry Andric Data.push_back(ArrayRef<uint8_t>( 4378bcb0991SDimitry Andric reinterpret_cast<const uint8_t *>(Contents.data()), 4388bcb0991SDimitry Andric Contents.size())); 4398bcb0991SDimitry Andric } else { 4408bcb0991SDimitry Andric if (!shouldIgnoreDuplicate(Context)) 4418bcb0991SDimitry Andric Duplicates.push_back(makeDuplicateResourceError( 4428bcb0991SDimitry Andric Context, InputFilenames[Child->Origin], InputFilenames.back())); 4438bcb0991SDimitry Andric } 4448bcb0991SDimitry Andric Context.pop_back(); 4458bcb0991SDimitry Andric 4468bcb0991SDimitry Andric } 4478bcb0991SDimitry Andric } 4488bcb0991SDimitry Andric return Error::success(); 4498bcb0991SDimitry Andric } 4508bcb0991SDimitry Andric 4518bcb0991SDimitry Andric WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex) 4528bcb0991SDimitry Andric : StringIndex(StringIndex) {} 4538bcb0991SDimitry Andric 4540b57cec5SDimitry Andric WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, 4550b57cec5SDimitry Andric uint16_t MinorVersion, 4560b57cec5SDimitry Andric uint32_t Characteristics, 4578bcb0991SDimitry Andric uint32_t Origin, uint32_t DataIndex) 4588bcb0991SDimitry Andric : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion), 4598bcb0991SDimitry Andric MinorVersion(MinorVersion), Characteristics(Characteristics), 4608bcb0991SDimitry Andric Origin(Origin) {} 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric std::unique_ptr<WindowsResourceParser::TreeNode> 4638bcb0991SDimitry Andric WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) { 4648bcb0991SDimitry Andric return std::unique_ptr<TreeNode>(new TreeNode(Index)); 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric std::unique_ptr<WindowsResourceParser::TreeNode> 4680b57cec5SDimitry Andric WindowsResourceParser::TreeNode::createIDNode() { 4698bcb0991SDimitry Andric return std::unique_ptr<TreeNode>(new TreeNode(0)); 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric std::unique_ptr<WindowsResourceParser::TreeNode> 4730b57cec5SDimitry Andric WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, 4740b57cec5SDimitry Andric uint16_t MinorVersion, 4750b57cec5SDimitry Andric uint32_t Characteristics, 4768bcb0991SDimitry Andric uint32_t Origin, 4778bcb0991SDimitry Andric uint32_t DataIndex) { 4788bcb0991SDimitry Andric return std::unique_ptr<TreeNode>(new TreeNode( 4798bcb0991SDimitry Andric MajorVersion, MinorVersion, Characteristics, Origin, DataIndex)); 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4828bcb0991SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode( 4838bcb0991SDimitry Andric const ResourceEntryRef &Entry, 4848bcb0991SDimitry Andric std::vector<std::vector<UTF16>> &StringTable) { 4850b57cec5SDimitry Andric if (Entry.checkTypeString()) 4868bcb0991SDimitry Andric return addNameChild(Entry.getTypeString(), StringTable); 4870b57cec5SDimitry Andric else 4880b57cec5SDimitry Andric return addIDChild(Entry.getTypeID()); 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric 4918bcb0991SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode( 4928bcb0991SDimitry Andric const ResourceEntryRef &Entry, 4938bcb0991SDimitry Andric std::vector<std::vector<UTF16>> &StringTable) { 4940b57cec5SDimitry Andric if (Entry.checkNameString()) 4958bcb0991SDimitry Andric return addNameChild(Entry.getNameString(), StringTable); 4960b57cec5SDimitry Andric else 4970b57cec5SDimitry Andric return addIDChild(Entry.getNameID()); 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric bool WindowsResourceParser::TreeNode::addLanguageNode( 5018bcb0991SDimitry Andric const ResourceEntryRef &Entry, uint32_t Origin, 5028bcb0991SDimitry Andric std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) { 5038bcb0991SDimitry Andric bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(), 5040b57cec5SDimitry Andric Entry.getMinorVersion(), Entry.getCharacteristics(), 5058bcb0991SDimitry Andric Origin, Data.size(), Result); 5068bcb0991SDimitry Andric if (Added) 5078bcb0991SDimitry Andric Data.push_back(Entry.getData()); 5088bcb0991SDimitry Andric return Added; 5090b57cec5SDimitry Andric } 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric bool WindowsResourceParser::TreeNode::addDataChild( 5120b57cec5SDimitry Andric uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, 5138bcb0991SDimitry Andric uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex, 5148bcb0991SDimitry Andric TreeNode *&Result) { 5158bcb0991SDimitry Andric auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics, 5168bcb0991SDimitry Andric Origin, DataIndex); 5170b57cec5SDimitry Andric auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild)); 5180b57cec5SDimitry Andric Result = ElementInserted.first->second.get(); 5190b57cec5SDimitry Andric return ElementInserted.second; 5200b57cec5SDimitry Andric } 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild( 5230b57cec5SDimitry Andric uint32_t ID) { 5240b57cec5SDimitry Andric auto Child = IDChildren.find(ID); 5250b57cec5SDimitry Andric if (Child == IDChildren.end()) { 5260b57cec5SDimitry Andric auto NewChild = createIDNode(); 5270b57cec5SDimitry Andric WindowsResourceParser::TreeNode &Node = *NewChild; 5280b57cec5SDimitry Andric IDChildren.emplace(ID, std::move(NewChild)); 5290b57cec5SDimitry Andric return Node; 5300b57cec5SDimitry Andric } else 5310b57cec5SDimitry Andric return *(Child->second); 5320b57cec5SDimitry Andric } 5330b57cec5SDimitry Andric 5348bcb0991SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild( 5358bcb0991SDimitry Andric ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) { 5360b57cec5SDimitry Andric std::string NameString; 5370b57cec5SDimitry Andric convertUTF16LEToUTF8String(NameRef, NameString); 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric auto Child = StringChildren.find(NameString); 5400b57cec5SDimitry Andric if (Child == StringChildren.end()) { 5418bcb0991SDimitry Andric auto NewChild = createStringNode(StringTable.size()); 5428bcb0991SDimitry Andric StringTable.push_back(NameRef); 5430b57cec5SDimitry Andric WindowsResourceParser::TreeNode &Node = *NewChild; 5440b57cec5SDimitry Andric StringChildren.emplace(NameString, std::move(NewChild)); 5450b57cec5SDimitry Andric return Node; 5460b57cec5SDimitry Andric } else 5470b57cec5SDimitry Andric return *(Child->second); 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, 5510b57cec5SDimitry Andric StringRef Name) const { 5520b57cec5SDimitry Andric ListScope NodeScope(Writer, Name); 5530b57cec5SDimitry Andric for (auto const &Child : StringChildren) { 5540b57cec5SDimitry Andric Child.second->print(Writer, Child.first); 5550b57cec5SDimitry Andric } 5560b57cec5SDimitry Andric for (auto const &Child : IDChildren) { 5570b57cec5SDimitry Andric Child.second->print(Writer, to_string(Child.first)); 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric } 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric // This function returns the size of the entire resource tree, including 5620b57cec5SDimitry Andric // directory tables, directory entries, and data entries. It does not include 5630b57cec5SDimitry Andric // the directory strings or the relocations of the .rsrc section. 5640b57cec5SDimitry Andric uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { 5650b57cec5SDimitry Andric uint32_t Size = (IDChildren.size() + StringChildren.size()) * 5660b57cec5SDimitry Andric sizeof(coff_resource_dir_entry); 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric // Reached a node pointing to a data entry. 5690b57cec5SDimitry Andric if (IsDataNode) { 5700b57cec5SDimitry Andric Size += sizeof(coff_resource_data_entry); 5710b57cec5SDimitry Andric return Size; 5720b57cec5SDimitry Andric } 5730b57cec5SDimitry Andric 5740b57cec5SDimitry Andric // If the node does not point to data, it must have a directory table pointing 5750b57cec5SDimitry Andric // to other nodes. 5760b57cec5SDimitry Andric Size += sizeof(coff_resource_dir_table); 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric for (auto const &Child : StringChildren) { 5790b57cec5SDimitry Andric Size += Child.second->getTreeSize(); 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric for (auto const &Child : IDChildren) { 5820b57cec5SDimitry Andric Size += Child.second->getTreeSize(); 5830b57cec5SDimitry Andric } 5840b57cec5SDimitry Andric return Size; 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric 5878bcb0991SDimitry Andric // Shift DataIndex of all data children with an Index greater or equal to the 5888bcb0991SDimitry Andric // given one, to fill a gap from removing an entry from the Data vector. 5898bcb0991SDimitry Andric void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) { 5908bcb0991SDimitry Andric if (IsDataNode && DataIndex >= Index) { 5918bcb0991SDimitry Andric DataIndex--; 5928bcb0991SDimitry Andric } else { 5938bcb0991SDimitry Andric for (auto &Child : IDChildren) 5948bcb0991SDimitry Andric Child.second->shiftDataIndexDown(Index); 5958bcb0991SDimitry Andric for (auto &Child : StringChildren) 5968bcb0991SDimitry Andric Child.second->shiftDataIndexDown(Index); 5978bcb0991SDimitry Andric } 5988bcb0991SDimitry Andric } 5998bcb0991SDimitry Andric 6000b57cec5SDimitry Andric class WindowsResourceCOFFWriter { 6010b57cec5SDimitry Andric public: 6020b57cec5SDimitry Andric WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, 6030b57cec5SDimitry Andric const WindowsResourceParser &Parser, Error &E); 6040b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp); 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric private: 6070b57cec5SDimitry Andric void performFileLayout(); 6080b57cec5SDimitry Andric void performSectionOneLayout(); 6090b57cec5SDimitry Andric void performSectionTwoLayout(); 6100b57cec5SDimitry Andric void writeCOFFHeader(uint32_t TimeDateStamp); 6110b57cec5SDimitry Andric void writeFirstSectionHeader(); 6120b57cec5SDimitry Andric void writeSecondSectionHeader(); 6130b57cec5SDimitry Andric void writeFirstSection(); 6140b57cec5SDimitry Andric void writeSecondSection(); 6150b57cec5SDimitry Andric void writeSymbolTable(); 6160b57cec5SDimitry Andric void writeStringTable(); 6170b57cec5SDimitry Andric void writeDirectoryTree(); 6180b57cec5SDimitry Andric void writeDirectoryStringTable(); 6190b57cec5SDimitry Andric void writeFirstSectionRelocations(); 6200b57cec5SDimitry Andric std::unique_ptr<WritableMemoryBuffer> OutputBuffer; 6210b57cec5SDimitry Andric char *BufferStart; 6220b57cec5SDimitry Andric uint64_t CurrentOffset = 0; 6230b57cec5SDimitry Andric COFF::MachineTypes MachineType; 6240b57cec5SDimitry Andric const WindowsResourceParser::TreeNode &Resources; 6250b57cec5SDimitry Andric const ArrayRef<std::vector<uint8_t>> Data; 6260b57cec5SDimitry Andric uint64_t FileSize; 6270b57cec5SDimitry Andric uint32_t SymbolTableOffset; 6280b57cec5SDimitry Andric uint32_t SectionOneSize; 6290b57cec5SDimitry Andric uint32_t SectionOneOffset; 6300b57cec5SDimitry Andric uint32_t SectionOneRelocations; 6310b57cec5SDimitry Andric uint32_t SectionTwoSize; 6320b57cec5SDimitry Andric uint32_t SectionTwoOffset; 6330b57cec5SDimitry Andric const ArrayRef<std::vector<UTF16>> StringTable; 6340b57cec5SDimitry Andric std::vector<uint32_t> StringTableOffsets; 6350b57cec5SDimitry Andric std::vector<uint32_t> DataOffsets; 6360b57cec5SDimitry Andric std::vector<uint32_t> RelocationAddresses; 6370b57cec5SDimitry Andric }; 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric WindowsResourceCOFFWriter::WindowsResourceCOFFWriter( 6400b57cec5SDimitry Andric COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, 6410b57cec5SDimitry Andric Error &E) 6420b57cec5SDimitry Andric : MachineType(MachineType), Resources(Parser.getTree()), 6430b57cec5SDimitry Andric Data(Parser.getData()), StringTable(Parser.getStringTable()) { 6440b57cec5SDimitry Andric performFileLayout(); 6450b57cec5SDimitry Andric 6460b57cec5SDimitry Andric OutputBuffer = WritableMemoryBuffer::getNewMemBuffer( 6470b57cec5SDimitry Andric FileSize, "internal .obj file created from .res files"); 6480b57cec5SDimitry Andric } 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric void WindowsResourceCOFFWriter::performFileLayout() { 6510b57cec5SDimitry Andric // Add size of COFF header. 6520b57cec5SDimitry Andric FileSize = COFF::Header16Size; 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric // one .rsrc section header for directory tree, another for resource data. 6550b57cec5SDimitry Andric FileSize += 2 * COFF::SectionSize; 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric performSectionOneLayout(); 6580b57cec5SDimitry Andric performSectionTwoLayout(); 6590b57cec5SDimitry Andric 6600b57cec5SDimitry Andric // We have reached the address of the symbol table. 6610b57cec5SDimitry Andric SymbolTableOffset = FileSize; 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol. 6640b57cec5SDimitry Andric FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section. 6650b57cec5SDimitry Andric FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource. 6660b57cec5SDimitry Andric FileSize += 4; // four null bytes for the string table. 6670b57cec5SDimitry Andric } 6680b57cec5SDimitry Andric 6690b57cec5SDimitry Andric void WindowsResourceCOFFWriter::performSectionOneLayout() { 6700b57cec5SDimitry Andric SectionOneOffset = FileSize; 6710b57cec5SDimitry Andric 6720b57cec5SDimitry Andric SectionOneSize = Resources.getTreeSize(); 6730b57cec5SDimitry Andric uint32_t CurrentStringOffset = SectionOneSize; 6740b57cec5SDimitry Andric uint32_t TotalStringTableSize = 0; 6750b57cec5SDimitry Andric for (auto const &String : StringTable) { 6760b57cec5SDimitry Andric StringTableOffsets.push_back(CurrentStringOffset); 6770b57cec5SDimitry Andric uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t); 6780b57cec5SDimitry Andric CurrentStringOffset += StringSize; 6790b57cec5SDimitry Andric TotalStringTableSize += StringSize; 6800b57cec5SDimitry Andric } 6810b57cec5SDimitry Andric SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t)); 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric // account for the relocations of section one. 6840b57cec5SDimitry Andric SectionOneRelocations = FileSize + SectionOneSize; 6850b57cec5SDimitry Andric FileSize += SectionOneSize; 6860b57cec5SDimitry Andric FileSize += 6870b57cec5SDimitry Andric Data.size() * COFF::RelocationSize; // one relocation for each resource. 6880b57cec5SDimitry Andric FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 6890b57cec5SDimitry Andric } 6900b57cec5SDimitry Andric 6910b57cec5SDimitry Andric void WindowsResourceCOFFWriter::performSectionTwoLayout() { 6920b57cec5SDimitry Andric // add size of .rsrc$2 section, which contains all resource data on 8-byte 6930b57cec5SDimitry Andric // alignment. 6940b57cec5SDimitry Andric SectionTwoOffset = FileSize; 6950b57cec5SDimitry Andric SectionTwoSize = 0; 6960b57cec5SDimitry Andric for (auto const &Entry : Data) { 6970b57cec5SDimitry Andric DataOffsets.push_back(SectionTwoSize); 6980b57cec5SDimitry Andric SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t)); 6990b57cec5SDimitry Andric } 7000b57cec5SDimitry Andric FileSize += SectionTwoSize; 7010b57cec5SDimitry Andric FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> 7050b57cec5SDimitry Andric WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) { 7060b57cec5SDimitry Andric BufferStart = OutputBuffer->getBufferStart(); 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric writeCOFFHeader(TimeDateStamp); 7090b57cec5SDimitry Andric writeFirstSectionHeader(); 7100b57cec5SDimitry Andric writeSecondSectionHeader(); 7110b57cec5SDimitry Andric writeFirstSection(); 7120b57cec5SDimitry Andric writeSecondSection(); 7130b57cec5SDimitry Andric writeSymbolTable(); 7140b57cec5SDimitry Andric writeStringTable(); 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric return std::move(OutputBuffer); 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric 7198bcb0991SDimitry Andric // According to COFF specification, if the Src has a size equal to Dest, 7208bcb0991SDimitry Andric // it's okay to *not* copy the trailing zero. 7218bcb0991SDimitry Andric static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) { 7228bcb0991SDimitry Andric assert(Src.size() <= COFF::NameSize && 7235ffd83dbSDimitry Andric "Src is larger than COFF::NameSize"); 7245ffd83dbSDimitry Andric assert((Src.size() == COFF::NameSize || Dest[Src.size()] == '\0') && 7255ffd83dbSDimitry Andric "Dest not zeroed upon initialization"); 7265ffd83dbSDimitry Andric memcpy(Dest, Src.data(), Src.size()); 7278bcb0991SDimitry Andric } 7288bcb0991SDimitry Andric 7290b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) { 7300b57cec5SDimitry Andric // Write the COFF header. 7310b57cec5SDimitry Andric auto *Header = reinterpret_cast<coff_file_header *>(BufferStart); 7320b57cec5SDimitry Andric Header->Machine = MachineType; 7330b57cec5SDimitry Andric Header->NumberOfSections = 2; 7340b57cec5SDimitry Andric Header->TimeDateStamp = TimeDateStamp; 7350b57cec5SDimitry Andric Header->PointerToSymbolTable = SymbolTableOffset; 7360b57cec5SDimitry Andric // One symbol for every resource plus 2 for each section and 1 for @feat.00 7370b57cec5SDimitry Andric Header->NumberOfSymbols = Data.size() + 5; 7380b57cec5SDimitry Andric Header->SizeOfOptionalHeader = 0; 7390b57cec5SDimitry Andric // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it. 7400b57cec5SDimitry Andric Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeFirstSectionHeader() { 7440b57cec5SDimitry Andric // Write the first section header. 7450b57cec5SDimitry Andric CurrentOffset += sizeof(coff_file_header); 7460b57cec5SDimitry Andric auto *SectionOneHeader = 7470b57cec5SDimitry Andric reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 7488bcb0991SDimitry Andric coffnamecpy(SectionOneHeader->Name, ".rsrc$01"); 7490b57cec5SDimitry Andric SectionOneHeader->VirtualSize = 0; 7500b57cec5SDimitry Andric SectionOneHeader->VirtualAddress = 0; 7510b57cec5SDimitry Andric SectionOneHeader->SizeOfRawData = SectionOneSize; 7520b57cec5SDimitry Andric SectionOneHeader->PointerToRawData = SectionOneOffset; 7530b57cec5SDimitry Andric SectionOneHeader->PointerToRelocations = SectionOneRelocations; 7540b57cec5SDimitry Andric SectionOneHeader->PointerToLinenumbers = 0; 7550b57cec5SDimitry Andric SectionOneHeader->NumberOfRelocations = Data.size(); 7560b57cec5SDimitry Andric SectionOneHeader->NumberOfLinenumbers = 0; 7570b57cec5SDimitry Andric SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 7580b57cec5SDimitry Andric SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 7590b57cec5SDimitry Andric } 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeSecondSectionHeader() { 7620b57cec5SDimitry Andric // Write the second section header. 7630b57cec5SDimitry Andric CurrentOffset += sizeof(coff_section); 7640b57cec5SDimitry Andric auto *SectionTwoHeader = 7650b57cec5SDimitry Andric reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 7668bcb0991SDimitry Andric coffnamecpy(SectionTwoHeader->Name, ".rsrc$02"); 7670b57cec5SDimitry Andric SectionTwoHeader->VirtualSize = 0; 7680b57cec5SDimitry Andric SectionTwoHeader->VirtualAddress = 0; 7690b57cec5SDimitry Andric SectionTwoHeader->SizeOfRawData = SectionTwoSize; 7700b57cec5SDimitry Andric SectionTwoHeader->PointerToRawData = SectionTwoOffset; 7710b57cec5SDimitry Andric SectionTwoHeader->PointerToRelocations = 0; 7720b57cec5SDimitry Andric SectionTwoHeader->PointerToLinenumbers = 0; 7730b57cec5SDimitry Andric SectionTwoHeader->NumberOfRelocations = 0; 7740b57cec5SDimitry Andric SectionTwoHeader->NumberOfLinenumbers = 0; 7750b57cec5SDimitry Andric SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 7760b57cec5SDimitry Andric SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 7770b57cec5SDimitry Andric } 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeFirstSection() { 7800b57cec5SDimitry Andric // Write section one. 7810b57cec5SDimitry Andric CurrentOffset += sizeof(coff_section); 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric writeDirectoryTree(); 7840b57cec5SDimitry Andric writeDirectoryStringTable(); 7850b57cec5SDimitry Andric writeFirstSectionRelocations(); 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 7880b57cec5SDimitry Andric } 7890b57cec5SDimitry Andric 7900b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeSecondSection() { 7910b57cec5SDimitry Andric // Now write the .rsrc$02 section. 7920b57cec5SDimitry Andric for (auto const &RawDataEntry : Data) { 7930b57cec5SDimitry Andric llvm::copy(RawDataEntry, BufferStart + CurrentOffset); 7940b57cec5SDimitry Andric CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t)); 7950b57cec5SDimitry Andric } 7960b57cec5SDimitry Andric 7970b57cec5SDimitry Andric CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeSymbolTable() { 8010b57cec5SDimitry Andric // Now write the symbol table. 8020b57cec5SDimitry Andric // First, the feat symbol. 8030b57cec5SDimitry Andric auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 8048bcb0991SDimitry Andric coffnamecpy(Symbol->Name.ShortName, "@feat.00"); 8050b57cec5SDimitry Andric Symbol->Value = 0x11; 8060b57cec5SDimitry Andric Symbol->SectionNumber = 0xffff; 8070b57cec5SDimitry Andric Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 8080b57cec5SDimitry Andric Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 8090b57cec5SDimitry Andric Symbol->NumberOfAuxSymbols = 0; 8100b57cec5SDimitry Andric CurrentOffset += sizeof(coff_symbol16); 8110b57cec5SDimitry Andric 8120b57cec5SDimitry Andric // Now write the .rsrc1 symbol + aux. 8130b57cec5SDimitry Andric Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 8148bcb0991SDimitry Andric coffnamecpy(Symbol->Name.ShortName, ".rsrc$01"); 8150b57cec5SDimitry Andric Symbol->Value = 0; 8160b57cec5SDimitry Andric Symbol->SectionNumber = 1; 8170b57cec5SDimitry Andric Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 8180b57cec5SDimitry Andric Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 8190b57cec5SDimitry Andric Symbol->NumberOfAuxSymbols = 1; 8200b57cec5SDimitry Andric CurrentOffset += sizeof(coff_symbol16); 8210b57cec5SDimitry Andric auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 8220b57cec5SDimitry Andric CurrentOffset); 8230b57cec5SDimitry Andric Aux->Length = SectionOneSize; 8240b57cec5SDimitry Andric Aux->NumberOfRelocations = Data.size(); 8250b57cec5SDimitry Andric Aux->NumberOfLinenumbers = 0; 8260b57cec5SDimitry Andric Aux->CheckSum = 0; 8270b57cec5SDimitry Andric Aux->NumberLowPart = 0; 8280b57cec5SDimitry Andric Aux->Selection = 0; 8290b57cec5SDimitry Andric CurrentOffset += sizeof(coff_aux_section_definition); 8300b57cec5SDimitry Andric 8310b57cec5SDimitry Andric // Now write the .rsrc2 symbol + aux. 8320b57cec5SDimitry Andric Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 8338bcb0991SDimitry Andric coffnamecpy(Symbol->Name.ShortName, ".rsrc$02"); 8340b57cec5SDimitry Andric Symbol->Value = 0; 8350b57cec5SDimitry Andric Symbol->SectionNumber = 2; 8360b57cec5SDimitry Andric Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 8370b57cec5SDimitry Andric Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 8380b57cec5SDimitry Andric Symbol->NumberOfAuxSymbols = 1; 8390b57cec5SDimitry Andric CurrentOffset += sizeof(coff_symbol16); 8400b57cec5SDimitry Andric Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 8410b57cec5SDimitry Andric CurrentOffset); 8420b57cec5SDimitry Andric Aux->Length = SectionTwoSize; 8430b57cec5SDimitry Andric Aux->NumberOfRelocations = 0; 8440b57cec5SDimitry Andric Aux->NumberOfLinenumbers = 0; 8450b57cec5SDimitry Andric Aux->CheckSum = 0; 8460b57cec5SDimitry Andric Aux->NumberLowPart = 0; 8470b57cec5SDimitry Andric Aux->Selection = 0; 8480b57cec5SDimitry Andric CurrentOffset += sizeof(coff_aux_section_definition); 8490b57cec5SDimitry Andric 8500b57cec5SDimitry Andric // Now write a symbol for each relocation. 8510b57cec5SDimitry Andric for (unsigned i = 0; i < Data.size(); i++) { 8520b57cec5SDimitry Andric auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>(); 8530b57cec5SDimitry Andric Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 8548bcb0991SDimitry Andric coffnamecpy(Symbol->Name.ShortName, RelocationName); 8550b57cec5SDimitry Andric Symbol->Value = DataOffsets[i]; 8560b57cec5SDimitry Andric Symbol->SectionNumber = 2; 8570b57cec5SDimitry Andric Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 8580b57cec5SDimitry Andric Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 8590b57cec5SDimitry Andric Symbol->NumberOfAuxSymbols = 0; 8600b57cec5SDimitry Andric CurrentOffset += sizeof(coff_symbol16); 8610b57cec5SDimitry Andric } 8620b57cec5SDimitry Andric } 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeStringTable() { 8650b57cec5SDimitry Andric // Just 4 null bytes for the string table. 8660b57cec5SDimitry Andric auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset); 8670b57cec5SDimitry Andric memset(COFFStringTable, 0, 4); 8680b57cec5SDimitry Andric } 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeDirectoryTree() { 8710b57cec5SDimitry Andric // Traverse parsed resource tree breadth-first and write the corresponding 8720b57cec5SDimitry Andric // COFF objects. 8730b57cec5SDimitry Andric std::queue<const WindowsResourceParser::TreeNode *> Queue; 8740b57cec5SDimitry Andric Queue.push(&Resources); 8750b57cec5SDimitry Andric uint32_t NextLevelOffset = 8760b57cec5SDimitry Andric sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() + 8770b57cec5SDimitry Andric Resources.getIDChildren().size()) * 8780b57cec5SDimitry Andric sizeof(coff_resource_dir_entry); 8790b57cec5SDimitry Andric std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder; 8800b57cec5SDimitry Andric uint32_t CurrentRelativeOffset = 0; 8810b57cec5SDimitry Andric 8820b57cec5SDimitry Andric while (!Queue.empty()) { 8830b57cec5SDimitry Andric auto CurrentNode = Queue.front(); 8840b57cec5SDimitry Andric Queue.pop(); 8850b57cec5SDimitry Andric auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart + 8860b57cec5SDimitry Andric CurrentOffset); 8870b57cec5SDimitry Andric Table->Characteristics = CurrentNode->getCharacteristics(); 8880b57cec5SDimitry Andric Table->TimeDateStamp = 0; 8890b57cec5SDimitry Andric Table->MajorVersion = CurrentNode->getMajorVersion(); 8900b57cec5SDimitry Andric Table->MinorVersion = CurrentNode->getMinorVersion(); 8910b57cec5SDimitry Andric auto &IDChildren = CurrentNode->getIDChildren(); 8920b57cec5SDimitry Andric auto &StringChildren = CurrentNode->getStringChildren(); 8930b57cec5SDimitry Andric Table->NumberOfNameEntries = StringChildren.size(); 8940b57cec5SDimitry Andric Table->NumberOfIDEntries = IDChildren.size(); 8950b57cec5SDimitry Andric CurrentOffset += sizeof(coff_resource_dir_table); 8960b57cec5SDimitry Andric CurrentRelativeOffset += sizeof(coff_resource_dir_table); 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric // Write the directory entries immediately following each directory table. 8990b57cec5SDimitry Andric for (auto const &Child : StringChildren) { 9000b57cec5SDimitry Andric auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 9010b57cec5SDimitry Andric CurrentOffset); 9020b57cec5SDimitry Andric Entry->Identifier.setNameOffset( 9030b57cec5SDimitry Andric StringTableOffsets[Child.second->getStringIndex()]); 9040b57cec5SDimitry Andric if (Child.second->checkIsDataNode()) { 9050b57cec5SDimitry Andric Entry->Offset.DataEntryOffset = NextLevelOffset; 9060b57cec5SDimitry Andric NextLevelOffset += sizeof(coff_resource_data_entry); 9070b57cec5SDimitry Andric DataEntriesTreeOrder.push_back(Child.second.get()); 9080b57cec5SDimitry Andric } else { 9090b57cec5SDimitry Andric Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 9100b57cec5SDimitry Andric NextLevelOffset += sizeof(coff_resource_dir_table) + 9110b57cec5SDimitry Andric (Child.second->getStringChildren().size() + 9120b57cec5SDimitry Andric Child.second->getIDChildren().size()) * 9130b57cec5SDimitry Andric sizeof(coff_resource_dir_entry); 9140b57cec5SDimitry Andric Queue.push(Child.second.get()); 9150b57cec5SDimitry Andric } 9160b57cec5SDimitry Andric CurrentOffset += sizeof(coff_resource_dir_entry); 9170b57cec5SDimitry Andric CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric for (auto const &Child : IDChildren) { 9200b57cec5SDimitry Andric auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 9210b57cec5SDimitry Andric CurrentOffset); 9220b57cec5SDimitry Andric Entry->Identifier.ID = Child.first; 9230b57cec5SDimitry Andric if (Child.second->checkIsDataNode()) { 9240b57cec5SDimitry Andric Entry->Offset.DataEntryOffset = NextLevelOffset; 9250b57cec5SDimitry Andric NextLevelOffset += sizeof(coff_resource_data_entry); 9260b57cec5SDimitry Andric DataEntriesTreeOrder.push_back(Child.second.get()); 9270b57cec5SDimitry Andric } else { 9280b57cec5SDimitry Andric Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 9290b57cec5SDimitry Andric NextLevelOffset += sizeof(coff_resource_dir_table) + 9300b57cec5SDimitry Andric (Child.second->getStringChildren().size() + 9310b57cec5SDimitry Andric Child.second->getIDChildren().size()) * 9320b57cec5SDimitry Andric sizeof(coff_resource_dir_entry); 9330b57cec5SDimitry Andric Queue.push(Child.second.get()); 9340b57cec5SDimitry Andric } 9350b57cec5SDimitry Andric CurrentOffset += sizeof(coff_resource_dir_entry); 9360b57cec5SDimitry Andric CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 9370b57cec5SDimitry Andric } 9380b57cec5SDimitry Andric } 9390b57cec5SDimitry Andric 9400b57cec5SDimitry Andric RelocationAddresses.resize(Data.size()); 9410b57cec5SDimitry Andric // Now write all the resource data entries. 942bdd1243dSDimitry Andric for (const auto *DataNodes : DataEntriesTreeOrder) { 9430b57cec5SDimitry Andric auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart + 9440b57cec5SDimitry Andric CurrentOffset); 9450b57cec5SDimitry Andric RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset; 9460b57cec5SDimitry Andric Entry->DataRVA = 0; // Set to zero because it is a relocation. 9470b57cec5SDimitry Andric Entry->DataSize = Data[DataNodes->getDataIndex()].size(); 9480b57cec5SDimitry Andric Entry->Codepage = 0; 9490b57cec5SDimitry Andric Entry->Reserved = 0; 9500b57cec5SDimitry Andric CurrentOffset += sizeof(coff_resource_data_entry); 9510b57cec5SDimitry Andric CurrentRelativeOffset += sizeof(coff_resource_data_entry); 9520b57cec5SDimitry Andric } 9530b57cec5SDimitry Andric } 9540b57cec5SDimitry Andric 9550b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeDirectoryStringTable() { 9560b57cec5SDimitry Andric // Now write the directory string table for .rsrc$01 9570b57cec5SDimitry Andric uint32_t TotalStringTableSize = 0; 9580b57cec5SDimitry Andric for (auto &String : StringTable) { 9590b57cec5SDimitry Andric uint16_t Length = String.size(); 9600b57cec5SDimitry Andric support::endian::write16le(BufferStart + CurrentOffset, Length); 9610b57cec5SDimitry Andric CurrentOffset += sizeof(uint16_t); 9620b57cec5SDimitry Andric auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset); 9630b57cec5SDimitry Andric llvm::copy(String, Start); 9640b57cec5SDimitry Andric CurrentOffset += Length * sizeof(UTF16); 9650b57cec5SDimitry Andric TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t); 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric CurrentOffset += 9680b57cec5SDimitry Andric alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize; 9690b57cec5SDimitry Andric } 9700b57cec5SDimitry Andric 9710b57cec5SDimitry Andric void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric // Now write the relocations for .rsrc$01 9740b57cec5SDimitry Andric // Five symbols already in table before we start, @feat.00 and 2 for each 9750b57cec5SDimitry Andric // .rsrc section. 9760b57cec5SDimitry Andric uint32_t NextSymbolIndex = 5; 9770b57cec5SDimitry Andric for (unsigned i = 0; i < Data.size(); i++) { 9780b57cec5SDimitry Andric auto *Reloc = 9790b57cec5SDimitry Andric reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset); 9800b57cec5SDimitry Andric Reloc->VirtualAddress = RelocationAddresses[i]; 9810b57cec5SDimitry Andric Reloc->SymbolTableIndex = NextSymbolIndex++; 982*0fca6ea1SDimitry Andric switch (getMachineArchType(MachineType)) { 983*0fca6ea1SDimitry Andric case Triple::thumb: 9840b57cec5SDimitry Andric Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB; 9850b57cec5SDimitry Andric break; 986*0fca6ea1SDimitry Andric case Triple::x86_64: 9870b57cec5SDimitry Andric Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB; 9880b57cec5SDimitry Andric break; 989*0fca6ea1SDimitry Andric case Triple::x86: 9900b57cec5SDimitry Andric Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; 9910b57cec5SDimitry Andric break; 992*0fca6ea1SDimitry Andric case Triple::aarch64: 9930b57cec5SDimitry Andric Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB; 9940b57cec5SDimitry Andric break; 9950b57cec5SDimitry Andric default: 9960b57cec5SDimitry Andric llvm_unreachable("unknown machine type"); 9970b57cec5SDimitry Andric } 9980b57cec5SDimitry Andric CurrentOffset += sizeof(coff_relocation); 9990b57cec5SDimitry Andric } 10000b57cec5SDimitry Andric } 10010b57cec5SDimitry Andric 10020b57cec5SDimitry Andric Expected<std::unique_ptr<MemoryBuffer>> 10030b57cec5SDimitry Andric writeWindowsResourceCOFF(COFF::MachineTypes MachineType, 10040b57cec5SDimitry Andric const WindowsResourceParser &Parser, 10050b57cec5SDimitry Andric uint32_t TimeDateStamp) { 10060b57cec5SDimitry Andric Error E = Error::success(); 10070b57cec5SDimitry Andric WindowsResourceCOFFWriter Writer(MachineType, Parser, E); 10080b57cec5SDimitry Andric if (E) 1009*0fca6ea1SDimitry Andric return E; 10100b57cec5SDimitry Andric return Writer.write(TimeDateStamp); 10110b57cec5SDimitry Andric } 10120b57cec5SDimitry Andric 10130b57cec5SDimitry Andric } // namespace object 10140b57cec5SDimitry Andric } // namespace llvm 1015