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

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 10 11:08:31 PDT 2017


I patched this in r305149 to unblock our bots. PTAL to make sure it looks ok.

vedant

> On Jun 9, 2017, at 3:02 PM, Evgenii Stepanov via llvm-commits <llvm-commits at lists.llvm.org> wrote:
> 
> Hi,
> 
> http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/5572
> 
> lib/Object/WindowsResource.cpp:578:3: runtime error: store to
> misaligned address 0x7fa09aedebbe for type 'unsigned int', which
> requires 4 byte alignment
> 0x7fa09aedebbe: note: pointer points here
> 00 00 03 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
> 00 00 00 00 00 00 00 00  00 00
>             ^
>    #0 0x44f81b in
> llvm::object::WindowsResourceCOFFWriter::writeStringTable()
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Object/WindowsResource.cpp:578:20
>    #1 0x44ef9b in llvm::object::WindowsResourceCOFFWriter::write()
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Object/WindowsResource.cpp:419:3
>    #2 0x450540 in
> llvm::object::writeWindowsResourceCOFF(llvm::StringRef,
> llvm::object::Machine, llvm::object::WindowsResourceParser const&)
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Object/WindowsResource.cpp:716:17
>    #3 0x43348f in main
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/llvm-cvtres/llvm-cvtres.cpp:198:7
> 
> 
> On Fri, Jun 9, 2017 at 10:34 AM, Eric Beckmann via llvm-commits
> <llvm-commits at lists.llvm.org> wrote:
>> 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
>> 
>> 
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list