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

Evgenii Stepanov via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 9 15:02:03 PDT 2017


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


More information about the llvm-commits mailing list