123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the .res file class.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/Object/WindowsResource.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>
- using namespace llvm;
- using namespace object;
- namespace llvm {
- namespace object {
- #define RETURN_IF_ERROR(X) \
- if (auto EC = X) \
- return EC;
- 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;
- 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;
- BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
- support::little);
- }
- Expected<std::unique_ptr<WindowsResource>>
- WindowsResource::createWindowsResource(MemoryBufferRef Source) {
- if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
- return make_error<GenericBinaryError>(
- "File too small to be a resource file",
- object_error::invalid_file_type);
- std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
- return std::move(Ret);
- }
- Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
- Error Err = Error::success();
- auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
- if (Err)
- return std::move(Err);
- return Ref;
- }
- ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
- const WindowsResource *Owner, Error &Err)
- : Reader(Ref), OwningRes(Owner) {
- if (loadNext())
- Err = make_error<GenericBinaryError>("Could not read first entry.\n",
- object_error::unexpected_eof);
- }
- Error ResourceEntryRef::moveNext(bool &End) {
- // Reached end of all the entries.
- if (Reader.bytesRemaining() == 0) {
- End = true;
- return Error::success();
- }
- RETURN_IF_ERROR(loadNext());
- return Error::success();
- }
- static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
- ArrayRef<UTF16> &Str, bool &IsString) {
- uint16_t IDFlag;
- RETURN_IF_ERROR(Reader.readInteger(IDFlag));
- IsString = IDFlag != 0xffff;
- if (IsString) {
- Reader.setOffset(
- Reader.getOffset() -
- sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
- RETURN_IF_ERROR(Reader.readWideString(Str));
- } else
- RETURN_IF_ERROR(Reader.readInteger(ID));
- return Error::success();
- }
- Error ResourceEntryRef::loadNext() {
- uint32_t DataSize;
- RETURN_IF_ERROR(Reader.readInteger(DataSize));
- uint32_t HeaderSize;
- RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
- if (HeaderSize < MIN_HEADER_SIZE)
- return make_error<GenericBinaryError>("Header size is too small.",
- object_error::parse_failed);
- RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
- RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
- RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
- RETURN_IF_ERROR(Reader.readObject(Suffix));
- RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
- RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
- return Error::success();
- }
- WindowsResourceParser::WindowsResourceParser() : Root(false) {}
- Error WindowsResourceParser::parse(WindowsResource *WR) {
- auto EntryOrErr = WR->getHeadEntry();
- if (!EntryOrErr)
- return EntryOrErr.takeError();
- ResourceEntryRef Entry = EntryOrErr.get();
- bool End = false;
- while (!End) {
- Data.push_back(Entry.getData());
- bool IsNewTypeString = false;
- bool IsNewNameString = false;
- Root.addEntry(Entry, IsNewTypeString, IsNewNameString);
- if (IsNewTypeString)
- StringTable.push_back(Entry.getTypeString());
- if (IsNewNameString)
- StringTable.push_back(Entry.getNameString());
- RETURN_IF_ERROR(Entry.moveNext(End));
- }
- return Error::success();
- }
- void WindowsResourceParser::printTree(raw_ostream &OS) const {
- ScopedPrinter Writer(OS);
- Root.print(Writer, "Resource Tree");
- }
- 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);
- }
- 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) {
- 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,
- bool &IsNewTypeString) {
- if (Entry.checkTypeString())
- return addChild(Entry.getTypeString(), IsNewTypeString);
- else
- return addChild(Entry.getTypeID());
- }
- WindowsResourceParser::TreeNode &
- WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry,
- bool &IsNewNameString) {
- if (Entry.checkNameString())
- return addChild(Entry.getNameString(), IsNewNameString);
- else
- return addChild(Entry.getNameID());
- }
- WindowsResourceParser::TreeNode &
- WindowsResourceParser::TreeNode::addLanguageNode(
- const ResourceEntryRef &Entry) {
- return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
- Entry.getMinorVersion(), Entry.getCharacteristics());
- }
- 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 =
- IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
- : createIDNode();
- WindowsResourceParser::TreeNode &Node = *NewChild;
- IDChildren.emplace(ID, std::move(NewChild));
- return Node;
- } else
- return *(Child->second);
- }
- WindowsResourceParser::TreeNode &
- WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef,
- bool &IsNewString) {
- std::string NameString;
- ArrayRef<UTF16> CorrectedName;
- std::vector<UTF16> EndianCorrectedName;
- if (sys::IsBigEndianHost) {
- EndianCorrectedName.resize(NameRef.size() + 1);
- std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1);
- EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
- CorrectedName = makeArrayRef(EndianCorrectedName);
- } else
- CorrectedName = NameRef;
- convertUTF16ToUTF8String(CorrectedName, NameString);
- 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;
- } else
- return *(Child->second);
- }
- void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
- StringRef Name) const {
- ListScope NodeScope(Writer, Name);
- for (auto const &Child : StringChildren) {
- Child.second->print(Writer, Child.first);
- }
- for (auto const &Child : IDChildren) {
- Child.second->print(Writer, to_string(Child.first));
- }
- }
- // 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(coff_resource_dir_entry);
- // Reached a node pointing to a data entry.
- if (IsDataNode) {
- Size += sizeof(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(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(COFF::MachineTypes MachineType,
- const WindowsResourceParser &Parser, Error &E);
- std::unique_ptr<MemoryBuffer> 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<MemoryBuffer> OutputBuffer;
- char *BufferStart;
- uint64_t CurrentOffset = 0;
- COFF::MachineTypes 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(
- COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
- Error &E)
- : MachineType(MachineType), Resources(Parser.getTree()),
- Data(Parser.getData()), StringTable(Parser.getStringTable()) {
- performFileLayout();
- OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize);
- }
- void WindowsResourceCOFFWriter::performFileLayout() {
- // Add size of COFF header.
- FileSize = COFF::Header16Size;
- // one .rsrc section header for directory tree, another for resource data.
- FileSize += 2 * COFF::SectionSize;
- performSectionOneLayout();
- performSectionTwoLayout();
- // We have reached the address of the symbol table.
- SymbolTableOffset = FileSize;
- FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol.
- FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
- FileSize += Data.size() * 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() * COFF::RelocationSize; // one relocation for each resource.
- FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
- }
- 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 += alignTo(Entry.size(), sizeof(uint64_t));
- }
- FileSize += SectionTwoSize;
- FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
- }
- static std::time_t getTime() {
- std::time_t Now = time(nullptr);
- if (Now < 0 || !isUInt<32>(Now))
- return UINT32_MAX;
- return Now;
- }
- std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() {
- BufferStart = const_cast<char *>(OutputBuffer->getBufferStart());
- writeCOFFHeader();
- writeFirstSectionHeader();
- writeSecondSectionHeader();
- writeFirstSection();
- writeSecondSection();
- writeSymbolTable();
- writeStringTable();
- return std::move(OutputBuffer);
- }
- void WindowsResourceCOFFWriter::writeCOFFHeader() {
- // Write the COFF header.
- auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
- switch (MachineType) {
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- Header->Machine = COFF::IMAGE_FILE_MACHINE_ARMNT;
- break;
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- Header->Machine = COFF::IMAGE_FILE_MACHINE_AMD64;
- break;
- case COFF::IMAGE_FILE_MACHINE_I386:
- Header->Machine = COFF::IMAGE_FILE_MACHINE_I386;
- break;
- default:
- Header->Machine = 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 = COFF::IMAGE_FILE_32BIT_MACHINE;
- }
- void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
- // Write the first section header.
- CurrentOffset += sizeof(coff_file_header);
- auto *SectionOneHeader =
- reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
- strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)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 = COFF::IMAGE_SCN_ALIGN_1BYTES;
- SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
- SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
- SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
- }
- void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
- // Write the second section header.
- CurrentOffset += sizeof(coff_section);
- auto *SectionTwoHeader =
- reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
- strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)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 = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
- SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
- }
- void WindowsResourceCOFFWriter::writeFirstSection() {
- // Write section one.
- CurrentOffset += sizeof(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(),
- 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<coff_symbol16 *>(BufferStart + CurrentOffset);
- strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize);
- Symbol->Value = 0x11;
- Symbol->SectionNumber = 0xffff;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 0;
- CurrentOffset += sizeof(coff_symbol16);
- // Now write the .rsrc1 symbol + aux.
- Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize);
- Symbol->Value = 0;
- Symbol->SectionNumber = 1;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 1;
- CurrentOffset += sizeof(coff_symbol16);
- auto *Aux = reinterpret_cast<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;
- CurrentOffset += sizeof(coff_aux_section_definition);
- // Now write the .rsrc2 symbol + aux.
- Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize);
- Symbol->Value = 0;
- Symbol->SectionNumber = 2;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 1;
- CurrentOffset += sizeof(coff_symbol16);
- Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
- CurrentOffset);
- Aux->Length = SectionTwoSize;
- Aux->NumberOfRelocations = 0;
- Aux->NumberOfLinenumbers = 0;
- Aux->CheckSum = 0;
- Aux->NumberLowPart = 0;
- Aux->Selection = 0;
- CurrentOffset += sizeof(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<coff_symbol16 *>(BufferStart + CurrentOffset);
- strncpy(Symbol->Name.ShortName, RelocationName, (size_t)COFF::NameSize);
- Symbol->Value = DataOffsets[i];
- Symbol->SectionNumber = 1;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 0;
- CurrentOffset += sizeof(coff_symbol16);
- }
- }
- void WindowsResourceCOFFWriter::writeStringTable() {
- // Just 4 null bytes for the string table.
- auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
- memset(COFFStringTable, 0, 4);
- }
- 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(coff_resource_dir_table) + (Resources.getStringChildren().size() +
- Resources.getIDChildren().size()) *
- sizeof(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<coff_resource_dir_table *>(BufferStart +
- CurrentOffset);
- 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();
- CurrentOffset += sizeof(coff_resource_dir_table);
- CurrentRelativeOffset += sizeof(coff_resource_dir_table);
- // Write the directory entries immediately following each directory table.
- for (auto const &Child : StringChildren) {
- auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
- CurrentOffset);
- Entry->Identifier.NameOffset =
- StringTableOffsets[Child.second->getStringIndex()];
- if (Child.second->checkIsDataNode()) {
- Entry->Offset.DataEntryOffset = NextLevelOffset;
- NextLevelOffset += sizeof(coff_resource_data_entry);
- DataEntriesTreeOrder.push_back(Child.second.get());
- } else {
- Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
- NextLevelOffset += sizeof(coff_resource_dir_table) +
- (Child.second->getStringChildren().size() +
- Child.second->getIDChildren().size()) *
- sizeof(coff_resource_dir_entry);
- Queue.push(Child.second.get());
- }
- CurrentOffset += sizeof(coff_resource_dir_entry);
- CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
- }
- for (auto const &Child : IDChildren) {
- auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
- CurrentOffset);
- Entry->Identifier.ID = Child.first;
- if (Child.second->checkIsDataNode()) {
- Entry->Offset.DataEntryOffset = NextLevelOffset;
- NextLevelOffset += sizeof(coff_resource_data_entry);
- DataEntriesTreeOrder.push_back(Child.second.get());
- } else {
- Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
- NextLevelOffset += sizeof(coff_resource_dir_table) +
- (Child.second->getStringChildren().size() +
- Child.second->getIDChildren().size()) *
- sizeof(coff_resource_dir_entry);
- Queue.push(Child.second.get());
- }
- CurrentOffset += sizeof(coff_resource_dir_entry);
- CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
- }
- }
- RelocationAddresses.resize(Data.size());
- // Now write all the resource data entries.
- for (auto DataNodes : DataEntriesTreeOrder) {
- auto *Entry = reinterpret_cast<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;
- CurrentOffset += sizeof(coff_resource_data_entry);
- CurrentRelativeOffset += sizeof(coff_resource_data_entry);
- }
- }
- void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
- // Now write the directory string table for .rsrc$01
- uint32_t TotalStringTableSize = 0;
- for (auto &String : StringTable) {
- uint16_t Length = String.size();
- support::endian::write16le(BufferStart + CurrentOffset, Length);
- CurrentOffset += sizeof(uint16_t);
- auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
- std::copy(String.begin(), String.end(), Start);
- CurrentOffset += Length * sizeof(UTF16);
- TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
- }
- CurrentOffset +=
- 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<coff_relocation *>(BufferStart + CurrentOffset);
- Reloc->VirtualAddress = RelocationAddresses[i];
- Reloc->SymbolTableIndex = NextSymbolIndex++;
- switch (MachineType) {
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
- break;
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
- break;
- case COFF::IMAGE_FILE_MACHINE_I386:
- Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
- break;
- default:
- Reloc->Type = 0;
- }
- CurrentOffset += sizeof(coff_relocation);
- }
- }
- Expected<std::unique_ptr<MemoryBuffer>>
- writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
- const WindowsResourceParser &Parser) {
- Error E = Error::success();
- WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
- if (E)
- return std::move(E);
- return Writer.write();
- }
- } // namespace object
- } // namespace llvm
|