]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Object/WindowsResource.cpp
Merge ^/head r320042 through r320397.
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Object / WindowsResource.cpp
1 //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the .res file class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/Object/WindowsResource.h"
15 #include "llvm/Object/COFF.h"
16 #include "llvm/Support/FileOutputBuffer.h"
17 #include "llvm/Support/MathExtras.h"
18 #include <ctime>
19 #include <queue>
20 #include <sstream>
21 #include <system_error>
22
23 using namespace llvm;
24 using namespace object;
25
26 namespace llvm {
27 namespace object {
28
29 #define RETURN_IF_ERROR(X)                                                     \
30   if (auto EC = X)                                                             \
31     return EC;
32
33 const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
34
35 // COFF files seem to be inconsistent with alignment between sections, just use
36 // 8-byte because it makes everyone happy.
37 const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
38
39 uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
40 uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
41
42 WindowsResource::WindowsResource(MemoryBufferRef Source)
43     : Binary(Binary::ID_WinRes, Source) {
44   size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
45   BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
46                          support::little);
47 }
48
49 Expected<std::unique_ptr<WindowsResource>>
50 WindowsResource::createWindowsResource(MemoryBufferRef Source) {
51   if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
52     return make_error<GenericBinaryError>(
53         "File too small to be a resource file",
54         object_error::invalid_file_type);
55   std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
56   return std::move(Ret);
57 }
58
59 Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
60   Error Err = Error::success();
61   auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
62   if (Err)
63     return std::move(Err);
64   return Ref;
65 }
66
67 ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
68                                    const WindowsResource *Owner, Error &Err)
69     : Reader(Ref), OwningRes(Owner) {
70   if (loadNext())
71     Err = make_error<GenericBinaryError>("Could not read first entry.\n",
72                                          object_error::unexpected_eof);
73 }
74
75 Error ResourceEntryRef::moveNext(bool &End) {
76   // Reached end of all the entries.
77   if (Reader.bytesRemaining() == 0) {
78     End = true;
79     return Error::success();
80   }
81   RETURN_IF_ERROR(loadNext());
82
83   return Error::success();
84 }
85
86 static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
87                             ArrayRef<UTF16> &Str, bool &IsString) {
88   uint16_t IDFlag;
89   RETURN_IF_ERROR(Reader.readInteger(IDFlag));
90   IsString = IDFlag != 0xffff;
91
92   if (IsString) {
93     Reader.setOffset(
94         Reader.getOffset() -
95         sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
96     RETURN_IF_ERROR(Reader.readWideString(Str));
97   } else
98     RETURN_IF_ERROR(Reader.readInteger(ID));
99
100   return Error::success();
101 }
102
103 Error ResourceEntryRef::loadNext() {
104   const WinResHeaderPrefix *Prefix;
105   RETURN_IF_ERROR(Reader.readObject(Prefix));
106
107   if (Prefix->HeaderSize < MIN_HEADER_SIZE)
108     return make_error<GenericBinaryError>("Header size is too small.",
109                                           object_error::parse_failed);
110
111   RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
112
113   RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
114
115   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
116
117   RETURN_IF_ERROR(Reader.readObject(Suffix));
118
119   RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
120
121   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
122
123   return Error::success();
124 }
125
126 WindowsResourceParser::WindowsResourceParser() : Root(false) {}
127
128 Error WindowsResourceParser::parse(WindowsResource *WR) {
129   auto EntryOrErr = WR->getHeadEntry();
130   if (!EntryOrErr)
131     return EntryOrErr.takeError();
132
133   ResourceEntryRef Entry = EntryOrErr.get();
134   bool End = false;
135   while (!End) {
136     Data.push_back(Entry.getData());
137
138     bool IsNewTypeString = false;
139     bool IsNewNameString = false;
140
141     Root.addEntry(Entry, IsNewTypeString, IsNewNameString);
142
143     if (IsNewTypeString)
144       StringTable.push_back(Entry.getTypeString());
145
146     if (IsNewNameString)
147       StringTable.push_back(Entry.getNameString());
148
149     RETURN_IF_ERROR(Entry.moveNext(End));
150   }
151
152   return Error::success();
153 }
154
155 void WindowsResourceParser::printTree(raw_ostream &OS) const {
156   ScopedPrinter Writer(OS);
157   Root.print(Writer, "Resource Tree");
158 }
159
160 void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
161                                                bool &IsNewTypeString,
162                                                bool &IsNewNameString) {
163   TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
164   TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
165   NameNode.addLanguageNode(Entry);
166 }
167
168 WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
169   if (IsStringNode)
170     StringIndex = StringCount++;
171 }
172
173 WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
174                                           uint16_t MinorVersion,
175                                           uint32_t Characteristics)
176     : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
177       Characteristics(Characteristics) {
178     DataIndex = DataCount++;
179 }
180
181 std::unique_ptr<WindowsResourceParser::TreeNode>
182 WindowsResourceParser::TreeNode::createStringNode() {
183   return std::unique_ptr<TreeNode>(new TreeNode(true));
184 }
185
186 std::unique_ptr<WindowsResourceParser::TreeNode>
187 WindowsResourceParser::TreeNode::createIDNode() {
188   return std::unique_ptr<TreeNode>(new TreeNode(false));
189 }
190
191 std::unique_ptr<WindowsResourceParser::TreeNode>
192 WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
193                                                 uint16_t MinorVersion,
194                                                 uint32_t Characteristics) {
195   return std::unique_ptr<TreeNode>(
196       new TreeNode(MajorVersion, MinorVersion, Characteristics));
197 }
198
199 WindowsResourceParser::TreeNode &
200 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry,
201                                              bool &IsNewTypeString) {
202   if (Entry.checkTypeString())
203     return addChild(Entry.getTypeString(), IsNewTypeString);
204   else
205     return addChild(Entry.getTypeID());
206 }
207
208 WindowsResourceParser::TreeNode &
209 WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry,
210                                              bool &IsNewNameString) {
211   if (Entry.checkNameString())
212     return addChild(Entry.getNameString(), IsNewNameString);
213   else
214     return addChild(Entry.getNameID());
215 }
216
217 WindowsResourceParser::TreeNode &
218 WindowsResourceParser::TreeNode::addLanguageNode(
219     const ResourceEntryRef &Entry) {
220   return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
221                   Entry.getMinorVersion(), Entry.getCharacteristics());
222 }
223
224 WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(
225     uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
226     uint32_t Characteristics) {
227   auto Child = IDChildren.find(ID);
228   if (Child == IDChildren.end()) {
229     auto NewChild =
230         IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
231                    : createIDNode();
232     WindowsResourceParser::TreeNode &Node = *NewChild;
233     IDChildren.emplace(ID, std::move(NewChild));
234     return Node;
235   } else
236     return *(Child->second);
237 }
238
239 WindowsResourceParser::TreeNode &
240 WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef,
241                                           bool &IsNewString) {
242   std::string NameString;
243   ArrayRef<UTF16> CorrectedName;
244   std::vector<UTF16> EndianCorrectedName;
245   if (sys::IsBigEndianHost) {
246     EndianCorrectedName.resize(NameRef.size() + 1);
247     std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1);
248     EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
249     CorrectedName = makeArrayRef(EndianCorrectedName);
250   } else
251     CorrectedName = NameRef;
252   convertUTF16ToUTF8String(CorrectedName, NameString);
253
254   auto Child = StringChildren.find(NameString);
255   if (Child == StringChildren.end()) {
256     auto NewChild = createStringNode();
257     IsNewString = true;
258     WindowsResourceParser::TreeNode &Node = *NewChild;
259     StringChildren.emplace(NameString, std::move(NewChild));
260     return Node;
261   } else
262     return *(Child->second);
263 }
264
265 void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
266                                             StringRef Name) const {
267   ListScope NodeScope(Writer, Name);
268   for (auto const &Child : StringChildren) {
269     Child.second->print(Writer, Child.first);
270   }
271   for (auto const &Child : IDChildren) {
272     Child.second->print(Writer, to_string(Child.first));
273   }
274 }
275
276 // This function returns the size of the entire resource tree, including
277 // directory tables, directory entries, and data entries.  It does not include
278 // the directory strings or the relocations of the .rsrc section.
279 uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
280   uint32_t Size = (IDChildren.size() + StringChildren.size()) *
281                   sizeof(coff_resource_dir_entry);
282
283   // Reached a node pointing to a data entry.
284   if (IsDataNode) {
285     Size += sizeof(coff_resource_data_entry);
286     return Size;
287   }
288
289   // If the node does not point to data, it must have a directory table pointing
290   // to other nodes.
291   Size += sizeof(coff_resource_dir_table);
292
293   for (auto const &Child : StringChildren) {
294     Size += Child.second->getTreeSize();
295   }
296   for (auto const &Child : IDChildren) {
297     Size += Child.second->getTreeSize();
298   }
299   return Size;
300 }
301
302 class WindowsResourceCOFFWriter {
303 public:
304   WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
305                             const WindowsResourceParser &Parser, Error &E);
306   std::unique_ptr<MemoryBuffer> write();
307
308 private:
309   void performFileLayout();
310   void performSectionOneLayout();
311   void performSectionTwoLayout();
312   void writeCOFFHeader();
313   void writeFirstSectionHeader();
314   void writeSecondSectionHeader();
315   void writeFirstSection();
316   void writeSecondSection();
317   void writeSymbolTable();
318   void writeStringTable();
319   void writeDirectoryTree();
320   void writeDirectoryStringTable();
321   void writeFirstSectionRelocations();
322   std::unique_ptr<MemoryBuffer> OutputBuffer;
323   char *BufferStart;
324   uint64_t CurrentOffset = 0;
325   COFF::MachineTypes MachineType;
326   const WindowsResourceParser::TreeNode &Resources;
327   const ArrayRef<std::vector<uint8_t>> Data;
328   uint64_t FileSize;
329   uint32_t SymbolTableOffset;
330   uint32_t SectionOneSize;
331   uint32_t SectionOneOffset;
332   uint32_t SectionOneRelocations;
333   uint32_t SectionTwoSize;
334   uint32_t SectionTwoOffset;
335   const ArrayRef<std::vector<UTF16>> StringTable;
336   std::vector<uint32_t> StringTableOffsets;
337   std::vector<uint32_t> DataOffsets;
338   std::vector<uint32_t> RelocationAddresses;
339 };
340
341 WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
342     COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
343     Error &E)
344     : MachineType(MachineType), Resources(Parser.getTree()),
345       Data(Parser.getData()), StringTable(Parser.getStringTable()) {
346   performFileLayout();
347
348   OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize);
349 }
350
351 void WindowsResourceCOFFWriter::performFileLayout() {
352   // Add size of COFF header.
353   FileSize = COFF::Header16Size;
354
355   // one .rsrc section header for directory tree, another for resource data.
356   FileSize += 2 * COFF::SectionSize;
357
358   performSectionOneLayout();
359   performSectionTwoLayout();
360
361   // We have reached the address of the symbol table.
362   SymbolTableOffset = FileSize;
363
364   FileSize += COFF::Symbol16Size;     // size of the @feat.00 symbol.
365   FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
366   FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
367   FileSize += 4; // four null bytes for the string table.
368 }
369
370 void WindowsResourceCOFFWriter::performSectionOneLayout() {
371   SectionOneOffset = FileSize;
372
373   SectionOneSize = Resources.getTreeSize();
374   uint32_t CurrentStringOffset = SectionOneSize;
375   uint32_t TotalStringTableSize = 0;
376   for (auto const &String : StringTable) {
377     StringTableOffsets.push_back(CurrentStringOffset);
378     uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
379     CurrentStringOffset += StringSize;
380     TotalStringTableSize += StringSize;
381   }
382   SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
383
384   // account for the relocations of section one.
385   SectionOneRelocations = FileSize + SectionOneSize;
386   FileSize += SectionOneSize;
387   FileSize +=
388       Data.size() * COFF::RelocationSize; // one relocation for each resource.
389   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
390 }
391
392 void WindowsResourceCOFFWriter::performSectionTwoLayout() {
393   // add size of .rsrc$2 section, which contains all resource data on 8-byte
394   // alignment.
395   SectionTwoOffset = FileSize;
396   SectionTwoSize = 0;
397   for (auto const &Entry : Data) {
398     DataOffsets.push_back(SectionTwoSize);
399     SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
400   }
401   FileSize += SectionTwoSize;
402   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
403 }
404
405 static std::time_t getTime() {
406   std::time_t Now = time(nullptr);
407   if (Now < 0 || !isUInt<32>(Now))
408     return UINT32_MAX;
409   return Now;
410 }
411
412 std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() {
413   BufferStart = const_cast<char *>(OutputBuffer->getBufferStart());
414
415   writeCOFFHeader();
416   writeFirstSectionHeader();
417   writeSecondSectionHeader();
418   writeFirstSection();
419   writeSecondSection();
420   writeSymbolTable();
421   writeStringTable();
422
423   return std::move(OutputBuffer);
424 }
425
426 void WindowsResourceCOFFWriter::writeCOFFHeader() {
427   // Write the COFF header.
428   auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
429   switch (MachineType) {
430   case COFF::IMAGE_FILE_MACHINE_ARMNT:
431     Header->Machine = COFF::IMAGE_FILE_MACHINE_ARMNT;
432     break;
433   case COFF::IMAGE_FILE_MACHINE_AMD64:
434     Header->Machine = COFF::IMAGE_FILE_MACHINE_AMD64;
435     break;
436   case COFF::IMAGE_FILE_MACHINE_I386:
437     Header->Machine = COFF::IMAGE_FILE_MACHINE_I386;
438     break;
439   default:
440     Header->Machine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
441   }
442   Header->NumberOfSections = 2;
443   Header->TimeDateStamp = getTime();
444   Header->PointerToSymbolTable = SymbolTableOffset;
445   // One symbol for every resource plus 2 for each section and @feat.00
446   Header->NumberOfSymbols = Data.size() + 5;
447   Header->SizeOfOptionalHeader = 0;
448   Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
449 }
450
451 void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
452   // Write the first section header.
453   CurrentOffset += sizeof(coff_file_header);
454   auto *SectionOneHeader =
455       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
456   strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize);
457   SectionOneHeader->VirtualSize = 0;
458   SectionOneHeader->VirtualAddress = 0;
459   SectionOneHeader->SizeOfRawData = SectionOneSize;
460   SectionOneHeader->PointerToRawData = SectionOneOffset;
461   SectionOneHeader->PointerToRelocations = SectionOneRelocations;
462   SectionOneHeader->PointerToLinenumbers = 0;
463   SectionOneHeader->NumberOfRelocations = Data.size();
464   SectionOneHeader->NumberOfLinenumbers = 0;
465   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
466   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
467 }
468
469 void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
470   // Write the second section header.
471   CurrentOffset += sizeof(coff_section);
472   auto *SectionTwoHeader =
473       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
474   strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize);
475   SectionTwoHeader->VirtualSize = 0;
476   SectionTwoHeader->VirtualAddress = 0;
477   SectionTwoHeader->SizeOfRawData = SectionTwoSize;
478   SectionTwoHeader->PointerToRawData = SectionTwoOffset;
479   SectionTwoHeader->PointerToRelocations = 0;
480   SectionTwoHeader->PointerToLinenumbers = 0;
481   SectionTwoHeader->NumberOfRelocations = 0;
482   SectionTwoHeader->NumberOfLinenumbers = 0;
483   SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
484   SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
485 }
486
487 void WindowsResourceCOFFWriter::writeFirstSection() {
488   // Write section one.
489   CurrentOffset += sizeof(coff_section);
490
491   writeDirectoryTree();
492   writeDirectoryStringTable();
493   writeFirstSectionRelocations();
494
495   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
496 }
497
498 void WindowsResourceCOFFWriter::writeSecondSection() {
499   // Now write the .rsrc$02 section.
500   for (auto const &RawDataEntry : Data) {
501     std::copy(RawDataEntry.begin(), RawDataEntry.end(),
502               BufferStart + CurrentOffset);
503     CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
504   }
505
506   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
507 }
508
509 void WindowsResourceCOFFWriter::writeSymbolTable() {
510   // Now write the symbol table.
511   // First, the feat symbol.
512   auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
513   strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize);
514   Symbol->Value = 0x11;
515   Symbol->SectionNumber = 0xffff;
516   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
517   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
518   Symbol->NumberOfAuxSymbols = 0;
519   CurrentOffset += sizeof(coff_symbol16);
520
521   // Now write the .rsrc1 symbol + aux.
522   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
523   strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize);
524   Symbol->Value = 0;
525   Symbol->SectionNumber = 1;
526   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
527   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
528   Symbol->NumberOfAuxSymbols = 1;
529   CurrentOffset += sizeof(coff_symbol16);
530   auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
531                                                               CurrentOffset);
532   Aux->Length = SectionOneSize;
533   Aux->NumberOfRelocations = Data.size();
534   Aux->NumberOfLinenumbers = 0;
535   Aux->CheckSum = 0;
536   Aux->NumberLowPart = 0;
537   Aux->Selection = 0;
538   CurrentOffset += sizeof(coff_aux_section_definition);
539
540   // Now write the .rsrc2 symbol + aux.
541   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
542   strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize);
543   Symbol->Value = 0;
544   Symbol->SectionNumber = 2;
545   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
546   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
547   Symbol->NumberOfAuxSymbols = 1;
548   CurrentOffset += sizeof(coff_symbol16);
549   Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
550                                                         CurrentOffset);
551   Aux->Length = SectionTwoSize;
552   Aux->NumberOfRelocations = 0;
553   Aux->NumberOfLinenumbers = 0;
554   Aux->CheckSum = 0;
555   Aux->NumberLowPart = 0;
556   Aux->Selection = 0;
557   CurrentOffset += sizeof(coff_aux_section_definition);
558
559   // Now write a symbol for each relocation.
560   for (unsigned i = 0; i < Data.size(); i++) {
561     char RelocationName[9];
562     sprintf(RelocationName, "$R%06X", DataOffsets[i]);
563     Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
564     strncpy(Symbol->Name.ShortName, RelocationName, (size_t)COFF::NameSize);
565     Symbol->Value = DataOffsets[i];
566     Symbol->SectionNumber = 1;
567     Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
568     Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
569     Symbol->NumberOfAuxSymbols = 0;
570     CurrentOffset += sizeof(coff_symbol16);
571   }
572 }
573
574 void WindowsResourceCOFFWriter::writeStringTable() {
575   // Just 4 null bytes for the string table.
576   auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
577   memset(COFFStringTable, 0, 4);
578 }
579
580 void WindowsResourceCOFFWriter::writeDirectoryTree() {
581   // Traverse parsed resource tree breadth-first and write the corresponding
582   // COFF objects.
583   std::queue<const WindowsResourceParser::TreeNode *> Queue;
584   Queue.push(&Resources);
585   uint32_t NextLevelOffset =
586       sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
587                                          Resources.getIDChildren().size()) *
588                                             sizeof(coff_resource_dir_entry);
589   std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
590   uint32_t CurrentRelativeOffset = 0;
591
592   while (!Queue.empty()) {
593     auto CurrentNode = Queue.front();
594     Queue.pop();
595     auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
596                                                               CurrentOffset);
597     Table->Characteristics = CurrentNode->getCharacteristics();
598     Table->TimeDateStamp = 0;
599     Table->MajorVersion = CurrentNode->getMajorVersion();
600     Table->MinorVersion = CurrentNode->getMinorVersion();
601     auto &IDChildren = CurrentNode->getIDChildren();
602     auto &StringChildren = CurrentNode->getStringChildren();
603     Table->NumberOfNameEntries = StringChildren.size();
604     Table->NumberOfIDEntries = IDChildren.size();
605     CurrentOffset += sizeof(coff_resource_dir_table);
606     CurrentRelativeOffset += sizeof(coff_resource_dir_table);
607
608     // Write the directory entries immediately following each directory table.
609     for (auto const &Child : StringChildren) {
610       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
611                                                                 CurrentOffset);
612       Entry->Identifier.NameOffset =
613           StringTableOffsets[Child.second->getStringIndex()];
614       if (Child.second->checkIsDataNode()) {
615         Entry->Offset.DataEntryOffset = NextLevelOffset;
616         NextLevelOffset += sizeof(coff_resource_data_entry);
617         DataEntriesTreeOrder.push_back(Child.second.get());
618       } else {
619         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
620         NextLevelOffset += sizeof(coff_resource_dir_table) +
621                            (Child.second->getStringChildren().size() +
622                             Child.second->getIDChildren().size()) *
623                                sizeof(coff_resource_dir_entry);
624         Queue.push(Child.second.get());
625       }
626       CurrentOffset += sizeof(coff_resource_dir_entry);
627       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
628     }
629     for (auto const &Child : IDChildren) {
630       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
631                                                                 CurrentOffset);
632       Entry->Identifier.ID = Child.first;
633       if (Child.second->checkIsDataNode()) {
634         Entry->Offset.DataEntryOffset = NextLevelOffset;
635         NextLevelOffset += sizeof(coff_resource_data_entry);
636         DataEntriesTreeOrder.push_back(Child.second.get());
637       } else {
638         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
639         NextLevelOffset += sizeof(coff_resource_dir_table) +
640                            (Child.second->getStringChildren().size() +
641                             Child.second->getIDChildren().size()) *
642                                sizeof(coff_resource_dir_entry);
643         Queue.push(Child.second.get());
644       }
645       CurrentOffset += sizeof(coff_resource_dir_entry);
646       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
647     }
648   }
649
650   RelocationAddresses.resize(Data.size());
651   // Now write all the resource data entries.
652   for (auto DataNodes : DataEntriesTreeOrder) {
653     auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
654                                                                CurrentOffset);
655     RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
656     Entry->DataRVA = 0; // Set to zero because it is a relocation.
657     Entry->DataSize = Data[DataNodes->getDataIndex()].size();
658     Entry->Codepage = 0;
659     Entry->Reserved = 0;
660     CurrentOffset += sizeof(coff_resource_data_entry);
661     CurrentRelativeOffset += sizeof(coff_resource_data_entry);
662   }
663 }
664
665 void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
666   // Now write the directory string table for .rsrc$01
667   uint32_t TotalStringTableSize = 0;
668   for (auto &String : StringTable) {
669     uint16_t Length = String.size();
670     support::endian::write16le(BufferStart + CurrentOffset, Length);
671     CurrentOffset += sizeof(uint16_t);
672     auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
673     std::copy(String.begin(), String.end(), Start);
674     CurrentOffset += Length * sizeof(UTF16);
675     TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
676   }
677   CurrentOffset +=
678       alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
679 }
680
681 void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
682
683   // Now write the relocations for .rsrc$01
684   // Five symbols already in table before we start, @feat.00 and 2 for each
685   // .rsrc section.
686   uint32_t NextSymbolIndex = 5;
687   for (unsigned i = 0; i < Data.size(); i++) {
688     auto *Reloc =
689         reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
690     Reloc->VirtualAddress = RelocationAddresses[i];
691     Reloc->SymbolTableIndex = NextSymbolIndex++;
692     switch (MachineType) {
693     case COFF::IMAGE_FILE_MACHINE_ARMNT:
694       Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
695       break;
696     case COFF::IMAGE_FILE_MACHINE_AMD64:
697       Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
698       break;
699     case COFF::IMAGE_FILE_MACHINE_I386:
700       Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
701       break;
702     default:
703       Reloc->Type = 0;
704     }
705     CurrentOffset += sizeof(coff_relocation);
706   }
707 }
708
709 Expected<std::unique_ptr<MemoryBuffer>>
710 writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
711                          const WindowsResourceParser &Parser) {
712   Error E = Error::success();
713   WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
714   if (E)
715     return std::move(E);
716   return Writer.write();
717 }
718
719 } // namespace object
720 } // namespace llvm