LLVM  9.0.0svn
WindowsResource.cpp
Go to the documentation of this file.
1 //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the .res file class.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "llvm/Object/COFF.h"
18 #include <ctime>
19 #include <queue>
20 #include <system_error>
21 
22 using namespace llvm;
23 using namespace object;
24 
25 namespace llvm {
26 namespace object {
27 
28 #define RETURN_IF_ERROR(X) \
29  if (auto EC = X) \
30  return EC;
31 
32 const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
33 
34 // COFF files seem to be inconsistent with alignment between sections, just use
35 // 8-byte because it makes everyone happy.
36 const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
37 
38 uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
39 uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
40 
41 WindowsResource::WindowsResource(MemoryBufferRef Source)
42  : Binary(Binary::ID_WinRes, Source) {
43  size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
44  BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
46 }
47 
51  return make_error<GenericBinaryError>(
52  "File too small to be a resource file",
54  std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
55  return std::move(Ret);
56 }
57 
59  if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
60  return make_error<EmptyResError>(".res contains no entries",
62  return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
63 }
64 
65 ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
66  const WindowsResource *Owner)
67  : Reader(Ref) {}
68 
70 ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) {
71  auto Ref = ResourceEntryRef(BSR, Owner);
72  if (auto E = Ref.loadNext())
73  return std::move(E);
74  return Ref;
75 }
76 
78  // Reached end of all the entries.
79  if (Reader.bytesRemaining() == 0) {
80  End = true;
81  return Error::success();
82  }
83  RETURN_IF_ERROR(loadNext());
84 
85  return Error::success();
86 }
87 
88 static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
89  ArrayRef<UTF16> &Str, bool &IsString) {
90  uint16_t IDFlag;
91  RETURN_IF_ERROR(Reader.readInteger(IDFlag));
92  IsString = IDFlag != 0xffff;
93 
94  if (IsString) {
95  Reader.setOffset(
96  Reader.getOffset() -
97  sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
98  RETURN_IF_ERROR(Reader.readWideString(Str));
99  } else
100  RETURN_IF_ERROR(Reader.readInteger(ID));
101 
102  return Error::success();
103 }
104 
105 Error ResourceEntryRef::loadNext() {
106  const WinResHeaderPrefix *Prefix;
107  RETURN_IF_ERROR(Reader.readObject(Prefix));
108 
109  if (Prefix->HeaderSize < MIN_HEADER_SIZE)
110  return make_error<GenericBinaryError>("Header size is too small.",
112 
113  RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
114 
115  RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
116 
117  RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
118 
119  RETURN_IF_ERROR(Reader.readObject(Suffix));
120 
121  RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
122 
123  RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
124 
125  return Error::success();
126 }
127 
129 
131  auto EntryOrErr = WR->getHeadEntry();
132  if (!EntryOrErr) {
133  auto E = EntryOrErr.takeError();
134  if (E.isA<EmptyResError>()) {
135  // Check if the .res file contains no entries. In this case we don't have
136  // to throw an error but can rather just return without parsing anything.
137  // This applies for files which have a valid PE header magic and the
138  // mandatory empty null resource entry. Files which do not fit this
139  // criteria would have already been filtered out by
140  // WindowsResource::createWindowsResource().
141  consumeError(std::move(E));
142  return Error::success();
143  }
144  return E;
145  }
146 
147  ResourceEntryRef Entry = EntryOrErr.get();
148  bool End = false;
149  while (!End) {
150  Data.push_back(Entry.getData());
151 
152  bool IsNewTypeString = false;
153  bool IsNewNameString = false;
154 
155  Root.addEntry(Entry, IsNewTypeString, IsNewNameString);
156 
157  if (IsNewTypeString)
158  StringTable.push_back(Entry.getTypeString());
159 
160  if (IsNewNameString)
161  StringTable.push_back(Entry.getNameString());
162 
163  RETURN_IF_ERROR(Entry.moveNext(End));
164  }
165 
166  return Error::success();
167 }
168 
170  ScopedPrinter Writer(OS);
171  Root.print(Writer, "Resource Tree");
172 }
173 
174 void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
175  bool &IsNewTypeString,
176  bool &IsNewNameString) {
177  TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
178  TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
179  NameNode.addLanguageNode(Entry);
180 }
181 
182 WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
183  if (IsStringNode)
184  StringIndex = StringCount++;
185 }
186 
187 WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
188  uint16_t MinorVersion,
190  : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
191  Characteristics(Characteristics) {
192  DataIndex = DataCount++;
193 }
194 
195 std::unique_ptr<WindowsResourceParser::TreeNode>
196 WindowsResourceParser::TreeNode::createStringNode() {
197  return std::unique_ptr<TreeNode>(new TreeNode(true));
198 }
199 
200 std::unique_ptr<WindowsResourceParser::TreeNode>
201 WindowsResourceParser::TreeNode::createIDNode() {
202  return std::unique_ptr<TreeNode>(new TreeNode(false));
203 }
204 
205 std::unique_ptr<WindowsResourceParser::TreeNode>
206 WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
207  uint16_t MinorVersion,
208  uint32_t Characteristics) {
209  return std::unique_ptr<TreeNode>(
210  new TreeNode(MajorVersion, MinorVersion, Characteristics));
211 }
212 
214 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry,
215  bool &IsNewTypeString) {
216  if (Entry.checkTypeString())
217  return addChild(Entry.getTypeString(), IsNewTypeString);
218  else
219  return addChild(Entry.getTypeID());
220 }
221 
223 WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry,
224  bool &IsNewNameString) {
225  if (Entry.checkNameString())
226  return addChild(Entry.getNameString(), IsNewNameString);
227  else
228  return addChild(Entry.getNameID());
229 }
230 
232 WindowsResourceParser::TreeNode::addLanguageNode(
233  const ResourceEntryRef &Entry) {
234  return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
235  Entry.getMinorVersion(), Entry.getCharacteristics());
236 }
237 
238 WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(
239  uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
240  uint32_t Characteristics) {
241  auto Child = IDChildren.find(ID);
242  if (Child == IDChildren.end()) {
243  auto NewChild =
244  IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
245  : createIDNode();
246  WindowsResourceParser::TreeNode &Node = *NewChild;
247  IDChildren.emplace(ID, std::move(NewChild));
248  return Node;
249  } else
250  return *(Child->second);
251 }
252 
254 WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef,
255  bool &IsNewString) {
256  std::string NameString;
257  ArrayRef<UTF16> CorrectedName;
258  std::vector<UTF16> EndianCorrectedName;
259  if (sys::IsBigEndianHost) {
260  EndianCorrectedName.resize(NameRef.size() + 1);
261  llvm::copy(NameRef, EndianCorrectedName.begin() + 1);
262  EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
263  CorrectedName = makeArrayRef(EndianCorrectedName);
264  } else
265  CorrectedName = NameRef;
266  convertUTF16ToUTF8String(CorrectedName, NameString);
267 
268  auto Child = StringChildren.find(NameString);
269  if (Child == StringChildren.end()) {
270  auto NewChild = createStringNode();
271  IsNewString = true;
272  WindowsResourceParser::TreeNode &Node = *NewChild;
273  StringChildren.emplace(NameString, std::move(NewChild));
274  return Node;
275  } else
276  return *(Child->second);
277 }
278 
280  StringRef Name) const {
281  ListScope NodeScope(Writer, Name);
282  for (auto const &Child : StringChildren) {
283  Child.second->print(Writer, Child.first);
284  }
285  for (auto const &Child : IDChildren) {
286  Child.second->print(Writer, to_string(Child.first));
287  }
288 }
289 
290 // This function returns the size of the entire resource tree, including
291 // directory tables, directory entries, and data entries. It does not include
292 // the directory strings or the relocations of the .rsrc section.
294  uint32_t Size = (IDChildren.size() + StringChildren.size()) *
295  sizeof(coff_resource_dir_entry);
296 
297  // Reached a node pointing to a data entry.
298  if (IsDataNode) {
299  Size += sizeof(coff_resource_data_entry);
300  return Size;
301  }
302 
303  // If the node does not point to data, it must have a directory table pointing
304  // to other nodes.
305  Size += sizeof(coff_resource_dir_table);
306 
307  for (auto const &Child : StringChildren) {
308  Size += Child.second->getTreeSize();
309  }
310  for (auto const &Child : IDChildren) {
311  Size += Child.second->getTreeSize();
312  }
313  return Size;
314 }
315 
317 public:
320  std::unique_ptr<MemoryBuffer> write();
321 
322 private:
323  void performFileLayout();
324  void performSectionOneLayout();
325  void performSectionTwoLayout();
326  void writeCOFFHeader();
327  void writeFirstSectionHeader();
328  void writeSecondSectionHeader();
329  void writeFirstSection();
330  void writeSecondSection();
331  void writeSymbolTable();
332  void writeStringTable();
333  void writeDirectoryTree();
334  void writeDirectoryStringTable();
335  void writeFirstSectionRelocations();
336  std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
337  char *BufferStart;
338  uint64_t CurrentOffset = 0;
339  COFF::MachineTypes MachineType;
340  const WindowsResourceParser::TreeNode &Resources;
342  uint64_t FileSize;
343  uint32_t SymbolTableOffset;
344  uint32_t SectionOneSize;
345  uint32_t SectionOneOffset;
346  uint32_t SectionOneRelocations;
347  uint32_t SectionTwoSize;
348  uint32_t SectionTwoOffset;
349  const ArrayRef<std::vector<UTF16>> StringTable;
350  std::vector<uint32_t> StringTableOffsets;
351  std::vector<uint32_t> DataOffsets;
352  std::vector<uint32_t> RelocationAddresses;
353 };
354 
356  COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
357  Error &E)
358  : MachineType(MachineType), Resources(Parser.getTree()),
359  Data(Parser.getData()), StringTable(Parser.getStringTable()) {
360  performFileLayout();
361 
362  OutputBuffer = WritableMemoryBuffer::getNewMemBuffer(FileSize);
363 }
364 
365 void WindowsResourceCOFFWriter::performFileLayout() {
366  // Add size of COFF header.
367  FileSize = COFF::Header16Size;
368 
369  // one .rsrc section header for directory tree, another for resource data.
370  FileSize += 2 * COFF::SectionSize;
371 
372  performSectionOneLayout();
373  performSectionTwoLayout();
374 
375  // We have reached the address of the symbol table.
376  SymbolTableOffset = FileSize;
377 
378  FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol.
379  FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
380  FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
381  FileSize += 4; // four null bytes for the string table.
382 }
383 
384 void WindowsResourceCOFFWriter::performSectionOneLayout() {
385  SectionOneOffset = FileSize;
386 
387  SectionOneSize = Resources.getTreeSize();
388  uint32_t CurrentStringOffset = SectionOneSize;
389  uint32_t TotalStringTableSize = 0;
390  for (auto const &String : StringTable) {
391  StringTableOffsets.push_back(CurrentStringOffset);
392  uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
393  CurrentStringOffset += StringSize;
394  TotalStringTableSize += StringSize;
395  }
396  SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
397 
398  // account for the relocations of section one.
399  SectionOneRelocations = FileSize + SectionOneSize;
400  FileSize += SectionOneSize;
401  FileSize +=
402  Data.size() * COFF::RelocationSize; // one relocation for each resource.
403  FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
404 }
405 
406 void WindowsResourceCOFFWriter::performSectionTwoLayout() {
407  // add size of .rsrc$2 section, which contains all resource data on 8-byte
408  // alignment.
409  SectionTwoOffset = FileSize;
410  SectionTwoSize = 0;
411  for (auto const &Entry : Data) {
412  DataOffsets.push_back(SectionTwoSize);
413  SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
414  }
415  FileSize += SectionTwoSize;
416  FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
417 }
418 
419 static std::time_t getTime() {
420  std::time_t Now = time(nullptr);
421  if (Now < 0 || !isUInt<32>(Now))
422  return UINT32_MAX;
423  return Now;
424 }
425 
426 std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() {
427  BufferStart = OutputBuffer->getBufferStart();
428 
429  writeCOFFHeader();
430  writeFirstSectionHeader();
431  writeSecondSectionHeader();
432  writeFirstSection();
433  writeSecondSection();
434  writeSymbolTable();
435  writeStringTable();
436 
437  return std::move(OutputBuffer);
438 }
439 
440 void WindowsResourceCOFFWriter::writeCOFFHeader() {
441  // Write the COFF header.
442  auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
443  Header->Machine = MachineType;
444  Header->NumberOfSections = 2;
445  Header->TimeDateStamp = getTime();
446  Header->PointerToSymbolTable = SymbolTableOffset;
447  // One symbol for every resource plus 2 for each section and @feat.00
448  Header->NumberOfSymbols = Data.size() + 5;
449  Header->SizeOfOptionalHeader = 0;
450  Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
451 }
452 
453 void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
454  // Write the first section header.
455  CurrentOffset += sizeof(coff_file_header);
456  auto *SectionOneHeader =
457  reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
458  strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize);
459  SectionOneHeader->VirtualSize = 0;
460  SectionOneHeader->VirtualAddress = 0;
461  SectionOneHeader->SizeOfRawData = SectionOneSize;
462  SectionOneHeader->PointerToRawData = SectionOneOffset;
463  SectionOneHeader->PointerToRelocations = SectionOneRelocations;
464  SectionOneHeader->PointerToLinenumbers = 0;
465  SectionOneHeader->NumberOfRelocations = Data.size();
466  SectionOneHeader->NumberOfLinenumbers = 0;
467  SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
468  SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
469 }
470 
471 void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
472  // Write the second section header.
473  CurrentOffset += sizeof(coff_section);
474  auto *SectionTwoHeader =
475  reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
476  strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize);
477  SectionTwoHeader->VirtualSize = 0;
478  SectionTwoHeader->VirtualAddress = 0;
479  SectionTwoHeader->SizeOfRawData = SectionTwoSize;
480  SectionTwoHeader->PointerToRawData = SectionTwoOffset;
481  SectionTwoHeader->PointerToRelocations = 0;
482  SectionTwoHeader->PointerToLinenumbers = 0;
483  SectionTwoHeader->NumberOfRelocations = 0;
484  SectionTwoHeader->NumberOfLinenumbers = 0;
485  SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
486  SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
487 }
488 
489 void WindowsResourceCOFFWriter::writeFirstSection() {
490  // Write section one.
491  CurrentOffset += sizeof(coff_section);
492 
493  writeDirectoryTree();
494  writeDirectoryStringTable();
495  writeFirstSectionRelocations();
496 
497  CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
498 }
499 
500 void WindowsResourceCOFFWriter::writeSecondSection() {
501  // Now write the .rsrc$02 section.
502  for (auto const &RawDataEntry : Data) {
503  llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
504  CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
505  }
506 
507  CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
508 }
509 
510 void WindowsResourceCOFFWriter::writeSymbolTable() {
511  // Now write the symbol table.
512  // First, the feat symbol.
513  auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
514  strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize);
515  Symbol->Value = 0x11;
516  Symbol->SectionNumber = 0xffff;
518  Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
519  Symbol->NumberOfAuxSymbols = 0;
520  CurrentOffset += sizeof(coff_symbol16);
521 
522  // Now write the .rsrc1 symbol + aux.
523  Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
524  strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize);
525  Symbol->Value = 0;
526  Symbol->SectionNumber = 1;
528  Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
529  Symbol->NumberOfAuxSymbols = 1;
530  CurrentOffset += sizeof(coff_symbol16);
531  auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
532  CurrentOffset);
533  Aux->Length = SectionOneSize;
534  Aux->NumberOfRelocations = Data.size();
535  Aux->NumberOfLinenumbers = 0;
536  Aux->CheckSum = 0;
537  Aux->NumberLowPart = 0;
538  Aux->Selection = 0;
539  CurrentOffset += sizeof(coff_aux_section_definition);
540 
541  // Now write the .rsrc2 symbol + aux.
542  Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
543  strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize);
544  Symbol->Value = 0;
545  Symbol->SectionNumber = 2;
547  Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
548  Symbol->NumberOfAuxSymbols = 1;
549  CurrentOffset += sizeof(coff_symbol16);
550  Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
551  CurrentOffset);
552  Aux->Length = SectionTwoSize;
553  Aux->NumberOfRelocations = 0;
554  Aux->NumberOfLinenumbers = 0;
555  Aux->CheckSum = 0;
556  Aux->NumberLowPart = 0;
557  Aux->Selection = 0;
558  CurrentOffset += sizeof(coff_aux_section_definition);
559 
560  // Now write a symbol for each relocation.
561  for (unsigned i = 0; i < Data.size(); i++) {
562  auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
563  Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
564  memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize);
565  Symbol->Value = DataOffsets[i];
566  Symbol->SectionNumber = 2;
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.setNameOffset(
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  llvm::copy(String, 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) {
694  Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
695  break;
697  Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
698  break;
700  Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
701  break;
703  Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
704  break;
705  default:
706  llvm_unreachable("unknown machine type");
707  }
708  CurrentOffset += sizeof(coff_relocation);
709  }
710 }
711 
714  const WindowsResourceParser &Parser) {
715  Error E = Error::success();
716  WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
717  if (E)
718  return std::move(E);
719  return Writer.write();
720 }
721 
722 } // namespace object
723 } // namespace llvm
coff_symbol< support::ulittle16_t > coff_symbol16
Definition: COFF.h:265
constexpr bool isUInt< 32 >(uint64_t x)
Definition: MathExtras.h:348
const size_t WIN_RES_NULL_ENTRY_SIZE
support::ulittle16_t Machine
Definition: COFF.h:76
An implementation of BinaryStream which holds its entire data set in a single contiguous buffer...
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream&#39;s offset.
iterator begin() const
Definition: ArrayRef.h:136
Error parse(WindowsResource *WR)
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
Error readWideString(ArrayRef< UTF16 > &Dest)
Similar to readCString, however read a null-terminated UTF16 string instead.
support::ulittle32_t HeaderSize
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
Definition: MathExtras.h:684
unsigned short UTF16
Definition: ConvertUTF.h:110
No complex type; simple scalar variable.
Definition: COFF.h:259
constexpr bool IsBigEndianHost
Definition: Host.h:46
MachineTypes
Definition: COFF.h:93
Machine is based on a 32bit word architecture.
Definition: COFF.h:145
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:450
const uint32_t SECTION_ALIGNMENT
void write16le(void *P, uint16_t V)
Definition: Endian.h:417
const Children< uint32_t > & getIDChildren() const
The access may reference the value stored in memory.
TypeID
Definitions of all of the base types for the Type system.
Definition: Type.h:54
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED
Definition: ConvertUTF.h:124
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
static Expected< std::unique_ptr< WindowsResource > > createWindowsResource(MemoryBufferRef Source)
Expected< ResourceEntryRef > getHeadEntry()
const uint32_t MIN_HEADER_SIZE
size_t getBufferSize() const
Definition: MemoryBuffer.h:278
WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, Error &E)
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:148
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Definition: COFF.h:740
ArrayRef< uint8_t > getData() const
ArrayRef< UTF16 > getTypeString() const
static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, ArrayRef< UTF16 > &Str, bool &IsString)
static std::time_t getTime()
static void write(bool isBE, void *P, T V)
void printTree(raw_ostream &OS) const
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:981
support::ulittle32_t VirtualAddress
Definition: COFF.h:472
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void setOffset(uint32_t Off)
const ArrayRef< std::vector< UTF16 > > getStringTable() const
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
const uint32_t WIN_RES_HEADER_ALIGNMENT
const ArrayRef< std::vector< uint8_t > > getData() const
BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.
std::unique_ptr< MemoryBuffer > write()
Bit scan reverse.
MemoryBufferRef Data
Definition: Binary.h:37
bool convertUTF16ToUTF8String(ArrayRef< char > SrcBytes, std::string &Out)
Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
const size_t WIN_RES_MAGIC_SIZE
Definition: COFF.h:717
Expected< std::unique_ptr< MemoryBuffer > > writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, const WindowsResourceParser &Parser)
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef< MemberData > Members, StringRef StringTable)
COFFYAML::WeakExternalCharacteristics Characteristics
Definition: COFFYAML.cpp:325
static void writeStringTable(std::vector< uint8_t > &B, ArrayRef< const std::string > Strings)
uint32_t getLength() override
Return the number of bytes of data in this stream.
ArrayRef< UTF16 > getNameString() const
uint32_t Size
Definition: Profile.cpp:46
const std::string to_string(const T &Value)
Definition: ScopedPrinter.h:61
const uint32_t WIN_RES_DATA_ALIGNMENT
#define RETURN_IF_ERROR(X)
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
void print(ScopedPrinter &Writer, StringRef Name) const
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
support::ulittle32_t Characteristics
Definition: COFF.h:748
const TreeNode & getTree() const
OutputIt copy(R &&Range, OutputIt Out)
Definition: STLExtras.h:1237
const Children< std::string > & getStringChildren() const