diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-06-16 21:03:24 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-06-16 21:03:24 +0000 | 
| commit | 7c7aba6e5fef47a01a136be655b0a92cfd7090f6 (patch) | |
| tree | 99ec531924f6078534b100ab9d7696abce848099 /lib/Object/WindowsResource.cpp | |
| parent | 7ab83427af0f77b59941ceba41d509d7d097b065 (diff) | |
Notes
Diffstat (limited to 'lib/Object/WindowsResource.cpp')
| -rw-r--r-- | lib/Object/WindowsResource.cpp | 156 | 
1 files changed, 90 insertions, 66 deletions
diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp index 041659e7aa239..3f6080d48f9d1 100644 --- a/lib/Object/WindowsResource.cpp +++ b/lib/Object/WindowsResource.cpp @@ -30,6 +30,10 @@ namespace object {  const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); +// COFF files seem to be inconsistent with alignment between sections, just use +// 8-byte because it makes everyone happy. +const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); +  static const size_t ResourceMagicSize = 16;  static const size_t NullEntrySize = 16; @@ -66,7 +70,7 @@ ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,                                     const WindowsResource *Owner, Error &Err)      : Reader(Ref), OwningRes(Owner) {    if (loadNext()) -    Err = make_error<GenericBinaryError>("Could not read first entry.", +    Err = make_error<GenericBinaryError>("Could not read first entry.\n",                                           object_error::unexpected_eof);  } @@ -133,31 +137,35 @@ Error WindowsResourceParser::parse(WindowsResource *WR) {    ResourceEntryRef Entry = EntryOrErr.get();    bool End = false;    while (!End) { -      Data.push_back(Entry.getData()); -    if (Entry.checkTypeString()) +    bool IsNewTypeString = false; +    bool IsNewNameString = false; + +    Root.addEntry(Entry, IsNewTypeString, IsNewNameString); + +    if (IsNewTypeString)        StringTable.push_back(Entry.getTypeString()); -    if (Entry.checkNameString()) +    if (IsNewNameString)        StringTable.push_back(Entry.getNameString()); -    Root.addEntry(Entry); -      RETURN_IF_ERROR(Entry.moveNext(End));    }    return Error::success();  } -void WindowsResourceParser::printTree() const { -  ScopedPrinter Writer(outs()); +void WindowsResourceParser::printTree(raw_ostream &OS) const { +  ScopedPrinter Writer(OS);    Root.print(Writer, "Resource Tree");  } -void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) { -  TreeNode &TypeNode = addTypeNode(Entry); -  TreeNode &NameNode = TypeNode.addNameNode(Entry); +void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, +                                               bool &IsNewTypeString, +                                               bool &IsNewNameString) { +  TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString); +  TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);    NameNode.addLanguageNode(Entry);  } @@ -171,7 +179,6 @@ WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,                                            uint32_t Characteristics)      : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),        Characteristics(Characteristics) { -  if (IsDataNode)      DataIndex = DataCount++;  } @@ -194,17 +201,19 @@ WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,  }  WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) { +WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry, +                                             bool &IsNewTypeString) {    if (Entry.checkTypeString()) -    return addChild(Entry.getTypeString()); +    return addChild(Entry.getTypeString(), IsNewTypeString);    else      return addChild(Entry.getTypeID());  }  WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry) { +WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry, +                                             bool &IsNewNameString) {    if (Entry.checkNameString()) -    return addChild(Entry.getNameString()); +    return addChild(Entry.getNameString(), IsNewNameString);    else      return addChild(Entry.getNameID());  } @@ -232,7 +241,8 @@ WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(  }  WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef) { +WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef, +                                          bool &IsNewString) {    std::string NameString;    ArrayRef<UTF16> CorrectedName;    std::vector<UTF16> EndianCorrectedName; @@ -248,6 +258,7 @@ WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef) {    auto Child = StringChildren.find(NameString);    if (Child == StringChildren.end()) {      auto NewChild = createStringNode(); +    IsNewString = true;      WindowsResourceParser::TreeNode &Node = *NewChild;      StringChildren.emplace(NameString, std::move(NewChild));      return Node; @@ -296,7 +307,6 @@ class WindowsResourceCOFFWriter {  public:    WindowsResourceCOFFWriter(StringRef OutputFile, Machine MachineType,                              const WindowsResourceParser &Parser, Error &E); -    Error write();  private: @@ -314,7 +324,8 @@ private:    void writeDirectoryStringTable();    void writeFirstSectionRelocations();    std::unique_ptr<FileOutputBuffer> Buffer; -  uint8_t *Current; +  uint8_t *BufferStart; +  uint64_t CurrentOffset = 0;    Machine MachineType;    const WindowsResourceParser::TreeNode &Resources;    const ArrayRef<std::vector<uint8_t>> Data; @@ -386,6 +397,7 @@ void WindowsResourceCOFFWriter::performSectionOneLayout() {    FileSize += SectionOneSize;    FileSize += Data.size() *                llvm::COFF::RelocationSize; // one relocation for each resource. +  FileSize = alignTo(FileSize, SECTION_ALIGNMENT);  }  void WindowsResourceCOFFWriter::performSectionTwoLayout() { @@ -398,6 +410,7 @@ void WindowsResourceCOFFWriter::performSectionTwoLayout() {      SectionTwoSize += llvm::alignTo(Entry.size(), sizeof(uint64_t));    }    FileSize += SectionTwoSize; +  FileSize = alignTo(FileSize, SECTION_ALIGNMENT);  }  static std::time_t getTime() { @@ -408,7 +421,7 @@ static std::time_t getTime() {  }  Error WindowsResourceCOFFWriter::write() { -  Current = Buffer->getBufferStart(); +  BufferStart = Buffer->getBufferStart();    writeCOFFHeader();    writeFirstSectionHeader(); @@ -427,7 +440,8 @@ Error WindowsResourceCOFFWriter::write() {  void WindowsResourceCOFFWriter::writeCOFFHeader() {    // Write the COFF header. -  auto *Header = reinterpret_cast<llvm::object::coff_file_header *>(Current); +  auto *Header = +      reinterpret_cast<llvm::object::coff_file_header *>(BufferStart);    switch (MachineType) {    case Machine::ARM:      Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; @@ -452,9 +466,9 @@ void WindowsResourceCOFFWriter::writeCOFFHeader() {  void WindowsResourceCOFFWriter::writeFirstSectionHeader() {    // Write the first section header. -  Current += sizeof(llvm::object::coff_file_header); -  auto *SectionOneHeader = -      reinterpret_cast<llvm::object::coff_section *>(Current); +  CurrentOffset += sizeof(llvm::object::coff_file_header); +  auto *SectionOneHeader = reinterpret_cast<llvm::object::coff_section *>( +      BufferStart + CurrentOffset);    strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)llvm::COFF::NameSize);    SectionOneHeader->VirtualSize = 0;    SectionOneHeader->VirtualAddress = 0; @@ -473,9 +487,9 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() {  void WindowsResourceCOFFWriter::writeSecondSectionHeader() {    // Write the second section header. -  Current += sizeof(llvm::object::coff_section); -  auto *SectionTwoHeader = -      reinterpret_cast<llvm::object::coff_section *>(Current); +  CurrentOffset += sizeof(llvm::object::coff_section); +  auto *SectionTwoHeader = reinterpret_cast<llvm::object::coff_section *>( +      BufferStart + CurrentOffset);    strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)llvm::COFF::NameSize);    SectionTwoHeader->VirtualSize = 0;    SectionTwoHeader->VirtualAddress = 0; @@ -492,75 +506,85 @@ void WindowsResourceCOFFWriter::writeSecondSectionHeader() {  void WindowsResourceCOFFWriter::writeFirstSection() {    // Write section one. -  Current += sizeof(llvm::object::coff_section); +  CurrentOffset += sizeof(llvm::object::coff_section);    writeDirectoryTree();    writeDirectoryStringTable();    writeFirstSectionRelocations(); + +  CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);  }  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)); +    std::copy(RawDataEntry.begin(), RawDataEntry.end(), +              BufferStart + CurrentOffset); +    CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));    } + +  CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);  }  void WindowsResourceCOFFWriter::writeSymbolTable() {    // Now write the symbol table.    // First, the feat symbol. -  auto *Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current); +  auto *Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(BufferStart + +                                                                 CurrentOffset);    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); +  CurrentOffset += sizeof(llvm::object::coff_symbol16);    // Now write the .rsrc1 symbol + aux. -  Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current); +  Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(BufferStart + +                                                           CurrentOffset);    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); +  CurrentOffset += sizeof(llvm::object::coff_symbol16); +  auto *Aux = reinterpret_cast<llvm::object::coff_aux_section_definition *>( +      BufferStart + CurrentOffset);    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); +  CurrentOffset += sizeof(llvm::object::coff_aux_section_definition);    // Now write the .rsrc2 symbol + aux. -  Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current); +  Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(BufferStart + +                                                           CurrentOffset);    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); +  CurrentOffset += sizeof(llvm::object::coff_symbol16); +  Aux = reinterpret_cast<llvm::object::coff_aux_section_definition *>( +      BufferStart + CurrentOffset);    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); +  CurrentOffset += 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); +    Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(BufferStart + +                                                             CurrentOffset);      strncpy(Symbol->Name.ShortName, RelocationName,              (size_t)llvm::COFF::NameSize);      Symbol->Value = DataOffsets[i]; @@ -568,14 +592,14 @@ void WindowsResourceCOFFWriter::writeSymbolTable() {      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); +    CurrentOffset += 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; +  auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset); +  memset(COFFStringTable, 0, 4);  }  void WindowsResourceCOFFWriter::writeDirectoryTree() { @@ -593,8 +617,8 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() {    while (!Queue.empty()) {      auto CurrentNode = Queue.front();      Queue.pop(); -    auto *Table = -        reinterpret_cast<llvm::object::coff_resource_dir_table *>(Current); +    auto *Table = reinterpret_cast<llvm::object::coff_resource_dir_table *>( +        BufferStart + CurrentOffset);      Table->Characteristics = CurrentNode->getCharacteristics();      Table->TimeDateStamp = 0;      Table->MajorVersion = CurrentNode->getMajorVersion(); @@ -603,13 +627,13 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() {      auto &StringChildren = CurrentNode->getStringChildren();      Table->NumberOfNameEntries = StringChildren.size();      Table->NumberOfIDEntries = IDChildren.size(); -    Current += sizeof(llvm::object::coff_resource_dir_table); +    CurrentOffset += 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); +      auto *Entry = reinterpret_cast<llvm::object::coff_resource_dir_entry *>( +          BufferStart + CurrentOffset);        Entry->Identifier.NameOffset =            StringTableOffsets[Child.second->getStringIndex()];        if (Child.second->checkIsDataNode()) { @@ -624,12 +648,12 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() {                                 sizeof(llvm::object::coff_resource_dir_entry);          Queue.push(Child.second.get());        } -      Current += sizeof(llvm::object::coff_resource_dir_entry); +      CurrentOffset += 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); +      auto *Entry = reinterpret_cast<llvm::object::coff_resource_dir_entry *>( +          BufferStart + CurrentOffset);        Entry->Identifier.ID = Child.first;        if (Child.second->checkIsDataNode()) {          Entry->Offset.DataEntryOffset = NextLevelOffset; @@ -643,7 +667,7 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() {                                 sizeof(llvm::object::coff_resource_dir_entry);          Queue.push(Child.second.get());        } -      Current += sizeof(llvm::object::coff_resource_dir_entry); +      CurrentOffset += sizeof(llvm::object::coff_resource_dir_entry);        CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry);      }    } @@ -651,14 +675,14 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() {    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); +    auto *Entry = reinterpret_cast<llvm::object::coff_resource_data_entry *>( +        BufferStart + CurrentOffset);      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); +    CurrentOffset += sizeof(llvm::object::coff_resource_data_entry);      CurrentRelativeOffset += sizeof(llvm::object::coff_resource_data_entry);    }  } @@ -666,17 +690,16 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() {  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); +  for (auto &String : StringTable) {      uint16_t Length = String.size(); -    *LengthField = Length; -    Current += sizeof(uint16_t); -    auto *Start = reinterpret_cast<UTF16 *>(Current); +    support::endian::write16le(BufferStart + CurrentOffset, Length); +    CurrentOffset += sizeof(uint16_t); +    auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);      std::copy(String.begin(), String.end(), Start); -    Current += Length * sizeof(UTF16); +    CurrentOffset += Length * sizeof(UTF16);      TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);    } -  Current += +  CurrentOffset +=        alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;  } @@ -687,7 +710,8 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {    // .rsrc section.    uint32_t NextSymbolIndex = 5;    for (unsigned i = 0; i < Data.size(); i++) { -    auto *Reloc = reinterpret_cast<llvm::object::coff_relocation *>(Current); +    auto *Reloc = reinterpret_cast<llvm::object::coff_relocation *>( +        BufferStart + CurrentOffset);      Reloc->VirtualAddress = RelocationAddresses[i];      Reloc->SymbolTableIndex = NextSymbolIndex++;      switch (MachineType) { @@ -703,7 +727,7 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {      default:        Reloc->Type = 0;      } -    Current += sizeof(llvm::object::coff_relocation); +    CurrentOffset += sizeof(llvm::object::coff_relocation);    }  }  | 
