llvm.org GIT mirror llvm / 3028aaf
Implement COFF emission for parsed Windows Resource ( .res) files. Summary: Add the WindowsResourceCOFFWriter class for producing the final COFF after all parsing is done. Reviewers: hiraditya!, zturner, ruiu Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34020 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305092 91177308-0d34-0410-b5e6-96231b3b80d8 Eric Beckmann 2 years ago
10 changed file(s) with 903 addition(s) and 108 deletion(s). Raw diff Collapse all Expand all
645645 } Offset;
646646 };
647647
648 struct coff_resource_data_entry {
649 support::ulittle32_t DataRVA;
650 support::ulittle32_t DataSize;
651 support::ulittle32_t Codepage;
652 support::ulittle32_t Reserved;
653 };
654
648655 struct coff_resource_dir_table {
649656 support::ulittle32_t Characteristics;
650657 support::ulittle32_t TimeDateStamp;
4343 #include
4444
4545 namespace llvm {
46
47 class FileOutputBuffer;
48
4649 namespace object {
4750
4851 class WindowsResource;
52
53 enum class Machine { UNKNOWN, ARM, X64, X86 };
4954
5055 class ResourceEntryRef {
5156 public:
5762 ArrayRef getNameString() const { return Name; }
5863 uint16_t getNameID() const { return NameID; }
5964 uint16_t getLanguage() const { return Suffix->Language; }
65 uint16_t getMajorVersion() const { return Suffix->Version >> 16; }
66 uint16_t getMinorVersion() const { return Suffix->Version; }
67 uint32_t getCharacteristics() const { return Suffix->Characteristics; }
68 ArrayRef getData() const { return Data; }
6069
6170 private:
6271 friend class WindowsResource;
105114
106115 class WindowsResourceParser {
107116 public:
117 class TreeNode;
108118 WindowsResourceParser();
119 Error parse(WindowsResource *WR);
120 void printTree() const;
121 const TreeNode &getTree() const { return Root; }
122 const ArrayRef> getData() const { return Data; }
123 const ArrayRef> getStringTable() const {
124 return StringTable;
125 }
109126
110 Error parse(WindowsResource *WR);
111
112 void printTree() const;
113
114 private:
115127 class TreeNode {
116128 public:
117 TreeNode() = default;
118 explicit TreeNode(ArrayRef Ref);
119 void addEntry(const ResourceEntryRef &Entry);
129 template
130 using Children = std::map>;
131
120132 void print(ScopedPrinter &Writer, StringRef Name) const;
133 uint32_t getTreeSize() const;
134 uint32_t getStringIndex() const { return StringIndex; }
135 uint32_t getDataIndex() const { return DataIndex; }
136 uint16_t getMajorVersion() const { return MajorVersion; }
137 uint16_t getMinorVersion() const { return MinorVersion; }
138 uint32_t getCharacteristics() const { return Characteristics; }
139 bool checkIsDataNode() const { return IsDataNode; }
140 const Children &getIDChildren() const { return IDChildren; }
141 const Children &getStringChildren() const {
142 return StringChildren;
143 }
121144
122145 private:
146 friend class WindowsResourceParser;
147
148 static uint32_t StringCount;
149 static uint32_t DataCount;
150
151 static std::unique_ptr createStringNode();
152 static std::unique_ptr createIDNode();
153 static std::unique_ptr createDataNode(uint16_t MajorVersion,
154 uint16_t MinorVersion,
155 uint32_t Characteristics);
156
157 explicit TreeNode(bool IsStringNode);
158 TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
159 uint32_t Characteristics);
160
161 void addEntry(const ResourceEntryRef &Entry);
123162 TreeNode &addTypeNode(const ResourceEntryRef &Entry);
124163 TreeNode &addNameNode(const ResourceEntryRef &Entry);
125164 TreeNode &addLanguageNode(const ResourceEntryRef &Entry);
126 TreeNode &addChild(uint32_t ID);
165 TreeNode &addChild(uint32_t ID, bool IsDataNode = false,
166 uint16_t MajorVersion = 0, uint16_t MinorVersion = 0,
167 uint32_t Characteristics = 0);
127168 TreeNode &addChild(ArrayRef NameRef);
128 std::vector Name;
129 std::map> IDChildren;
130 std::map> StringChildren;
169 bool IsDataNode = false;
170 uint32_t StringIndex;
171 uint32_t DataIndex;
172 Children IDChildren;
173 Children StringChildren;
174 uint16_t MajorVersion = 0;
175 uint16_t MinorVersion = 0;
176 uint32_t Characteristics = 0;
131177 };
132178
179 private:
133180 TreeNode Root;
181 std::vector> Data;
182 std::vector> StringTable;
134183 };
184
185 Error writeWindowsResourceCOFF(StringRef OutputFile, Machine MachineType,
186 const WindowsResourceParser &Parser);
135187
136188 } // namespace object
137189 } // namespace llvm
1212
1313 #include "llvm/Object/WindowsResource.h"
1414 #include "llvm/BinaryFormat/COFF.h"
15 #include "llvm/Object/COFF.h"
16 #include "llvm/Support/FileOutputBuffer.h"
17 #include "llvm/Support/MathExtras.h"
18 #include
19 #include
1520 #include
1621 #include
1722
2732 static const size_t ResourceMagicSize = 16;
2833
2934 static const size_t NullEntrySize = 16;
35
36 uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
37 uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
3038
3139 WindowsResource::WindowsResource(MemoryBufferRef Source)
3240 : Binary(Binary::ID_WinRes, Source) {
114122 return Error::success();
115123 }
116124
117 WindowsResourceParser::WindowsResourceParser() {}
125 WindowsResourceParser::WindowsResourceParser() : Root(false) {}
118126
119127 Error WindowsResourceParser::parse(WindowsResource *WR) {
120128 auto EntryOrErr = WR->getHeadEntry();
123131
124132 ResourceEntryRef Entry = EntryOrErr.get();
125133 bool End = false;
126
127134 while (!End) {
135
136 Data.push_back(Entry.getData());
137
138 if (Entry.checkTypeString())
139 StringTable.push_back(Entry.getTypeString());
140
141 if (Entry.checkNameString())
142 StringTable.push_back(Entry.getNameString());
128143
129144 Root.addEntry(Entry);
130145
145160 NameNode.addLanguageNode(Entry);
146161 }
147162
148 WindowsResourceParser::TreeNode::TreeNode(ArrayRef NameRef)
149 : Name(NameRef) {}
163 WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
164 if (IsStringNode)
165 StringIndex = StringCount++;
166 }
167
168 WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
169 uint16_t MinorVersion,
170 uint32_t Characteristics)
171 : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
172 Characteristics(Characteristics) {
173 if (IsDataNode)
174 DataIndex = DataCount++;
175 }
176
177 std::unique_ptr
178 WindowsResourceParser::TreeNode::createStringNode() {
179 return std::unique_ptr(new TreeNode(true));
180 }
181
182 std::unique_ptr
183 WindowsResourceParser::TreeNode::createIDNode() {
184 return std::unique_ptr(new TreeNode(false));
185 }
186
187 std::unique_ptr
188 WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
189 uint16_t MinorVersion,
190 uint32_t Characteristics) {
191 return std::unique_ptr(
192 new TreeNode(MajorVersion, MinorVersion, Characteristics));
193 }
150194
151195 WindowsResourceParser::TreeNode &
152196 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) {
167211 WindowsResourceParser::TreeNode &
168212 WindowsResourceParser::TreeNode::addLanguageNode(
169213 const ResourceEntryRef &Entry) {
170 return addChild(Entry.getLanguage());
171 }
172
173 WindowsResourceParser::TreeNode &
174 WindowsResourceParser::TreeNode::addChild(uint32_t ID) {
214 return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
215 Entry.getMinorVersion(), Entry.getCharacteristics());
216 }
217
218 WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(
219 uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
220 uint32_t Characteristics) {
175221 auto Child = IDChildren.find(ID);
176222 if (Child == IDChildren.end()) {
177 auto NewChild = llvm::make_unique(ID);
223 auto NewChild =
224 IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
225 : createIDNode();
178226 WindowsResourceParser::TreeNode &Node = *NewChild;
179227 IDChildren.emplace(ID, std::move(NewChild));
180228 return Node;
198246
199247 auto Child = StringChildren.find(NameString);
200248 if (Child == StringChildren.end()) {
201 auto NewChild = llvm::make_unique(NameRef);
249 auto NewChild = createStringNode();
202250 WindowsResourceParser::TreeNode &Node = *NewChild;
203251 StringChildren.emplace(NameString, std::move(NewChild));
204252 return Node;
217265 }
218266 }
219267
268 // This function returns the size of the entire resource tree, including
269 // directory tables, directory entries, and data entries. It does not include
270 // the directory strings or the relocations of the .rsrc section.
271 uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
272 uint32_t Size = (IDChildren.size() + StringChildren.size()) *
273 sizeof(llvm::object::coff_resource_dir_entry);
274
275 // Reached a node pointing to a data entry.
276 if (IsDataNode) {
277 Size += sizeof(llvm::object::coff_resource_data_entry);
278 return Size;
279 }
280
281 // If the node does not point to data, it must have a directory table pointing
282 // to other nodes.
283 Size += sizeof(llvm::object::coff_resource_dir_table);
284
285 for (auto const &Child : StringChildren) {
286 Size += Child.second->getTreeSize();
287 }
288 for (auto const &Child : IDChildren) {
289 Size += Child.second->getTreeSize();
290 }
291 return Size;
292 }
293
294 class WindowsResourceCOFFWriter {
295 public:
296 WindowsResourceCOFFWriter(StringRef OutputFile, Machine MachineType,
297 const WindowsResourceParser &Parser, Error &E);
298
299 Error write();
300
301 private:
302 void performFileLayout();
303 void performSectionOneLayout();
304 void performSectionTwoLayout();
305 void writeCOFFHeader();
306 void writeFirstSectionHeader();
307 void writeSecondSectionHeader();
308 void writeFirstSection();
309 void writeSecondSection();
310 void writeSymbolTable();
311 void writeStringTable();
312 void writeDirectoryTree();
313 void writeDirectoryStringTable();
314 void writeFirstSectionRelocations();
315 std::unique_ptr Buffer;
316 uint8_t *Current;
317 Machine MachineType;
318 const WindowsResourceParser::TreeNode &Resources;
319 const ArrayRef> Data;
320 uint64_t FileSize;
321 uint32_t SymbolTableOffset;
322 uint32_t SectionOneSize;
323 uint32_t SectionOneOffset;
324 uint32_t SectionOneRelocations;
325 uint32_t SectionTwoSize;
326 uint32_t SectionTwoOffset;
327 const ArrayRef> StringTable;
328 std::vector StringTableOffsets;
329 std::vector DataOffsets;
330 std::vector RelocationAddresses;
331 };
332
333 WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
334 StringRef OutputFile, Machine MachineType,
335 const WindowsResourceParser &Parser, Error &E)
336 : MachineType(MachineType), Resources(Parser.getTree()),
337 Data(Parser.getData()), StringTable(Parser.getStringTable()) {
338 performFileLayout();
339
340 ErrorOr> BufferOrErr =
341 FileOutputBuffer::create(OutputFile, FileSize);
342 if (!BufferOrErr) {
343 E = errorCodeToError(BufferOrErr.getError());
344 return;
345 }
346
347 Buffer = std::move(*BufferOrErr);
348 }
349
350 void WindowsResourceCOFFWriter::performFileLayout() {
351 // Add size of COFF header.
352 FileSize = llvm::COFF::Header16Size;
353
354 // one .rsrc section header for directory tree, another for resource data.
355 FileSize += 2 * llvm::COFF::SectionSize;
356
357 performSectionOneLayout();
358 performSectionTwoLayout();
359
360 // We have reached the address of the symbol table.
361 SymbolTableOffset = FileSize;
362
363 FileSize += llvm::COFF::Symbol16Size; // size of the @feat.00 symbol.
364 FileSize += 4 * llvm::COFF::Symbol16Size; // symbol + aux for each section.
365 FileSize += Data.size() * llvm::COFF::Symbol16Size; // 1 symbol per resource.
366 FileSize += 4; // four null bytes for the string table.
367 }
368
369 void WindowsResourceCOFFWriter::performSectionOneLayout() {
370 SectionOneOffset = FileSize;
371
372 SectionOneSize = Resources.getTreeSize();
373 uint32_t CurrentStringOffset = SectionOneSize;
374 uint32_t TotalStringTableSize = 0;
375 for (auto const &String : StringTable) {
376 StringTableOffsets.push_back(CurrentStringOffset);
377 uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
378 CurrentStringOffset += StringSize;
379 TotalStringTableSize += StringSize;
380 }
381 SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
382
383 // account for the relocations of section one.
384 SectionOneRelocations = FileSize + SectionOneSize;
385 FileSize += SectionOneSize;
386 FileSize += Data.size() *
387 llvm::COFF::RelocationSize; // one relocation for each resource.
388 }
389
390 void WindowsResourceCOFFWriter::performSectionTwoLayout() {
391 // add size of .rsrc$2 section, which contains all resource data on 8-byte
392 // alignment.
393 SectionTwoOffset = FileSize;
394 SectionTwoSize = 0;
395 for (auto const &Entry : Data) {
396 DataOffsets.push_back(SectionTwoSize);
397 SectionTwoSize += llvm::alignTo(Entry.size(), sizeof(uint64_t));
398 }
399 FileSize += SectionTwoSize;
400 }
401
402 static std::time_t getTime() {
403 std::time_t Now = time(nullptr);
404 if (Now < 0 || !isUInt<32>(Now))
405 return UINT32_MAX;
406 return Now;
407 }
408
409 Error WindowsResourceCOFFWriter::write() {
410 Current = Buffer->getBufferStart();
411
412 writeCOFFHeader();
413 writeFirstSectionHeader();
414 writeSecondSectionHeader();
415 writeFirstSection();
416 writeSecondSection();
417 writeSymbolTable();
418 writeStringTable();
419
420 if (auto EC = Buffer->commit()) {
421 return errorCodeToError(EC);
422 }
423
424 return Error::success();
425 }
426
427 void WindowsResourceCOFFWriter::writeCOFFHeader() {
428 // Write the COFF header.
429 auto *Header = reinterpret_cast(Current);
430 switch (MachineType) {
431 case Machine::ARM:
432 Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
433 break;
434 case Machine::X64:
435 Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
436 break;
437 case Machine::X86:
438 Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_I386;
439 break;
440 default:
441 Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
442 }
443 Header->NumberOfSections = 2;
444 Header->TimeDateStamp = getTime();
445 Header->PointerToSymbolTable = SymbolTableOffset;
446 // One symbol for every resource plus 2 for each section and @feat.00
447 Header->NumberOfSymbols = Data.size() + 5;
448 Header->SizeOfOptionalHeader = 0;
449 Header->Characteristics = llvm::COFF::IMAGE_FILE_32BIT_MACHINE;
450 }
451
452 void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
453 // Write the first section header.
454 Current += sizeof(llvm::object::coff_file_header);
455 auto *SectionOneHeader =
456 reinterpret_cast(Current);
457 strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)llvm::COFF::NameSize);
458 SectionOneHeader->VirtualSize = 0;
459 SectionOneHeader->VirtualAddress = 0;
460 SectionOneHeader->SizeOfRawData = SectionOneSize;
461 SectionOneHeader->PointerToRawData = SectionOneOffset;
462 SectionOneHeader->PointerToRelocations = SectionOneRelocations;
463 SectionOneHeader->PointerToLinenumbers = 0;
464 SectionOneHeader->NumberOfRelocations = Data.size();
465 SectionOneHeader->NumberOfLinenumbers = 0;
466 SectionOneHeader->Characteristics = llvm::COFF::IMAGE_SCN_ALIGN_1BYTES;
467 SectionOneHeader->Characteristics +=
468 llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
469 SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE;
470 SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ;
471 }
472
473 void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
474 // Write the second section header.
475 Current += sizeof(llvm::object::coff_section);
476 auto *SectionTwoHeader =
477 reinterpret_cast(Current);
478 strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)llvm::COFF::NameSize);
479 SectionTwoHeader->VirtualSize = 0;
480 SectionTwoHeader->VirtualAddress = 0;
481 SectionTwoHeader->SizeOfRawData = SectionTwoSize;
482 SectionTwoHeader->PointerToRawData = SectionTwoOffset;
483 SectionTwoHeader->PointerToRelocations = 0;
484 SectionTwoHeader->PointerToLinenumbers = 0;
485 SectionTwoHeader->NumberOfRelocations = 0;
486 SectionTwoHeader->NumberOfLinenumbers = 0;
487 SectionTwoHeader->Characteristics =
488 llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
489 SectionTwoHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ;
490 }
491
492 void WindowsResourceCOFFWriter::writeFirstSection() {
493 // Write section one.
494 Current += sizeof(llvm::object::coff_section);
495
496 writeDirectoryTree();
497 writeDirectoryStringTable();
498 writeFirstSectionRelocations();
499 }
500
501 void WindowsResourceCOFFWriter::writeSecondSection() {
502 // Now write the .rsrc$02 section.
503 for (auto const &RawDataEntry : Data) {
504 std::copy(RawDataEntry.begin(), RawDataEntry.end(), Current);
505 Current += alignTo(RawDataEntry.size(), sizeof(uint64_t));
506 }
507 }
508
509 void WindowsResourceCOFFWriter::writeSymbolTable() {
510 // Now write the symbol table.
511 // First, the feat symbol.
512 auto *Symbol = reinterpret_cast(Current);
513 strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)llvm::COFF::NameSize);
514 Symbol->Value = 0x11;
515 Symbol->SectionNumber = 0xffff;
516 Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
517 Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
518 Symbol->NumberOfAuxSymbols = 0;
519 Current += sizeof(llvm::object::coff_symbol16);
520
521 // Now write the .rsrc1 symbol + aux.
522 Symbol = reinterpret_cast(Current);
523 strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)llvm::COFF::NameSize);
524 Symbol->Value = 0;
525 Symbol->SectionNumber = 1;
526 Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
527 Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
528 Symbol->NumberOfAuxSymbols = 1;
529 Current += sizeof(llvm::object::coff_symbol16);
530 auto *Aux =
531 reinterpret_cast(Current);
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 Current += sizeof(llvm::object::coff_aux_section_definition);
539
540 // Now write the .rsrc2 symbol + aux.
541 Symbol = reinterpret_cast(Current);
542 strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)llvm::COFF::NameSize);
543 Symbol->Value = 0;
544 Symbol->SectionNumber = 2;
545 Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
546 Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
547 Symbol->NumberOfAuxSymbols = 1;
548 Current += sizeof(llvm::object::coff_symbol16);
549 Aux = reinterpret_cast(Current);
550 Aux->Length = SectionTwoSize;
551 Aux->NumberOfRelocations = 0;
552 Aux->NumberOfLinenumbers = 0;
553 Aux->CheckSum = 0;
554 Aux->NumberLowPart = 0;
555 Aux->Selection = 0;
556 Current += sizeof(llvm::object::coff_aux_section_definition);
557
558 // Now write a symbol for each relocation.
559 for (unsigned i = 0; i < Data.size(); i++) {
560 char RelocationName[9];
561 sprintf(RelocationName, "$R%06X", DataOffsets[i]);
562 Symbol = reinterpret_cast(Current);
563 strncpy(Symbol->Name.ShortName, RelocationName,
564 (size_t)llvm::COFF::NameSize);
565 Symbol->Value = DataOffsets[i];
566 Symbol->SectionNumber = 1;
567 Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
568 Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
569 Symbol->NumberOfAuxSymbols = 0;
570 Current += sizeof(llvm::object::coff_symbol16);
571 }
572 }
573
574 void WindowsResourceCOFFWriter::writeStringTable() {
575 // Just 4 null bytes for the string table.
576 auto COFFStringTable = reinterpret_cast(Current);
577 *COFFStringTable = 0;
578 }
579
580 void WindowsResourceCOFFWriter::writeDirectoryTree() {
581 // Traverse parsed resource tree breadth-first and write the corresponding
582 // COFF objects.
583 std::queue Queue;
584 Queue.push(&Resources);
585 uint32_t NextLevelOffset = sizeof(llvm::object::coff_resource_dir_table) +
586 (Resources.getStringChildren().size() +
587 Resources.getIDChildren().size()) *
588 sizeof(llvm::object::coff_resource_dir_entry);
589 std::vector DataEntriesTreeOrder;
590 uint32_t CurrentRelativeOffset = 0;
591
592 while (!Queue.empty()) {
593 auto CurrentNode = Queue.front();
594 Queue.pop();
595 auto *Table =
596 reinterpret_cast(Current);
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 Current += sizeof(llvm::object::coff_resource_dir_table);
606 CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_table);
607
608 // Write the directory entries immediately following each directory table.
609 for (auto const &Child : StringChildren) {
610 auto *Entry =
611 reinterpret_cast(Current);
612 Entry->Identifier.NameOffset =
613 StringTableOffsets[Child.second->getStringIndex()];
614 if (Child.second->checkIsDataNode()) {
615 Entry->Offset.DataEntryOffset = NextLevelOffset;
616 NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry);
617 DataEntriesTreeOrder.push_back(Child.second.get());
618 } else {
619 Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
620 NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) +
621 (Child.second->getStringChildren().size() +
622 Child.second->getIDChildren().size()) *
623 sizeof(llvm::object::coff_resource_dir_entry);
624 Queue.push(Child.second.get());
625 }
626 Current += sizeof(llvm::object::coff_resource_dir_entry);
627 CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry);
628 }
629 for (auto const &Child : IDChildren) {
630 auto *Entry =
631 reinterpret_cast(Current);
632 Entry->Identifier.ID = Child.first;
633 if (Child.second->checkIsDataNode()) {
634 Entry->Offset.DataEntryOffset = NextLevelOffset;
635 NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry);
636 DataEntriesTreeOrder.push_back(Child.second.get());
637 } else {
638 Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
639 NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) +
640 (Child.second->getStringChildren().size() +
641 Child.second->getIDChildren().size()) *
642 sizeof(llvm::object::coff_resource_dir_entry);
643 Queue.push(Child.second.get());
644 }
645 Current += sizeof(llvm::object::coff_resource_dir_entry);
646 CurrentRelativeOffset += sizeof(llvm::object::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 =
654 reinterpret_cast(Current);
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 Current += sizeof(llvm::object::coff_resource_data_entry);
661 CurrentRelativeOffset += sizeof(llvm::object::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 auto *LengthField = reinterpret_cast(Current);
670 uint16_t Length = String.size();
671 *LengthField = Length;
672 Current += sizeof(uint16_t);
673 auto *Start = reinterpret_cast(Current);
674 std::copy(String.begin(), String.end(), Start);
675 Current += Length * sizeof(UTF16);
676 TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
677 }
678 Current +=
679 alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
680 }
681
682 void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
683
684 // Now write the relocations for .rsrc$01
685 // Five symbols already in table before we start, @feat.00 and 2 for each
686 // .rsrc section.
687 uint32_t NextSymbolIndex = 5;
688 for (unsigned i = 0; i < Data.size(); i++) {
689 auto *Reloc = reinterpret_cast(Current);
690 Reloc->VirtualAddress = RelocationAddresses[i];
691 Reloc->SymbolTableIndex = NextSymbolIndex++;
692 switch (MachineType) {
693 case Machine::ARM:
694 Reloc->Type = llvm::COFF::IMAGE_REL_ARM_ADDR32NB;
695 break;
696 case Machine::X64:
697 Reloc->Type = llvm::COFF::IMAGE_REL_AMD64_ADDR32NB;
698 break;
699 case Machine::X86:
700 Reloc->Type = llvm::COFF::IMAGE_REL_I386_DIR32NB;
701 break;
702 default:
703 Reloc->Type = 0;
704 }
705 Current += sizeof(llvm::object::coff_relocation);
706 }
707 }
708
709 Error writeWindowsResourceCOFF(StringRef OutputFile, Machine MachineType,
710 const WindowsResourceParser &Parser) {
711 Error E = Error::success();
712 WindowsResourceCOFFWriter Writer(OutputFile, MachineType, Parser, E);
713 if (E)
714 return E;
715 return Writer.write();
716 }
717
220718 } // namespace object
221719 } // namespace llvm
0 // Check COFF emission of cvtres
1 // The input was generated with the following command, using the original Windows
2 // rc.exe:
3 // > rc /fo test_resource.res /nologo test_resource.rc
4 // The object file we are comparing against was generated with this command using
5 // the original cvtres.
6 // > cvtres /machine:X86 /readonly /nologo /out:test_resource.o test_resource.res
7
8 RUN: llvm-cvtres /out:%t %p/Inputs/test_resource.res
9 RUN: llvm-readobj -coff-resources -section-data %t | FileCheck %s
10
11 CHECK: Resources [
12 CHECK-NEXT: String Name Entries: 1
13 CHECK-NEXT: ID Entries: 4
14 CHECK-NEXT: Type: STRINGARRAY [
15 CHECK-NEXT: String Name Entries: 1
16 CHECK-NEXT: ID Entries: 0
17 CHECK-NEXT: Name: MYRESOURCE [
18 CHECK-NEXT: String Name Entries: 0
19 CHECK-NEXT: ID Entries: 1
20 CHECK-NEXT: Language: (ID 1033) [
21 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
22 CHECK-NEXT: Major Version: 0
23 CHECK-NEXT: Minor Version: 0
24 CHECK-NEXT: ]
25 CHECK-NEXT: ]
26 CHECK-NEXT: ]
27 CHECK-NEXT: Type: kRT_BITMAP (ID 2) [
28 CHECK-NEXT: String Name Entries: 2
29 CHECK-NEXT: ID Entries: 0
30 CHECK-NEXT: Name: CURSOR [
31 CHECK-NEXT: String Name Entries: 0
32 CHECK-NEXT: ID Entries: 1
33 CHECK-NEXT: Language: (ID 1033) [
34 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
35 CHECK-NEXT: Major Version: 0
36 CHECK-NEXT: Minor Version: 0
37 CHECK-NEXT: ]
38 CHECK-NEXT: ]
39 CHECK-NEXT: Name: OKAY [
40 CHECK-NEXT: String Name Entries: 0
41 CHECK-NEXT: ID Entries: 1
42 CHECK-NEXT: Language: (ID 1033) [
43 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
44 CHECK-NEXT: Major Version: 0
45 CHECK-NEXT: Minor Version: 0
46 CHECK-NEXT: ]
47 CHECK-NEXT: ]
48 CHECK-NEXT: ]
49 CHECK-NEXT: Type: kRT_MENU (ID 4) [
50 CHECK-NEXT: String Name Entries: 1
51 CHECK-NEXT: ID Entries: 1
52 CHECK-NEXT: Name: "EAT" [
53 CHECK-NEXT: String Name Entries: 0
54 CHECK-NEXT: ID Entries: 1
55 CHECK-NEXT: Language: (ID 3081) [
56 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
57 CHECK-NEXT: Major Version: 0
58 CHECK-NEXT: Minor Version: 0
59 CHECK-NEXT: ]
60 CHECK-NEXT: ]
61 CHECK-NEXT: Name: (ID 14432) [
62 CHECK-NEXT: String Name Entries: 0
63 CHECK-NEXT: ID Entries: 1
64 CHECK-NEXT: Language: (ID 2052) [
65 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
66 CHECK-NEXT: Major Version: 0
67 CHECK-NEXT: Minor Version: 0
68 CHECK-NEXT: ]
69 CHECK-NEXT: ]
70 CHECK-NEXT: ]
71 CHECK-NEXT: Type: kRT_DIALOG (ID 5) [
72 CHECK-NEXT: String Name Entries: 1
73 CHECK-NEXT: ID Entries: 0
74 CHECK-NEXT: Name: TESTDIALOG [
75 CHECK-NEXT: String Name Entries: 0
76 CHECK-NEXT: ID Entries: 1
77 CHECK-NEXT: Language: (ID 1033) [
78 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
79 CHECK-NEXT: Major Version: 0
80 CHECK-NEXT: Minor Version: 0
81 CHECK-NEXT: ]
82 CHECK-NEXT: ]
83 CHECK-NEXT: ]
84 CHECK-NEXT: Type: kRT_ACCELERATOR (ID 9) [
85 CHECK-NEXT: String Name Entries: 1
86 CHECK-NEXT: ID Entries: 1
87 CHECK-NEXT: Name: MYACCELERATORS [
88 CHECK-NEXT: String Name Entries: 0
89 CHECK-NEXT: ID Entries: 1
90 CHECK-NEXT: Language: (ID 1033) [
91 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
92 CHECK-NEXT: Major Version: 0
93 CHECK-NEXT: Minor Version: 0
94 CHECK-NEXT: ]
95 CHECK-NEXT: ]
96 CHECK-NEXT: Name: (ID 12) [
97 CHECK-NEXT: String Name Entries: 0
98 CHECK-NEXT: ID Entries: 1
99 CHECK-NEXT: Language: (ID 1033) [
100 CHECK-NEXT: Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
101 CHECK-NEXT: Major Version: 0
102 CHECK-NEXT: Minor Version: 0
103 CHECK-NEXT: ]
104 CHECK-NEXT: ]
105 CHECK-NEXT: ]
106 CHECK-DAG: .rsrc$02 Data (
107 CHECK-NEXT: 0000: 11000300 E7030000 0D004400 4C040000 |..........D.L...|
108 CHECK-NEXT: 0010: 82001200 BC010000 28000000 10000000 |........(.......|
109 CHECK-NEXT: 0020: 10000000 01001800 00000000 00030000 |................|
110 CHECK-NEXT: 0030: C40E0000 C40E0000 00000000 00000000 |................|
111 CHECK-NEXT: 0040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
112 CHECK-NEXT: 0050: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
113 CHECK-NEXT: 0060: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
114 CHECK-NEXT: 0070: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
115 CHECK-NEXT: 0080: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
116 CHECK-NEXT: 0090: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
117 CHECK-NEXT: 00A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
118 CHECK-NEXT: 00B0: FFFFFFFF FF7F7F7F 7C7C7C78 78787575 |........|||xxxuu|
119 CHECK-NEXT: 00C0: 75FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |u...............|
120 CHECK-NEXT: 00D0: FFFFFFFF FFFFFFFF FFFFFFFF 979797FF |................|
121 CHECK-NEXT: 00E0: FFFFFFFF FF838383 AAAAAADB DBDB7979 |..............yy|
122 CHECK-NEXT: 00F0: 79757575 FFFFFFFF FFFFFFFF FFFFFFFF |yuuu............|
123 CHECK-NEXT: 0100: FFFFFFFF FFFFFFFF FFFFFFFF 9C9C9C98 |................|
124 CHECK-NEXT: 0110: 9898FFFF FF888888 DBDBDBB7 B7B77D7D |..............}}|
125 CHECK-NEXT: 0120: 7DFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |}...............|
126 CHECK-NEXT: 0130: FFFFFFFF FFFFFFFF FFFFFFFF A0A0A09C |................|
127 CHECK-NEXT: 0140: 9C9C9393 93ADADAD F2F2F284 84848181 |................|
128 CHECK-NEXT: 0150: 81FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
129 CHECK-NEXT: 0160: FFFFFFFF FFFFFFFF FFFFFFFF A4A4A4D7 |................|
130 CHECK-NEXT: 0170: D7D79D9D 9DD0D0D0 EEEEEE91 91918D8D |................|
131 CHECK-NEXT: 0180: 8DFFFFFF FFFFFF81 81817E7E 7EFFFFFF |..........~~~...|
132 CHECK-NEXT: 0190: FFFFFFFF FFFFFFFF FFFFFFFF A9A9A9F2 |................|
133 CHECK-NEXT: 01A0: F2F2E5E5 E5E2E2E2 95959591 91918D8D |................|
134 CHECK-NEXT: 01B0: 8D898989 868686FF FFFFFFFF FFFFFFFF |................|
135 CHECK-NEXT: 01C0: FFFFFFFF FFFFFFFF FFFFFFFF ADADADF2 |................|
136 CHECK-NEXT: 01D0: F2F2E1E1 E1DFDFDF E7E7E7E4 E4E4BBBB |................|
137 CHECK-NEXT: 01E0: BB8E8E8E FFFFFFFF FFFFFFFF FFFFFFFF |................|
138 CHECK-NEXT: 01F0: FFFFFFFF FFFFFFFF FFFFFFFF B5B5B5F2 |................|
139 CHECK-NEXT: 0200: F2F2E8E8 E8E7E7E7 EAEAEAC6 C6C69E9E |................|
140 CHECK-NEXT: 0210: 9EFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
141 CHECK-NEXT: 0220: FFFFFFFF FFFFFFFF FFFFFFFF B9B9B9F4 |................|
142 CHECK-NEXT: 0230: F4F4ECEC ECEDEDED CBCBCBA7 A7A7FFFF |................|
143 CHECK-NEXT: 0240: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
144 CHECK-NEXT: 0250: FFFFFFFF FFFFFFFF FFFFFFFF BDBDBDF7 |................|
145 CHECK-NEXT: 0260: F7F7EFEF EFD0D0D0 AFAFAFFF FFFFFFFF |................|
146 CHECK-NEXT: 0270: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
147 CHECK-NEXT: 0280: FFFFFFFF FFFFFFFF FFFFFFFF C1C1C1F7 |................|
148 CHECK-NEXT: 0290: F7F7D5D5 D5B6B6B6 FFFFFFFF FFFFFFFF |................|
149 CHECK-NEXT: 02A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
150 CHECK-NEXT: 02B0: FFFFFFFF FFFFFFFF FFFFFFFF C4C4C4D9 |................|
151 CHECK-NEXT: 02C0: D9D9BEBE BEFFFFFF FFFFFFFF FFFFFFFF |................|
152 CHECK-NEXT: 02D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
153 CHECK-NEXT: 02E0: FFFFFFFF FFFFFFFF FFFFFFFF C8C8C8C5 |................|
154 CHECK-NEXT: 02F0: C5C5FFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
155 CHECK-NEXT: 0300: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
156 CHECK-NEXT: 0310: FFFFFFFF FFFFFFFF FFFFFFFF CBCBCBFF |................|
157 CHECK-NEXT: 0320: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
158 CHECK-NEXT: 0330: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
159 CHECK-NEXT: 0340: 28000000 10000000 10000000 01001800 |(...............|
160 CHECK-NEXT: 0350: 00000000 00030000 C40E0000 C40E0000 |................|
161 CHECK-NEXT: 0360: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
162 CHECK-NEXT: 0370: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
163 CHECK-NEXT: 0380: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
164 CHECK-NEXT: 0390: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
165 CHECK-NEXT: 03A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
166 CHECK-NEXT: 03B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
167 CHECK-NEXT: 03C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
168 CHECK-NEXT: 03D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
169 CHECK-NEXT: 03E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
170 CHECK-NEXT: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
171 CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
172 CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
173 CHECK-NEXT: 0420: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
174 CHECK-NEXT: 0430: FFFFFFFF A0E3A901 B31801B3 1801B318 |................|
175 CHECK-NEXT: 0440: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....|
176 CHECK-NEXT: 0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
177 CHECK-NEXT: 0460: FFFFFFFF 01B31800 D7331CDB 49DBF9E2 |.........3..I...|
178 CHECK-NEXT: 0470: 9BEFAF00 D73300D7 3301B318 FFFFFFFF |.....3..3.......|
179 CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
180 CHECK-NEXT: 0490: FFFFFFFF 01B31800 DE55F6FE F9DBFAE7 |.........U......|
181 CHECK-NEXT: 04A0: FEFFFE86 EFAE00DE 5501B318 FFFFFFFF |........U.......|
182 CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
183 CHECK-NEXT: 04C0: FFFFFFFF 01B31800 E676DBFB EC00E676 |.........v.....v|
184 CHECK-NEXT: 04D0: 57EFA5FB FFFD55EE A401B318 FFFFFFFF |W.....U.........|
185 CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
186 CHECK-NEXT: 04F0: FFFFFFFF 01B31800 ED9800ED 9800ED98 |................|
187 CHECK-NEXT: 0500: 00ED9887 F7CFFEFF FF01B318 FFFFFFFF |................|
188 CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
189 CHECK-NEXT: 0520: FFFFFFFF 01B31800 F4BA00F4 BA00F4BA |................|
190 CHECK-NEXT: 0530: 00F4BA00 F4BA9CFB E401B318 FFFFFFFF |................|
191 CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
192 CHECK-NEXT: 0550: FFFFFFFF 01B31800 FBDB00FB DB00FBDB |................|
193 CHECK-NEXT: 0560: 00FBDB00 FBDB00FB DB01B318 FFFFFFFF |................|
194 CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
195 CHECK-NEXT: 0580: FFFFFFFF 9FE2A801 B31801B3 1801B318 |................|
196 CHECK-NEXT: 0590: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....|
197 CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
198 CHECK-NEXT: 05B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
199 CHECK-NEXT: 05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
200 CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
201 CHECK-NEXT: 05E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
202 CHECK-NEXT: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
203 CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
204 CHECK-NEXT: 0610: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
205 CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
206 CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
207 CHECK-NEXT: 0640: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
208 CHECK-NEXT: 0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
209 CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF 00000000 00006400 |..............d.|
210 CHECK-NEXT: 0670: 79007500 00000000 65007300 68006100 |y.u.....e.s.h.a.|
211 CHECK-NEXT: 0680: 6C006100 00008000 66006B00 61006F00 |l.a.....f.k.a.o.|
212 CHECK-NEXT: 0690: 79006100 00000000 0000C080 00000000 |y.a.............|
213 CHECK-NEXT: 06A0: 02000A00 0A00C800 2C010000 00005400 |........,.....T.|
214 CHECK-NEXT: 06B0: 65007300 74000000 01000250 00000000 |e.s.t......P....|
215 CHECK-NEXT: 06C0: 0A000A00 E6000E00 0100FFFF 82004300 |..............C.|
216 CHECK-NEXT: 06D0: 6F006E00 74006900 6E007500 65003A00 |o.n.t.i.n.u.e.:.|
217 CHECK-NEXT: 06E0: 00000000 00000150 00000000 42008600 |.......P....B...|
218 CHECK-NEXT: 06F0: A1000D00 0200FFFF 80002600 4F004B00 |..........&.O.K.|
219 CHECK-NEXT: 0700: 00000000 00000000 11005800 A4000000 |..........X.....|
220 CHECK-NEXT: 0710: 0D004800 2E160000 82001200 BC010000 |..H.............|
221 CHECK-NEXT: 0720: 00000000 00006400 66006900 73006800 |......d.f.i.s.h.|
222 CHECK-NEXT: 0730: 00000000 65007300 61006C00 61006400 |....e.s.a.l.a.d.|
223 CHECK-NEXT: 0740: 00008000 66006400 75006300 6B000000 |....f.d.u.c.k...|
224 CHECK-NEXT: 0750: 74686973 20697320 61207573 65722064 |this is a user d|
225 CHECK-NEXT: 0760: 6566696E 65642072 65736F75 72636500 |efined resource.|
226 CHECK-NEXT: 0770: 69742063 6F6E7461 696E7320 6D616E79 |it contains many|
227 CHECK-NEXT: 0780: 20737472 696E6773 00000000 00000000 | strings........|
228 CHECK-NEXT: )
0 // The input was generated with the following command, using the original Windows
1 // rc.exe:
2 // > rc /fo test_resource.res /nologo test_resource.rc
3
4 RUN: llvm-cvtres /verbose %p/Inputs/test_resource.res | FileCheck %s
5
6 CHECK: Number of resources: 8
7 CHECK-NEXT: Resource Tree [
8 CHECK-NEXT: STRINGARRAY [
9 CHECK-NEXT: MYRESOURCE [
10 CHECK-NEXT: 1033 [
11 CHECK-NEXT: ]
12 CHECK-NEXT: ]
13 CHECK-NEXT: ]
14 CHECK-NEXT: 2 [
15 CHECK-NEXT: CURSOR [
16 CHECK-NEXT: 1033 [
17 CHECK-NEXT: ]
18 CHECK-NEXT: ]
19 CHECK-NEXT: OKAY [
20 CHECK-NEXT: 1033 [
21 CHECK-NEXT: ]
22 CHECK-NEXT: ]
23 CHECK-NEXT: ]
24 CHECK-NEXT: 4 [
25 CHECK-NEXT: "EAT" [
26 CHECK-NEXT: 3081 [
27 CHECK-NEXT: ]
28 CHECK-NEXT: ]
29 CHECK-NEXT: 14432 [
30 CHECK-NEXT: 2052 [
31 CHECK-NEXT: ]
32 CHECK-NEXT: ]
33 CHECK-NEXT: ]
34 CHECK-NEXT: 5 [
35 CHECK-NEXT: TESTDIALOG [
36 CHECK-NEXT: 1033 [
37 CHECK-NEXT: ]
38 CHECK-NEXT: ]
39 CHECK-NEXT: ]
40 CHECK-NEXT: 9 [
41 CHECK-NEXT: MYACCELERATORS [
42 CHECK-NEXT: 1033 [
43 CHECK-NEXT: ]
44 CHECK-NEXT: ]
45 CHECK-NEXT: 12 [
46 CHECK-NEXT: 1033 [
47 CHECK-NEXT: ]
48 CHECK-NEXT: ]
49 CHECK-NEXT: ]
50 CHECK-NEXT: ]
+0
-51
test/tools/llvm-cvtres/resource.test less more
None // The input was generated with the following command, using the original Windows
1 // rc.exe:
2 // > rc /fo test_resource.res /nologo test_resource.rc
3
4 RUN: llvm-cvtres %p/Inputs/test_resource.res | FileCheck %s
5
6 CHECK: Number of resources: 8
7 CHECK-NEXT: Resource Tree [
8 CHECK-NEXT: STRINGARRAY [
9 CHECK-NEXT: MYRESOURCE [
10 CHECK-NEXT: 1033 [
11 CHECK-NEXT: ]
12 CHECK-NEXT: ]
13 CHECK-NEXT: ]
14 CHECK-NEXT: 2 [
15 CHECK-NEXT: CURSOR [
16 CHECK-NEXT: 1033 [
17 CHECK-NEXT: ]
18 CHECK-NEXT: ]
19 CHECK-NEXT: OKAY [
20 CHECK-NEXT: 1033 [
21 CHECK-NEXT: ]
22 CHECK-NEXT: ]
23 CHECK-NEXT: ]
24 CHECK-NEXT: 4 [
25 CHECK-NEXT: "EAT" [
26 CHECK-NEXT: 3081 [
27 CHECK-NEXT: ]
28 CHECK-NEXT: ]
29 CHECK-NEXT: 14432 [
30 CHECK-NEXT: 2052 [
31 CHECK-NEXT: ]
32 CHECK-NEXT: ]
33 CHECK-NEXT: ]
34 CHECK-NEXT: 5 [
35 CHECK-NEXT: TESTDIALOG [
36 CHECK-NEXT: 1033 [
37 CHECK-NEXT: ]
38 CHECK-NEXT: ]
39 CHECK-NEXT: ]
40 CHECK-NEXT: 9 [
41 CHECK-NEXT: MYACCELERATORS [
42 CHECK-NEXT: 1033 [
43 CHECK-NEXT: ]
44 CHECK-NEXT: ]
45 CHECK-NEXT: 12 [
46 CHECK-NEXT: 1033 [
47 CHECK-NEXT: ]
48 CHECK-NEXT: ]
49 CHECK-NEXT: ]
50 CHECK-NEXT: ]
1818 type = Tool
1919 name = llvm-cvtres
2020 parent = Tools
21 required_libraries = Option Support
21 required_libraries = Object Option Support
111111 return 0;
112112 }
113113
114 machine Machine;
114 bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
115
116 Machine MachineType;
115117
116118 if (InputArgs.hasArg(OPT_MACHINE)) {
117119 std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper();
118 Machine = StringSwitch(MachineString)
119 .Case("ARM", machine::ARM)
120 .Case("X64", machine::X64)
121 .Case("X86", machine::X86)
122 .Default(machine::UNKNOWN);
123 if (Machine == machine::UNKNOWN)
120 MachineType = StringSwitch(MachineString)
121 .Case("ARM", Machine::ARM)
122 .Case("X64", Machine::X64)
123 .Case("X86", Machine::X86)
124 .Default(Machine::UNKNOWN);
125 if (MachineType == Machine::UNKNOWN)
124126 reportError("Unsupported machine architecture");
125127 } else {
126 outs() << "Machine architecture not specified; assumed X64.\n";
127 Machine = machine::X64;
128 if (Verbose)
129 outs() << "Machine architecture not specified; assumed X64.\n";
130 MachineType = Machine::X64;
128131 }
129132
130133 std::vector InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
138141 if (InputArgs.hasArg(OPT_OUT)) {
139142 OutputFile = InputArgs.getLastArgValue(OPT_OUT);
140143 } else {
141 OutputFile = StringRef(InputFiles[0]);
144 OutputFile = llvm::sys::path::filename(StringRef(InputFiles[0]));
142145 llvm::sys::path::replace_extension(OutputFile, ".obj");
143146 }
144147
145 outs() << "Machine: ";
146 switch (Machine) {
147 case machine::ARM:
148 outs() << "ARM\n";
149 break;
150 case machine::X86:
151 outs() << "X86\n";
152 break;
153 default:
154 outs() << "X64\n";
148 if (Verbose) {
149 outs() << "Machine: ";
150 switch (MachineType) {
151 case Machine::ARM:
152 outs() << "ARM\n";
153 break;
154 case Machine::X86:
155 outs() << "X86\n";
156 break;
157 default:
158 outs() << "X64\n";
159 }
155160 }
156161
157162 WindowsResourceParser Parser;
168173 if (!RF)
169174 reportError(File + ": unrecognized file format.\n");
170175
171 int EntryNumber = 0;
172 Expected EntryOrErr = RF->getHeadEntry();
173 if (!EntryOrErr)
174 error(EntryOrErr.takeError());
175 ResourceEntryRef Entry = EntryOrErr.get();
176 bool End = false;
177 while (!End) {
178 error(Entry.moveNext(End));
179 EntryNumber++;
176 if (Verbose) {
177 int EntryNumber = 0;
178 Expected EntryOrErr = RF->getHeadEntry();
179 if (!EntryOrErr)
180 error(EntryOrErr.takeError());
181 ResourceEntryRef Entry = EntryOrErr.get();
182 bool End = false;
183 while (!End) {
184 error(Entry.moveNext(End));
185 EntryNumber++;
186 }
187 outs() << "Number of resources: " << EntryNumber << "\n";
180188 }
181 outs() << "Number of resources: " << EntryNumber << "\n";
182189
183190 error(Parser.parse(RF));
184191 }
185192
186 Parser.printTree();
193 if (Verbose)
194 Parser.printTree();
195
196 error(
197 llvm::object::writeWindowsResourceCOFF(OutputFile, MachineType, Parser));
187198
188199 return 0;
189200 }
1313
1414 void error(std::error_code EC);
1515
16 enum class machine { UNKNOWN = 0, ARM, X64, X86 };
17
1816 #endif