aboutsummaryrefslogtreecommitdiff
path: root/lib/Object/WindowsResource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Object/WindowsResource.cpp')
-rw-r--r--lib/Object/WindowsResource.cpp156
1 files changed, 90 insertions, 66 deletions
diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp
index 041659e7aa23..3f6080d48f9d 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);
}
}