[llvm] r305092 - Implement COFF emission for parsed Windows Resource ( .res) files.

Eric Beckmann via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 9 10:34:31 PDT 2017


Author: ecbeckmann
Date: Fri Jun  9 12:34:30 2017
New Revision: 305092

URL: http://llvm.org/viewvc/llvm-project?rev=305092&view=rev
Log:
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

Added:
    llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.obj.coff   (with props)
    llvm/trunk/test/tools/llvm-cvtres/object.test
    llvm/trunk/test/tools/llvm-cvtres/parse.test
Removed:
    llvm/trunk/test/tools/llvm-cvtres/resource.test
Modified:
    llvm/trunk/include/llvm/Object/COFF.h
    llvm/trunk/include/llvm/Object/WindowsResource.h
    llvm/trunk/lib/Object/WindowsResource.cpp
    llvm/trunk/tools/llvm-cvtres/LLVMBuild.txt
    llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp
    llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h

Modified: llvm/trunk/include/llvm/Object/COFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/COFF.h?rev=305092&r1=305091&r2=305092&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/COFF.h (original)
+++ llvm/trunk/include/llvm/Object/COFF.h Fri Jun  9 12:34:30 2017
@@ -646,6 +646,13 @@ struct coff_resource_dir_entry {
   } Offset;
 };
 
+struct coff_resource_data_entry {
+  support::ulittle32_t DataRVA;
+  support::ulittle32_t DataSize;
+  support::ulittle32_t Codepage;
+  support::ulittle32_t Reserved;
+};
+
 struct coff_resource_dir_table {
   support::ulittle32_t Characteristics;
   support::ulittle32_t TimeDateStamp;

Modified: llvm/trunk/include/llvm/Object/WindowsResource.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/WindowsResource.h?rev=305092&r1=305091&r2=305092&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/WindowsResource.h (original)
+++ llvm/trunk/include/llvm/Object/WindowsResource.h Fri Jun  9 12:34:30 2017
@@ -44,10 +44,15 @@
 #include <map>
 
 namespace llvm {
+
+class FileOutputBuffer;
+
 namespace object {
 
 class WindowsResource;
 
+enum class Machine { UNKNOWN, ARM, X64, X86 };
+
 class ResourceEntryRef {
 public:
   Error moveNext(bool &End);
@@ -58,6 +63,10 @@ public:
   ArrayRef<UTF16> getNameString() const { return Name; }
   uint16_t getNameID() const { return NameID; }
   uint16_t getLanguage() const { return Suffix->Language; }
+  uint16_t getMajorVersion() const { return Suffix->Version >> 16; }
+  uint16_t getMinorVersion() const { return Suffix->Version; }
+  uint32_t getCharacteristics() const { return Suffix->Characteristics; }
+  ArrayRef<uint8_t> getData() const { return Data; }
 
 private:
   friend class WindowsResource;
@@ -106,34 +115,77 @@ private:
 
 class WindowsResourceParser {
 public:
+  class TreeNode;
   WindowsResourceParser();
-
   Error parse(WindowsResource *WR);
-
   void printTree() const;
+  const TreeNode &getTree() const { return Root; }
+  const ArrayRef<std::vector<uint8_t>> getData() const { return Data; }
+  const ArrayRef<std::vector<UTF16>> getStringTable() const {
+    return StringTable;
+  }
 
-private:
   class TreeNode {
   public:
-    TreeNode() = default;
-    explicit TreeNode(ArrayRef<UTF16> Ref);
-    void addEntry(const ResourceEntryRef &Entry);
+    template <typename T>
+    using Children = std::map<T, std::unique_ptr<TreeNode>>;
+
     void print(ScopedPrinter &Writer, StringRef Name) const;
+    uint32_t getTreeSize() const;
+    uint32_t getStringIndex() const { return StringIndex; }
+    uint32_t getDataIndex() const { return DataIndex; }
+    uint16_t getMajorVersion() const { return MajorVersion; }
+    uint16_t getMinorVersion() const { return MinorVersion; }
+    uint32_t getCharacteristics() const { return Characteristics; }
+    bool checkIsDataNode() const { return IsDataNode; }
+    const Children<uint32_t> &getIDChildren() const { return IDChildren; }
+    const Children<std::string> &getStringChildren() const {
+      return StringChildren;
+    }
 
   private:
+    friend class WindowsResourceParser;
+
+    static uint32_t StringCount;
+    static uint32_t DataCount;
+
+    static std::unique_ptr<TreeNode> createStringNode();
+    static std::unique_ptr<TreeNode> createIDNode();
+    static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion,
+                                                    uint16_t MinorVersion,
+                                                    uint32_t Characteristics);
+
+    explicit TreeNode(bool IsStringNode);
+    TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
+             uint32_t Characteristics);
+
+    void addEntry(const ResourceEntryRef &Entry);
     TreeNode &addTypeNode(const ResourceEntryRef &Entry);
     TreeNode &addNameNode(const ResourceEntryRef &Entry);
     TreeNode &addLanguageNode(const ResourceEntryRef &Entry);
-    TreeNode &addChild(uint32_t ID);
+    TreeNode &addChild(uint32_t ID, bool IsDataNode = false,
+                       uint16_t MajorVersion = 0, uint16_t MinorVersion = 0,
+                       uint32_t Characteristics = 0);
     TreeNode &addChild(ArrayRef<UTF16> NameRef);
-    std::vector<UTF16> Name;
-    std::map<uint32_t, std::unique_ptr<TreeNode>> IDChildren;
-    std::map<std::string, std::unique_ptr<TreeNode>> StringChildren;
+    bool IsDataNode = false;
+    uint32_t StringIndex;
+    uint32_t DataIndex;
+    Children<uint32_t> IDChildren;
+    Children<std::string> StringChildren;
+    uint16_t MajorVersion = 0;
+    uint16_t MinorVersion = 0;
+    uint32_t Characteristics = 0;
   };
 
+private:
   TreeNode Root;
+  std::vector<std::vector<uint8_t>> Data;
+  std::vector<std::vector<UTF16>> StringTable;
 };
 
+Error writeWindowsResourceCOFF(StringRef OutputFile, Machine MachineType,
+                               const WindowsResourceParser &Parser);
+
 } // namespace object
 } // namespace llvm
 

Modified: llvm/trunk/lib/Object/WindowsResource.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/WindowsResource.cpp?rev=305092&r1=305091&r2=305092&view=diff
==============================================================================
--- llvm/trunk/lib/Object/WindowsResource.cpp (original)
+++ llvm/trunk/lib/Object/WindowsResource.cpp Fri Jun  9 12:34:30 2017
@@ -13,6 +13,11 @@
 
 #include "llvm/Object/WindowsResource.h"
 #include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MathExtras.h"
+#include <ctime>
+#include <queue>
 #include <sstream>
 #include <system_error>
 
@@ -29,6 +34,9 @@ static const size_t ResourceMagicSize =
 
 static const size_t NullEntrySize = 16;
 
+uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
+uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
+
 WindowsResource::WindowsResource(MemoryBufferRef Source)
     : Binary(Binary::ID_WinRes, Source) {
   size_t LeadingSize = ResourceMagicSize + NullEntrySize;
@@ -115,7 +123,7 @@ Error ResourceEntryRef::loadNext() {
   return Error::success();
 }
 
-WindowsResourceParser::WindowsResourceParser() {}
+WindowsResourceParser::WindowsResourceParser() : Root(false) {}
 
 Error WindowsResourceParser::parse(WindowsResource *WR) {
   auto EntryOrErr = WR->getHeadEntry();
@@ -124,9 +132,16 @@ Error WindowsResourceParser::parse(Windo
 
   ResourceEntryRef Entry = EntryOrErr.get();
   bool End = false;
-
   while (!End) {
 
+    Data.push_back(Entry.getData());
+
+    if (Entry.checkTypeString())
+      StringTable.push_back(Entry.getTypeString());
+
+    if (Entry.checkNameString())
+      StringTable.push_back(Entry.getNameString());
+
     Root.addEntry(Entry);
 
     RETURN_IF_ERROR(Entry.moveNext(End));
@@ -146,8 +161,37 @@ void WindowsResourceParser::TreeNode::ad
   NameNode.addLanguageNode(Entry);
 }
 
-WindowsResourceParser::TreeNode::TreeNode(ArrayRef<UTF16> NameRef)
-    : Name(NameRef) {}
+WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
+  if (IsStringNode)
+    StringIndex = StringCount++;
+}
+
+WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
+                                          uint16_t MinorVersion,
+                                          uint32_t Characteristics)
+    : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
+      Characteristics(Characteristics) {
+  if (IsDataNode)
+    DataIndex = DataCount++;
+}
+
+std::unique_ptr<WindowsResourceParser::TreeNode>
+WindowsResourceParser::TreeNode::createStringNode() {
+  return std::unique_ptr<TreeNode>(new TreeNode(true));
+}
+
+std::unique_ptr<WindowsResourceParser::TreeNode>
+WindowsResourceParser::TreeNode::createIDNode() {
+  return std::unique_ptr<TreeNode>(new TreeNode(false));
+}
+
+std::unique_ptr<WindowsResourceParser::TreeNode>
+WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
+                                                uint16_t MinorVersion,
+                                                uint32_t Characteristics) {
+  return std::unique_ptr<TreeNode>(
+      new TreeNode(MajorVersion, MinorVersion, Characteristics));
+}
 
 WindowsResourceParser::TreeNode &
 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) {
@@ -168,14 +212,18 @@ WindowsResourceParser::TreeNode::addName
 WindowsResourceParser::TreeNode &
 WindowsResourceParser::TreeNode::addLanguageNode(
     const ResourceEntryRef &Entry) {
-  return addChild(Entry.getLanguage());
+  return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
+                  Entry.getMinorVersion(), Entry.getCharacteristics());
 }
 
-WindowsResourceParser::TreeNode &
-WindowsResourceParser::TreeNode::addChild(uint32_t ID) {
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(
+    uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
+    uint32_t Characteristics) {
   auto Child = IDChildren.find(ID);
   if (Child == IDChildren.end()) {
-    auto NewChild = llvm::make_unique<WindowsResourceParser::TreeNode>(ID);
+    auto NewChild =
+        IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
+                   : createIDNode();
     WindowsResourceParser::TreeNode &Node = *NewChild;
     IDChildren.emplace(ID, std::move(NewChild));
     return Node;
@@ -199,7 +247,7 @@ WindowsResourceParser::TreeNode::addChil
 
   auto Child = StringChildren.find(NameString);
   if (Child == StringChildren.end()) {
-    auto NewChild = llvm::make_unique<WindowsResourceParser::TreeNode>(NameRef);
+    auto NewChild = createStringNode();
     WindowsResourceParser::TreeNode &Node = *NewChild;
     StringChildren.emplace(NameString, std::move(NewChild));
     return Node;
@@ -218,5 +266,455 @@ void WindowsResourceParser::TreeNode::pr
   }
 }
 
+// This function returns the size of the entire resource tree, including
+// directory tables, directory entries, and data entries.  It does not include
+// the directory strings or the relocations of the .rsrc section.
+uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
+  uint32_t Size = (IDChildren.size() + StringChildren.size()) *
+                  sizeof(llvm::object::coff_resource_dir_entry);
+
+  // Reached a node pointing to a data entry.
+  if (IsDataNode) {
+    Size += sizeof(llvm::object::coff_resource_data_entry);
+    return Size;
+  }
+
+  // If the node does not point to data, it must have a directory table pointing
+  // to other nodes.
+  Size += sizeof(llvm::object::coff_resource_dir_table);
+
+  for (auto const &Child : StringChildren) {
+    Size += Child.second->getTreeSize();
+  }
+  for (auto const &Child : IDChildren) {
+    Size += Child.second->getTreeSize();
+  }
+  return Size;
+}
+
+class WindowsResourceCOFFWriter {
+public:
+  WindowsResourceCOFFWriter(StringRef OutputFile, Machine MachineType,
+                            const WindowsResourceParser &Parser, Error &E);
+
+  Error write();
+
+private:
+  void performFileLayout();
+  void performSectionOneLayout();
+  void performSectionTwoLayout();
+  void writeCOFFHeader();
+  void writeFirstSectionHeader();
+  void writeSecondSectionHeader();
+  void writeFirstSection();
+  void writeSecondSection();
+  void writeSymbolTable();
+  void writeStringTable();
+  void writeDirectoryTree();
+  void writeDirectoryStringTable();
+  void writeFirstSectionRelocations();
+  std::unique_ptr<FileOutputBuffer> Buffer;
+  uint8_t *Current;
+  Machine MachineType;
+  const WindowsResourceParser::TreeNode &Resources;
+  const ArrayRef<std::vector<uint8_t>> Data;
+  uint64_t FileSize;
+  uint32_t SymbolTableOffset;
+  uint32_t SectionOneSize;
+  uint32_t SectionOneOffset;
+  uint32_t SectionOneRelocations;
+  uint32_t SectionTwoSize;
+  uint32_t SectionTwoOffset;
+  const ArrayRef<std::vector<UTF16>> StringTable;
+  std::vector<uint32_t> StringTableOffsets;
+  std::vector<uint32_t> DataOffsets;
+  std::vector<uint32_t> RelocationAddresses;
+};
+
+WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
+    StringRef OutputFile, Machine MachineType,
+    const WindowsResourceParser &Parser, Error &E)
+    : MachineType(MachineType), Resources(Parser.getTree()),
+      Data(Parser.getData()), StringTable(Parser.getStringTable()) {
+  performFileLayout();
+
+  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+      FileOutputBuffer::create(OutputFile, FileSize);
+  if (!BufferOrErr) {
+    E = errorCodeToError(BufferOrErr.getError());
+    return;
+  }
+
+  Buffer = std::move(*BufferOrErr);
+}
+
+void WindowsResourceCOFFWriter::performFileLayout() {
+  // Add size of COFF header.
+  FileSize = llvm::COFF::Header16Size;
+
+  // one .rsrc section header for directory tree, another for resource data.
+  FileSize += 2 * llvm::COFF::SectionSize;
+
+  performSectionOneLayout();
+  performSectionTwoLayout();
+
+  // We have reached the address of the symbol table.
+  SymbolTableOffset = FileSize;
+
+  FileSize += llvm::COFF::Symbol16Size;     // size of the @feat.00 symbol.
+  FileSize += 4 * llvm::COFF::Symbol16Size; // symbol + aux for each section.
+  FileSize += Data.size() * llvm::COFF::Symbol16Size; // 1 symbol per resource.
+  FileSize += 4; // four null bytes for the string table.
+}
+
+void WindowsResourceCOFFWriter::performSectionOneLayout() {
+  SectionOneOffset = FileSize;
+
+  SectionOneSize = Resources.getTreeSize();
+  uint32_t CurrentStringOffset = SectionOneSize;
+  uint32_t TotalStringTableSize = 0;
+  for (auto const &String : StringTable) {
+    StringTableOffsets.push_back(CurrentStringOffset);
+    uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
+    CurrentStringOffset += StringSize;
+    TotalStringTableSize += StringSize;
+  }
+  SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
+
+  // account for the relocations of section one.
+  SectionOneRelocations = FileSize + SectionOneSize;
+  FileSize += SectionOneSize;
+  FileSize += Data.size() *
+              llvm::COFF::RelocationSize; // one relocation for each resource.
+}
+
+void WindowsResourceCOFFWriter::performSectionTwoLayout() {
+  // add size of .rsrc$2 section, which contains all resource data on 8-byte
+  // alignment.
+  SectionTwoOffset = FileSize;
+  SectionTwoSize = 0;
+  for (auto const &Entry : Data) {
+    DataOffsets.push_back(SectionTwoSize);
+    SectionTwoSize += llvm::alignTo(Entry.size(), sizeof(uint64_t));
+  }
+  FileSize += SectionTwoSize;
+}
+
+static std::time_t getTime() {
+  std::time_t Now = time(nullptr);
+  if (Now < 0 || !isUInt<32>(Now))
+    return UINT32_MAX;
+  return Now;
+}
+
+Error WindowsResourceCOFFWriter::write() {
+  Current = Buffer->getBufferStart();
+
+  writeCOFFHeader();
+  writeFirstSectionHeader();
+  writeSecondSectionHeader();
+  writeFirstSection();
+  writeSecondSection();
+  writeSymbolTable();
+  writeStringTable();
+
+  if (auto EC = Buffer->commit()) {
+    return errorCodeToError(EC);
+  }
+
+  return Error::success();
+}
+
+void WindowsResourceCOFFWriter::writeCOFFHeader() {
+  // Write the COFF header.
+  auto *Header = reinterpret_cast<llvm::object::coff_file_header *>(Current);
+  switch (MachineType) {
+  case Machine::ARM:
+    Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
+    break;
+  case Machine::X64:
+    Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+    break;
+  case Machine::X86:
+    Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+    break;
+  default:
+    Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+  }
+  Header->NumberOfSections = 2;
+  Header->TimeDateStamp = getTime();
+  Header->PointerToSymbolTable = SymbolTableOffset;
+  // One symbol for every resource plus 2 for each section and @feat.00
+  Header->NumberOfSymbols = Data.size() + 5;
+  Header->SizeOfOptionalHeader = 0;
+  Header->Characteristics = llvm::COFF::IMAGE_FILE_32BIT_MACHINE;
+}
+
+void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
+  // Write the first section header.
+  Current += sizeof(llvm::object::coff_file_header);
+  auto *SectionOneHeader =
+      reinterpret_cast<llvm::object::coff_section *>(Current);
+  strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)llvm::COFF::NameSize);
+  SectionOneHeader->VirtualSize = 0;
+  SectionOneHeader->VirtualAddress = 0;
+  SectionOneHeader->SizeOfRawData = SectionOneSize;
+  SectionOneHeader->PointerToRawData = SectionOneOffset;
+  SectionOneHeader->PointerToRelocations = SectionOneRelocations;
+  SectionOneHeader->PointerToLinenumbers = 0;
+  SectionOneHeader->NumberOfRelocations = Data.size();
+  SectionOneHeader->NumberOfLinenumbers = 0;
+  SectionOneHeader->Characteristics = llvm::COFF::IMAGE_SCN_ALIGN_1BYTES;
+  SectionOneHeader->Characteristics +=
+      llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
+  SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE;
+  SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ;
+}
+
+void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
+  // Write the second section header.
+  Current += sizeof(llvm::object::coff_section);
+  auto *SectionTwoHeader =
+      reinterpret_cast<llvm::object::coff_section *>(Current);
+  strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)llvm::COFF::NameSize);
+  SectionTwoHeader->VirtualSize = 0;
+  SectionTwoHeader->VirtualAddress = 0;
+  SectionTwoHeader->SizeOfRawData = SectionTwoSize;
+  SectionTwoHeader->PointerToRawData = SectionTwoOffset;
+  SectionTwoHeader->PointerToRelocations = 0;
+  SectionTwoHeader->PointerToLinenumbers = 0;
+  SectionTwoHeader->NumberOfRelocations = 0;
+  SectionTwoHeader->NumberOfLinenumbers = 0;
+  SectionTwoHeader->Characteristics =
+      llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
+  SectionTwoHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ;
+}
+
+void WindowsResourceCOFFWriter::writeFirstSection() {
+  // Write section one.
+  Current += sizeof(llvm::object::coff_section);
+
+  writeDirectoryTree();
+  writeDirectoryStringTable();
+  writeFirstSectionRelocations();
+}
+
+void WindowsResourceCOFFWriter::writeSecondSection() {
+  // Now write the .rsrc$02 section.
+  for (auto const &RawDataEntry : Data) {
+    std::copy(RawDataEntry.begin(), RawDataEntry.end(), Current);
+    Current += alignTo(RawDataEntry.size(), sizeof(uint64_t));
+  }
+}
+
+void WindowsResourceCOFFWriter::writeSymbolTable() {
+  // Now write the symbol table.
+  // First, the feat symbol.
+  auto *Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
+  strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)llvm::COFF::NameSize);
+  Symbol->Value = 0x11;
+  Symbol->SectionNumber = 0xffff;
+  Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
+  Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
+  Symbol->NumberOfAuxSymbols = 0;
+  Current += sizeof(llvm::object::coff_symbol16);
+
+  // Now write the .rsrc1 symbol + aux.
+  Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
+  strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)llvm::COFF::NameSize);
+  Symbol->Value = 0;
+  Symbol->SectionNumber = 1;
+  Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
+  Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
+  Symbol->NumberOfAuxSymbols = 1;
+  Current += sizeof(llvm::object::coff_symbol16);
+  auto *Aux =
+      reinterpret_cast<llvm::object::coff_aux_section_definition *>(Current);
+  Aux->Length = SectionOneSize;
+  Aux->NumberOfRelocations = Data.size();
+  Aux->NumberOfLinenumbers = 0;
+  Aux->CheckSum = 0;
+  Aux->NumberLowPart = 0;
+  Aux->Selection = 0;
+  Current += sizeof(llvm::object::coff_aux_section_definition);
+
+  // Now write the .rsrc2 symbol + aux.
+  Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
+  strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)llvm::COFF::NameSize);
+  Symbol->Value = 0;
+  Symbol->SectionNumber = 2;
+  Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
+  Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
+  Symbol->NumberOfAuxSymbols = 1;
+  Current += sizeof(llvm::object::coff_symbol16);
+  Aux = reinterpret_cast<llvm::object::coff_aux_section_definition *>(Current);
+  Aux->Length = SectionTwoSize;
+  Aux->NumberOfRelocations = 0;
+  Aux->NumberOfLinenumbers = 0;
+  Aux->CheckSum = 0;
+  Aux->NumberLowPart = 0;
+  Aux->Selection = 0;
+  Current += sizeof(llvm::object::coff_aux_section_definition);
+
+  // Now write a symbol for each relocation.
+  for (unsigned i = 0; i < Data.size(); i++) {
+    char RelocationName[9];
+    sprintf(RelocationName, "$R%06X", DataOffsets[i]);
+    Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
+    strncpy(Symbol->Name.ShortName, RelocationName,
+            (size_t)llvm::COFF::NameSize);
+    Symbol->Value = DataOffsets[i];
+    Symbol->SectionNumber = 1;
+    Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
+    Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
+    Symbol->NumberOfAuxSymbols = 0;
+    Current += sizeof(llvm::object::coff_symbol16);
+  }
+}
+
+void WindowsResourceCOFFWriter::writeStringTable() {
+  // Just 4 null bytes for the string table.
+  auto COFFStringTable = reinterpret_cast<uint32_t *>(Current);
+  *COFFStringTable = 0;
+}
+
+void WindowsResourceCOFFWriter::writeDirectoryTree() {
+  // Traverse parsed resource tree breadth-first and write the corresponding
+  // COFF objects.
+  std::queue<const WindowsResourceParser::TreeNode *> Queue;
+  Queue.push(&Resources);
+  uint32_t NextLevelOffset = sizeof(llvm::object::coff_resource_dir_table) +
+                             (Resources.getStringChildren().size() +
+                              Resources.getIDChildren().size()) *
+                                 sizeof(llvm::object::coff_resource_dir_entry);
+  std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
+  uint32_t CurrentRelativeOffset = 0;
+
+  while (!Queue.empty()) {
+    auto CurrentNode = Queue.front();
+    Queue.pop();
+    auto *Table =
+        reinterpret_cast<llvm::object::coff_resource_dir_table *>(Current);
+    Table->Characteristics = CurrentNode->getCharacteristics();
+    Table->TimeDateStamp = 0;
+    Table->MajorVersion = CurrentNode->getMajorVersion();
+    Table->MinorVersion = CurrentNode->getMinorVersion();
+    auto &IDChildren = CurrentNode->getIDChildren();
+    auto &StringChildren = CurrentNode->getStringChildren();
+    Table->NumberOfNameEntries = StringChildren.size();
+    Table->NumberOfIDEntries = IDChildren.size();
+    Current += sizeof(llvm::object::coff_resource_dir_table);
+    CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_table);
+
+    // Write the directory entries immediately following each directory table.
+    for (auto const &Child : StringChildren) {
+      auto *Entry =
+          reinterpret_cast<llvm::object::coff_resource_dir_entry *>(Current);
+      Entry->Identifier.NameOffset =
+          StringTableOffsets[Child.second->getStringIndex()];
+      if (Child.second->checkIsDataNode()) {
+        Entry->Offset.DataEntryOffset = NextLevelOffset;
+        NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry);
+        DataEntriesTreeOrder.push_back(Child.second.get());
+      } else {
+        Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
+        NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) +
+                           (Child.second->getStringChildren().size() +
+                            Child.second->getIDChildren().size()) *
+                               sizeof(llvm::object::coff_resource_dir_entry);
+        Queue.push(Child.second.get());
+      }
+      Current += sizeof(llvm::object::coff_resource_dir_entry);
+      CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry);
+    }
+    for (auto const &Child : IDChildren) {
+      auto *Entry =
+          reinterpret_cast<llvm::object::coff_resource_dir_entry *>(Current);
+      Entry->Identifier.ID = Child.first;
+      if (Child.second->checkIsDataNode()) {
+        Entry->Offset.DataEntryOffset = NextLevelOffset;
+        NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry);
+        DataEntriesTreeOrder.push_back(Child.second.get());
+      } else {
+        Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
+        NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) +
+                           (Child.second->getStringChildren().size() +
+                            Child.second->getIDChildren().size()) *
+                               sizeof(llvm::object::coff_resource_dir_entry);
+        Queue.push(Child.second.get());
+      }
+      Current += sizeof(llvm::object::coff_resource_dir_entry);
+      CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry);
+    }
+  }
+
+  RelocationAddresses.resize(Data.size());
+  // Now write all the resource data entries.
+  for (auto DataNodes : DataEntriesTreeOrder) {
+    auto *Entry =
+        reinterpret_cast<llvm::object::coff_resource_data_entry *>(Current);
+    RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
+    Entry->DataRVA = 0; // Set to zero because it is a relocation.
+    Entry->DataSize = Data[DataNodes->getDataIndex()].size();
+    Entry->Codepage = 0;
+    Entry->Reserved = 0;
+    Current += sizeof(llvm::object::coff_resource_data_entry);
+    CurrentRelativeOffset += sizeof(llvm::object::coff_resource_data_entry);
+  }
+}
+
+void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
+  // Now write the directory string table for .rsrc$01
+  uint32_t TotalStringTableSize = 0;
+  for (auto String : StringTable) {
+    auto *LengthField = reinterpret_cast<uint16_t *>(Current);
+    uint16_t Length = String.size();
+    *LengthField = Length;
+    Current += sizeof(uint16_t);
+    auto *Start = reinterpret_cast<UTF16 *>(Current);
+    std::copy(String.begin(), String.end(), Start);
+    Current += Length * sizeof(UTF16);
+    TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
+  }
+  Current +=
+      alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
+}
+
+void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
+
+  // Now write the relocations for .rsrc$01
+  // Five symbols already in table before we start, @feat.00 and 2 for each
+  // .rsrc section.
+  uint32_t NextSymbolIndex = 5;
+  for (unsigned i = 0; i < Data.size(); i++) {
+    auto *Reloc = reinterpret_cast<llvm::object::coff_relocation *>(Current);
+    Reloc->VirtualAddress = RelocationAddresses[i];
+    Reloc->SymbolTableIndex = NextSymbolIndex++;
+    switch (MachineType) {
+    case Machine::ARM:
+      Reloc->Type = llvm::COFF::IMAGE_REL_ARM_ADDR32NB;
+      break;
+    case Machine::X64:
+      Reloc->Type = llvm::COFF::IMAGE_REL_AMD64_ADDR32NB;
+      break;
+    case Machine::X86:
+      Reloc->Type = llvm::COFF::IMAGE_REL_I386_DIR32NB;
+      break;
+    default:
+      Reloc->Type = 0;
+    }
+    Current += sizeof(llvm::object::coff_relocation);
+  }
+}
+
+Error writeWindowsResourceCOFF(StringRef OutputFile, Machine MachineType,
+                               const WindowsResourceParser &Parser) {
+  Error E = Error::success();
+  WindowsResourceCOFFWriter Writer(OutputFile, MachineType, Parser, E);
+  if (E)
+    return E;
+  return Writer.write();
+}
+
 } // namespace object
 } // namespace llvm

Added: llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.obj.coff
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.obj.coff?rev=305092&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.obj.coff
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-cvtres/object.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/object.test?rev=305092&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cvtres/object.test (added)
+++ llvm/trunk/test/tools/llvm-cvtres/object.test Fri Jun  9 12:34:30 2017
@@ -0,0 +1,229 @@
+// Check COFF emission of cvtres
+// The input was generated with the following command, using the original Windows
+// rc.exe:
+// > rc /fo test_resource.res /nologo test_resource.rc
+// The object file we are comparing against was generated with this command using
+// the original cvtres.
+// > cvtres /machine:X86 /readonly /nologo /out:test_resource.o test_resource.res
+
+RUN: llvm-cvtres /out:%t %p/Inputs/test_resource.res
+RUN: llvm-readobj -coff-resources -section-data %t | FileCheck %s
+
+CHECK:      Resources [
+CHECK-NEXT:   String Name Entries: 1
+CHECK-NEXT:   ID Entries: 4
+CHECK-NEXT:   Type: STRINGARRAY [
+CHECK-NEXT:     String Name Entries: 1
+CHECK-NEXT:     ID Entries: 0
+CHECK-NEXT:     Name: MYRESOURCE [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 1033) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   Type: kRT_BITMAP (ID 2) [
+CHECK-NEXT:     String Name Entries: 2
+CHECK-NEXT:     ID Entries: 0
+CHECK-NEXT:     Name: CURSOR [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 1033) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:     Name: OKAY [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 1033) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   Type: kRT_MENU (ID 4) [
+CHECK-NEXT:     String Name Entries: 1
+CHECK-NEXT:     ID Entries: 1
+CHECK-NEXT:     Name: "EAT" [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 3081) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:     Name: (ID 14432) [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 2052) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   Type: kRT_DIALOG (ID 5) [
+CHECK-NEXT:     String Name Entries: 1
+CHECK-NEXT:     ID Entries: 0
+CHECK-NEXT:     Name: TESTDIALOG [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 1033) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   Type: kRT_ACCELERATOR (ID 9) [
+CHECK-NEXT:     String Name Entries: 1
+CHECK-NEXT:     ID Entries: 1
+CHECK-NEXT:     Name: MYACCELERATORS [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 1033) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:     Name: (ID 12) [
+CHECK-NEXT:       String Name Entries: 0
+CHECK-NEXT:       ID Entries: 1
+CHECK-NEXT:       Language: (ID 1033) [
+CHECK-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+CHECK-NEXT:         Major Version: 0
+CHECK-NEXT:         Minor Version: 0
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-DAG:   .rsrc$02 Data (
+CHECK-NEXT:    0000: 11000300 E7030000 0D004400 4C040000  |..........D.L...|
+CHECK-NEXT:    0010: 82001200 BC010000 28000000 10000000  |........(.......|
+CHECK-NEXT:    0020: 10000000 01001800 00000000 00030000  |................|
+CHECK-NEXT:    0030: C40E0000 C40E0000 00000000 00000000  |................|
+CHECK-NEXT:    0040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0050: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0060: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0070: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0080: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0090: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    00A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    00B0: FFFFFFFF FF7F7F7F 7C7C7C78 78787575  |........|||xxxuu|
+CHECK-NEXT:    00C0: 75FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |u...............|
+CHECK-NEXT:    00D0: FFFFFFFF FFFFFFFF FFFFFFFF 979797FF  |................|
+CHECK-NEXT:    00E0: FFFFFFFF FF838383 AAAAAADB DBDB7979  |..............yy|
+CHECK-NEXT:    00F0: 79757575 FFFFFFFF FFFFFFFF FFFFFFFF  |yuuu............|
+CHECK-NEXT:    0100: FFFFFFFF FFFFFFFF FFFFFFFF 9C9C9C98  |................|
+CHECK-NEXT:    0110: 9898FFFF FF888888 DBDBDBB7 B7B77D7D  |..............}}|
+CHECK-NEXT:    0120: 7DFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |}...............|
+CHECK-NEXT:    0130: FFFFFFFF FFFFFFFF FFFFFFFF A0A0A09C  |................|
+CHECK-NEXT:    0140: 9C9C9393 93ADADAD F2F2F284 84848181  |................|
+CHECK-NEXT:    0150: 81FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0160: FFFFFFFF FFFFFFFF FFFFFFFF A4A4A4D7  |................|
+CHECK-NEXT:    0170: D7D79D9D 9DD0D0D0 EEEEEE91 91918D8D  |................|
+CHECK-NEXT:    0180: 8DFFFFFF FFFFFF81 81817E7E 7EFFFFFF  |..........~~~...|
+CHECK-NEXT:    0190: FFFFFFFF FFFFFFFF FFFFFFFF A9A9A9F2  |................|
+CHECK-NEXT:    01A0: F2F2E5E5 E5E2E2E2 95959591 91918D8D  |................|
+CHECK-NEXT:    01B0: 8D898989 868686FF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    01C0: FFFFFFFF FFFFFFFF FFFFFFFF ADADADF2  |................|
+CHECK-NEXT:    01D0: F2F2E1E1 E1DFDFDF E7E7E7E4 E4E4BBBB  |................|
+CHECK-NEXT:    01E0: BB8E8E8E FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    01F0: FFFFFFFF FFFFFFFF FFFFFFFF B5B5B5F2  |................|
+CHECK-NEXT:    0200: F2F2E8E8 E8E7E7E7 EAEAEAC6 C6C69E9E  |................|
+CHECK-NEXT:    0210: 9EFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0220: FFFFFFFF FFFFFFFF FFFFFFFF B9B9B9F4  |................|
+CHECK-NEXT:    0230: F4F4ECEC ECEDEDED CBCBCBA7 A7A7FFFF  |................|
+CHECK-NEXT:    0240: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0250: FFFFFFFF FFFFFFFF FFFFFFFF BDBDBDF7  |................|
+CHECK-NEXT:    0260: F7F7EFEF EFD0D0D0 AFAFAFFF FFFFFFFF  |................|
+CHECK-NEXT:    0270: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0280: FFFFFFFF FFFFFFFF FFFFFFFF C1C1C1F7  |................|
+CHECK-NEXT:    0290: F7F7D5D5 D5B6B6B6 FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    02A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    02B0: FFFFFFFF FFFFFFFF FFFFFFFF C4C4C4D9  |................|
+CHECK-NEXT:    02C0: D9D9BEBE BEFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    02D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    02E0: FFFFFFFF FFFFFFFF FFFFFFFF C8C8C8C5  |................|
+CHECK-NEXT:    02F0: C5C5FFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0300: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0310: FFFFFFFF FFFFFFFF FFFFFFFF CBCBCBFF  |................|
+CHECK-NEXT:    0320: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0330: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0340: 28000000 10000000 10000000 01001800  |(...............|
+CHECK-NEXT:    0350: 00000000 00030000 C40E0000 C40E0000  |................|
+CHECK-NEXT:    0360: 00000000 00000000 FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0370: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0380: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0390: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    03A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    03B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    03C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    03D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    03E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0420: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0430: FFFFFFFF A0E3A901 B31801B3 1801B318  |................|
+CHECK-NEXT:    0440: 01B31801 B31801B3 1861D06F FFFFFFFF  |.........a.o....|
+CHECK-NEXT:    0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0460: FFFFFFFF 01B31800 D7331CDB 49DBF9E2  |.........3..I...|
+CHECK-NEXT:    0470: 9BEFAF00 D73300D7 3301B318 FFFFFFFF  |.....3..3.......|
+CHECK-NEXT:    0480: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0490: FFFFFFFF 01B31800 DE55F6FE F9DBFAE7  |.........U......|
+CHECK-NEXT:    04A0: FEFFFE86 EFAE00DE 5501B318 FFFFFFFF  |........U.......|
+CHECK-NEXT:    04B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    04C0: FFFFFFFF 01B31800 E676DBFB EC00E676  |.........v.....v|
+CHECK-NEXT:    04D0: 57EFA5FB FFFD55EE A401B318 FFFFFFFF  |W.....U.........|
+CHECK-NEXT:    04E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    04F0: FFFFFFFF 01B31800 ED9800ED 9800ED98  |................|
+CHECK-NEXT:    0500: 00ED9887 F7CFFEFF FF01B318 FFFFFFFF  |................|
+CHECK-NEXT:    0510: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0520: FFFFFFFF 01B31800 F4BA00F4 BA00F4BA  |................|
+CHECK-NEXT:    0530: 00F4BA00 F4BA9CFB E401B318 FFFFFFFF  |................|
+CHECK-NEXT:    0540: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0550: FFFFFFFF 01B31800 FBDB00FB DB00FBDB  |................|
+CHECK-NEXT:    0560: 00FBDB00 FBDB00FB DB01B318 FFFFFFFF  |................|
+CHECK-NEXT:    0570: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0580: FFFFFFFF 9FE2A801 B31801B3 1801B318  |................|
+CHECK-NEXT:    0590: 01B31801 B31801B3 1861D06F FFFFFFFF  |.........a.o....|
+CHECK-NEXT:    05A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    05B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    05D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    05E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0600: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0610: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0630: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0640: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT:    0660: FFFFFFFF FFFFFFFF 00000000 00006400  |..............d.|
+CHECK-NEXT:    0670: 79007500 00000000 65007300 68006100  |y.u.....e.s.h.a.|
+CHECK-NEXT:    0680: 6C006100 00008000 66006B00 61006F00  |l.a.....f.k.a.o.|
+CHECK-NEXT:    0690: 79006100 00000000 0000C080 00000000  |y.a.............|
+CHECK-NEXT:    06A0: 02000A00 0A00C800 2C010000 00005400  |........,.....T.|
+CHECK-NEXT:    06B0: 65007300 74000000 01000250 00000000  |e.s.t......P....|
+CHECK-NEXT:    06C0: 0A000A00 E6000E00 0100FFFF 82004300  |..............C.|
+CHECK-NEXT:    06D0: 6F006E00 74006900 6E007500 65003A00  |o.n.t.i.n.u.e.:.|
+CHECK-NEXT:    06E0: 00000000 00000150 00000000 42008600  |.......P....B...|
+CHECK-NEXT:    06F0: A1000D00 0200FFFF 80002600 4F004B00  |..........&.O.K.|
+CHECK-NEXT:    0700: 00000000 00000000 11005800 A4000000  |..........X.....|
+CHECK-NEXT:    0710: 0D004800 2E160000 82001200 BC010000  |..H.............|
+CHECK-NEXT:    0720: 00000000 00006400 66006900 73006800  |......d.f.i.s.h.|
+CHECK-NEXT:    0730: 00000000 65007300 61006C00 61006400  |....e.s.a.l.a.d.|
+CHECK-NEXT:    0740: 00008000 66006400 75006300 6B000000  |....f.d.u.c.k...|
+CHECK-NEXT:    0750: 74686973 20697320 61207573 65722064  |this is a user d|
+CHECK-NEXT:    0760: 6566696E 65642072 65736F75 72636500  |efined resource.|
+CHECK-NEXT:    0770: 69742063 6F6E7461 696E7320 6D616E79  |it contains many|
+CHECK-NEXT:    0780: 20737472 696E6773 00000000 00000000  | strings........|
+CHECK-NEXT:  )

Added: llvm/trunk/test/tools/llvm-cvtres/parse.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/parse.test?rev=305092&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cvtres/parse.test (added)
+++ llvm/trunk/test/tools/llvm-cvtres/parse.test Fri Jun  9 12:34:30 2017
@@ -0,0 +1,51 @@
+// The input was generated with the following command, using the original Windows
+// rc.exe:
+// > rc /fo test_resource.res /nologo test_resource.rc
+
+RUN: llvm-cvtres /verbose %p/Inputs/test_resource.res | FileCheck %s
+
+CHECK:      Number of resources: 8
+CHECK-NEXT: Resource Tree [
+CHECK-NEXT:   STRINGARRAY [
+CHECK-NEXT:     MYRESOURCE [
+CHECK-NEXT:       1033 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   2 [
+CHECK-NEXT:     CURSOR [
+CHECK-NEXT:       1033 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:     OKAY [
+CHECK-NEXT:       1033 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   4 [
+CHECK-NEXT:     "EAT" [
+CHECK-NEXT:       3081 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:     14432 [
+CHECK-NEXT:       2052 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   5 [
+CHECK-NEXT:     TESTDIALOG [
+CHECK-NEXT:       1033 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT:   9 [
+CHECK-NEXT:     MYACCELERATORS [
+CHECK-NEXT:       1033 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:     12 [
+CHECK-NEXT:       1033 [
+CHECK-NEXT:       ]
+CHECK-NEXT:     ]
+CHECK-NEXT:   ]
+CHECK-NEXT: ]

Removed: llvm/trunk/test/tools/llvm-cvtres/resource.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/resource.test?rev=305091&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cvtres/resource.test (original)
+++ llvm/trunk/test/tools/llvm-cvtres/resource.test (removed)
@@ -1,51 +0,0 @@
-// The input was generated with the following command, using the original Windows
-// rc.exe:
-// > rc /fo test_resource.res /nologo test_resource.rc
-
-RUN: llvm-cvtres %p/Inputs/test_resource.res | FileCheck %s
-
-CHECK:      Number of resources: 8
-CHECK-NEXT: Resource Tree [
-CHECK-NEXT:   STRINGARRAY [
-CHECK-NEXT:     MYRESOURCE [
-CHECK-NEXT:       1033 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:   ]
-CHECK-NEXT:   2 [
-CHECK-NEXT:     CURSOR [
-CHECK-NEXT:       1033 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:     OKAY [
-CHECK-NEXT:       1033 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:   ]
-CHECK-NEXT:   4 [
-CHECK-NEXT:     "EAT" [
-CHECK-NEXT:       3081 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:     14432 [
-CHECK-NEXT:       2052 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:   ]
-CHECK-NEXT:   5 [
-CHECK-NEXT:     TESTDIALOG [
-CHECK-NEXT:       1033 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:   ]
-CHECK-NEXT:   9 [
-CHECK-NEXT:     MYACCELERATORS [
-CHECK-NEXT:       1033 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:     12 [
-CHECK-NEXT:       1033 [
-CHECK-NEXT:       ]
-CHECK-NEXT:     ]
-CHECK-NEXT:   ]
-CHECK-NEXT: ]

Modified: llvm/trunk/tools/llvm-cvtres/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cvtres/LLVMBuild.txt?rev=305092&r1=305091&r2=305092&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cvtres/LLVMBuild.txt (original)
+++ llvm/trunk/tools/llvm-cvtres/LLVMBuild.txt Fri Jun  9 12:34:30 2017
@@ -19,4 +19,4 @@
 type = Tool
 name = llvm-cvtres
 parent = Tools
-required_libraries = Option Support
+required_libraries = Object Option Support

Modified: llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp?rev=305092&r1=305091&r2=305092&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp (original)
+++ llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp Fri Jun  9 12:34:30 2017
@@ -112,20 +112,23 @@ int main(int argc_, const char *argv_[])
     return 0;
   }
 
-  machine Machine;
+  bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
+
+  Machine MachineType;
 
   if (InputArgs.hasArg(OPT_MACHINE)) {
     std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper();
-    Machine = StringSwitch<machine>(MachineString)
-                  .Case("ARM", machine::ARM)
-                  .Case("X64", machine::X64)
-                  .Case("X86", machine::X86)
-                  .Default(machine::UNKNOWN);
-    if (Machine == machine::UNKNOWN)
+    MachineType = StringSwitch<Machine>(MachineString)
+                      .Case("ARM", Machine::ARM)
+                      .Case("X64", Machine::X64)
+                      .Case("X86", Machine::X86)
+                      .Default(Machine::UNKNOWN);
+    if (MachineType == Machine::UNKNOWN)
       reportError("Unsupported machine architecture");
   } else {
-    outs() << "Machine architecture not specified; assumed X64.\n";
-    Machine = machine::X64;
+    if (Verbose)
+      outs() << "Machine architecture not specified; assumed X64.\n";
+    MachineType = Machine::X64;
   }
 
   std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
@@ -139,20 +142,22 @@ int main(int argc_, const char *argv_[])
   if (InputArgs.hasArg(OPT_OUT)) {
     OutputFile = InputArgs.getLastArgValue(OPT_OUT);
   } else {
-    OutputFile = StringRef(InputFiles[0]);
+    OutputFile = llvm::sys::path::filename(StringRef(InputFiles[0]));
     llvm::sys::path::replace_extension(OutputFile, ".obj");
   }
 
-  outs() << "Machine: ";
-  switch (Machine) {
-  case machine::ARM:
-    outs() << "ARM\n";
-    break;
-  case machine::X86:
-    outs() << "X86\n";
-    break;
-  default:
-    outs() << "X64\n";
+  if (Verbose) {
+    outs() << "Machine: ";
+    switch (MachineType) {
+    case Machine::ARM:
+      outs() << "ARM\n";
+      break;
+    case Machine::X86:
+      outs() << "X86\n";
+      break;
+    default:
+      outs() << "X64\n";
+    }
   }
 
   WindowsResourceParser Parser;
@@ -169,22 +174,28 @@ int main(int argc_, const char *argv_[])
     if (!RF)
       reportError(File + ": unrecognized file format.\n");
 
-    int EntryNumber = 0;
-    Expected<ResourceEntryRef> EntryOrErr = RF->getHeadEntry();
-    if (!EntryOrErr)
-      error(EntryOrErr.takeError());
-    ResourceEntryRef Entry = EntryOrErr.get();
-    bool End = false;
-    while (!End) {
-      error(Entry.moveNext(End));
-      EntryNumber++;
+    if (Verbose) {
+      int EntryNumber = 0;
+      Expected<ResourceEntryRef> EntryOrErr = RF->getHeadEntry();
+      if (!EntryOrErr)
+        error(EntryOrErr.takeError());
+      ResourceEntryRef Entry = EntryOrErr.get();
+      bool End = false;
+      while (!End) {
+        error(Entry.moveNext(End));
+        EntryNumber++;
+      }
+      outs() << "Number of resources: " << EntryNumber << "\n";
     }
-    outs() << "Number of resources: " << EntryNumber << "\n";
 
     error(Parser.parse(RF));
   }
 
-  Parser.printTree();
+  if (Verbose)
+    Parser.printTree();
+
+  error(
+      llvm::object::writeWindowsResourceCOFF(OutputFile, MachineType, Parser));
 
   return 0;
 }

Modified: llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h?rev=305092&r1=305091&r2=305092&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h (original)
+++ llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h Fri Jun  9 12:34:30 2017
@@ -14,6 +14,4 @@
 
 void error(std::error_code EC);
 
-enum class machine { UNKNOWN = 0, ARM, X64, X86 };
-
 #endif




More information about the llvm-commits mailing list