From e79a17e385d03cc9750c748eb27bb77fdd58affb Mon Sep 17 00:00:00 2001 From: Sean Silva Date: Wed, 5 Jun 2013 19:56:47 +0000 Subject: [PATCH] yaml2obj: split out COFF logic into separate file llvm-svn: 183335 --- tools/yaml2obj/CMakeLists.txt | 1 + tools/yaml2obj/yaml2coff.cpp | 306 ++++++++++++++++++++++++++++++++++ tools/yaml2obj/yaml2obj.cpp | 289 +------------------------------- tools/yaml2obj/yaml2obj.h | 21 +++ 4 files changed, 330 insertions(+), 287 deletions(-) create mode 100644 tools/yaml2obj/yaml2coff.cpp create mode 100644 tools/yaml2obj/yaml2obj.h diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt index 0918ea365e4..5cccf9330ed 100644 --- a/tools/yaml2obj/CMakeLists.txt +++ b/tools/yaml2obj/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS object) add_llvm_utility(yaml2obj yaml2obj.cpp + yaml2coff.cpp ) target_link_libraries(yaml2obj LLVMSupport) diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp new file mode 100644 index 00000000000..54c5fb1256f --- /dev/null +++ b/tools/yaml2obj/yaml2coff.cpp @@ -0,0 +1,306 @@ +//===- yaml2coff - Convert YAML to a COFF object file ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief The COFF component of yaml2obj. +/// +//===----------------------------------------------------------------------===// + +#include "yaml2obj.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/COFFYAML.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; + +/// This parses a yaml stream that represents a COFF object file. +/// See docs/yaml2obj for the yaml scheema. +struct COFFParser { + COFFParser(COFFYAML::Object &Obj) : Obj(Obj) { + // A COFF string table always starts with a 4 byte size field. Offsets into + // it include this size, so allocate it now. + StringTable.append(4, 0); + } + + bool parseSections() { + for (std::vector::iterator i = Obj.Sections.begin(), + e = Obj.Sections.end(); i != e; ++i) { + COFFYAML::Section &Sec = *i; + + // If the name is less than 8 bytes, store it in place, otherwise + // store it in the string table. + StringRef Name = Sec.Name; + + if (Name.size() <= COFF::NameSize) { + std::copy(Name.begin(), Name.end(), Sec.Header.Name); + } else { + // Add string to the string table and format the index for output. + unsigned Index = getStringIndex(Name); + std::string str = utostr(Index); + if (str.size() > 7) { + errs() << "String table got too large"; + return false; + } + Sec.Header.Name[0] = '/'; + std::copy(str.begin(), str.end(), Sec.Header.Name + 1); + } + + Sec.Header.Characteristics |= (Log2_32(Sec.Alignment) + 1) << 20; + } + return true; + } + + bool parseSymbols() { + for (std::vector::iterator i = Obj.Symbols.begin(), + e = Obj.Symbols.end(); i != e; ++i) { + COFFYAML::Symbol &Sym = *i; + + // If the name is less than 8 bytes, store it in place, otherwise + // store it in the string table. + StringRef Name = Sym.Name; + if (Name.size() <= COFF::NameSize) { + std::copy(Name.begin(), Name.end(), Sym.Header.Name); + } else { + // Add string to the string table and format the index for output. + unsigned Index = getStringIndex(Name); + *reinterpret_cast( + Sym.Header.Name + 4) = Index; + } + + Sym.Header.Type = Sym.SimpleType; + Sym.Header.Type |= Sym.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT; + } + return true; + } + + bool parse() { + if (!parseSections()) + return false; + if (!parseSymbols()) + return false; + return true; + } + + unsigned getStringIndex(StringRef Str) { + StringMap::iterator i = StringTableMap.find(Str); + if (i == StringTableMap.end()) { + unsigned Index = StringTable.size(); + StringTable.append(Str.begin(), Str.end()); + StringTable.push_back(0); + StringTableMap[Str] = Index; + return Index; + } + return i->second; + } + + COFFYAML::Object &Obj; + + StringMap StringTableMap; + std::string StringTable; +}; + +// Take a CP and assign addresses and sizes to everything. Returns false if the +// layout is not valid to do. +static bool layoutCOFF(COFFParser &CP) { + uint32_t SectionTableStart = 0; + uint32_t SectionTableSize = 0; + + // The section table starts immediately after the header, including the + // optional header. + SectionTableStart = sizeof(COFF::header) + CP.Obj.Header.SizeOfOptionalHeader; + SectionTableSize = sizeof(COFF::section) * CP.Obj.Sections.size(); + + uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize; + + // Assign each section data address consecutively. + for (std::vector::iterator i = CP.Obj.Sections.begin(), + e = CP.Obj.Sections.end(); + i != e; ++i) { + StringRef SecData = i->SectionData.getHex(); + if (!SecData.empty()) { + i->Header.SizeOfRawData = SecData.size()/2; + i->Header.PointerToRawData = CurrentSectionDataOffset; + CurrentSectionDataOffset += i->Header.SizeOfRawData; + if (!i->Relocations.empty()) { + i->Header.PointerToRelocations = CurrentSectionDataOffset; + i->Header.NumberOfRelocations = i->Relocations.size(); + CurrentSectionDataOffset += i->Header.NumberOfRelocations * + COFF::RelocationSize; + } + // TODO: Handle alignment. + } else { + i->Header.SizeOfRawData = 0; + i->Header.PointerToRawData = 0; + } + } + + uint32_t SymbolTableStart = CurrentSectionDataOffset; + + // Calculate number of symbols. + uint32_t NumberOfSymbols = 0; + for (std::vector::iterator i = CP.Obj.Symbols.begin(), + e = CP.Obj.Symbols.end(); + i != e; ++i) { + unsigned AuxBytes = i->AuxiliaryData.getHex().size() / 2; + if (AuxBytes % COFF::SymbolSize != 0) { + errs() << "AuxiliaryData size not a multiple of symbol size!\n"; + return false; + } + i->Header.NumberOfAuxSymbols = AuxBytes / COFF::SymbolSize; + NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols; + } + + // Store all the allocated start addresses in the header. + CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size(); + CP.Obj.Header.NumberOfSymbols = NumberOfSymbols; + CP.Obj.Header.PointerToSymbolTable = SymbolTableStart; + + *reinterpret_cast(&CP.StringTable[0]) + = CP.StringTable.size(); + + return true; +} + +template +struct binary_le_impl { + value_type Value; + binary_le_impl(value_type V) : Value(V) {} +}; + +template +raw_ostream &operator <<( raw_ostream &OS + , const binary_le_impl &BLE) { + char Buffer[sizeof(BLE.Value)]; + support::endian::write( + Buffer, BLE.Value); + OS.write(Buffer, sizeof(BLE.Value)); + return OS; +} + +template +binary_le_impl binary_le(value_type V) { + return binary_le_impl(V); +} + +static bool writeHexData(StringRef Data, raw_ostream &OS) { + unsigned Size = Data.size(); + if (Size % 2) + return false; + + for (unsigned I = 0; I != Size; I += 2) { + uint8_t Byte; + if (Data.substr(I, 2).getAsInteger(16, Byte)) + return false; + OS.write(Byte); + } + + return true; +} + +bool writeCOFF(COFFParser &CP, raw_ostream &OS) { + OS << binary_le(CP.Obj.Header.Machine) + << binary_le(CP.Obj.Header.NumberOfSections) + << binary_le(CP.Obj.Header.TimeDateStamp) + << binary_le(CP.Obj.Header.PointerToSymbolTable) + << binary_le(CP.Obj.Header.NumberOfSymbols) + << binary_le(CP.Obj.Header.SizeOfOptionalHeader) + << binary_le(CP.Obj.Header.Characteristics); + + // Output section table. + for (std::vector::iterator i = CP.Obj.Sections.begin(), + e = CP.Obj.Sections.end(); + i != e; ++i) { + OS.write(i->Header.Name, COFF::NameSize); + OS << binary_le(i->Header.VirtualSize) + << binary_le(i->Header.VirtualAddress) + << binary_le(i->Header.SizeOfRawData) + << binary_le(i->Header.PointerToRawData) + << binary_le(i->Header.PointerToRelocations) + << binary_le(i->Header.PointerToLineNumbers) + << binary_le(i->Header.NumberOfRelocations) + << binary_le(i->Header.NumberOfLineNumbers) + << binary_le(i->Header.Characteristics); + } + + // Output section data. + for (std::vector::iterator i = CP.Obj.Sections.begin(), + e = CP.Obj.Sections.end(); + i != e; ++i) { + StringRef SecData = i->SectionData.getHex(); + if (!SecData.empty()) { + if (!writeHexData(SecData, OS)) { + errs() << "SectionData must be a collection of pairs of hex bytes"; + return false; + } + } + for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) { + const COFF::relocation &R = i->Relocations[I2]; + OS << binary_le(R.VirtualAddress) + << binary_le(R.SymbolTableIndex) + << binary_le(R.Type); + } + } + + // Output symbol table. + + for (std::vector::const_iterator i = CP.Obj.Symbols.begin(), + e = CP.Obj.Symbols.end(); + i != e; ++i) { + OS.write(i->Header.Name, COFF::NameSize); + OS << binary_le(i->Header.Value) + << binary_le(i->Header.SectionNumber) + << binary_le(i->Header.Type) + << binary_le(i->Header.StorageClass) + << binary_le(i->Header.NumberOfAuxSymbols); + StringRef Data = i->AuxiliaryData.getHex(); + if (!Data.empty()) { + if (!writeHexData(Data, OS)) { + errs() << "AuxiliaryData must be a collection of pairs of hex bytes"; + return false; + } + } + } + + // Output string table. + OS.write(&CP.StringTable[0], CP.StringTable.size()); + return true; +} + +int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { + yaml::Input YIn(Buf->getBuffer()); + COFFYAML::Object Doc; + YIn >> Doc; + if (YIn.error()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + + COFFParser CP(Doc); + if (!CP.parse()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + + if (!layoutCOFF(CP)) { + errs() << "yaml2obj: Failed to layout COFF file!\n"; + return 1; + } + if (!writeCOFF(CP, Out)) { + errs() << "yaml2obj: Failed to write COFF file!\n"; + return 1; + } + return 0; +} diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp index d042d7dfa63..a9ac78bce48 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -14,22 +14,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Object/COFFYAML.h" -#include "llvm/Support/Casting.h" +#include "yaml2obj.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include using namespace llvm; @@ -55,284 +48,6 @@ cl::opt Format( clEnumValN(YOF_COFF, "coff", "COFF object file format"), clEnumValEnd)); -/// This parses a yaml stream that represents a COFF object file. -/// See docs/yaml2obj for the yaml scheema. -struct COFFParser { - COFFParser(COFFYAML::Object &Obj) : Obj(Obj) { - // A COFF string table always starts with a 4 byte size field. Offsets into - // it include this size, so allocate it now. - StringTable.append(4, 0); - } - - bool parseSections() { - for (std::vector::iterator i = Obj.Sections.begin(), - e = Obj.Sections.end(); i != e; ++i) { - COFFYAML::Section &Sec = *i; - - // If the name is less than 8 bytes, store it in place, otherwise - // store it in the string table. - StringRef Name = Sec.Name; - - if (Name.size() <= COFF::NameSize) { - std::copy(Name.begin(), Name.end(), Sec.Header.Name); - } else { - // Add string to the string table and format the index for output. - unsigned Index = getStringIndex(Name); - std::string str = utostr(Index); - if (str.size() > 7) { - errs() << "String table got too large"; - return false; - } - Sec.Header.Name[0] = '/'; - std::copy(str.begin(), str.end(), Sec.Header.Name + 1); - } - - Sec.Header.Characteristics |= (Log2_32(Sec.Alignment) + 1) << 20; - } - return true; - } - - bool parseSymbols() { - for (std::vector::iterator i = Obj.Symbols.begin(), - e = Obj.Symbols.end(); i != e; ++i) { - COFFYAML::Symbol &Sym = *i; - - // If the name is less than 8 bytes, store it in place, otherwise - // store it in the string table. - StringRef Name = Sym.Name; - if (Name.size() <= COFF::NameSize) { - std::copy(Name.begin(), Name.end(), Sym.Header.Name); - } else { - // Add string to the string table and format the index for output. - unsigned Index = getStringIndex(Name); - *reinterpret_cast( - Sym.Header.Name + 4) = Index; - } - - Sym.Header.Type = Sym.SimpleType; - Sym.Header.Type |= Sym.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT; - } - return true; - } - - bool parse() { - if (!parseSections()) - return false; - if (!parseSymbols()) - return false; - return true; - } - - unsigned getStringIndex(StringRef Str) { - StringMap::iterator i = StringTableMap.find(Str); - if (i == StringTableMap.end()) { - unsigned Index = StringTable.size(); - StringTable.append(Str.begin(), Str.end()); - StringTable.push_back(0); - StringTableMap[Str] = Index; - return Index; - } - return i->second; - } - - COFFYAML::Object &Obj; - - StringMap StringTableMap; - std::string StringTable; -}; - -// Take a CP and assign addresses and sizes to everything. Returns false if the -// layout is not valid to do. -static bool layoutCOFF(COFFParser &CP) { - uint32_t SectionTableStart = 0; - uint32_t SectionTableSize = 0; - - // The section table starts immediately after the header, including the - // optional header. - SectionTableStart = sizeof(COFF::header) + CP.Obj.Header.SizeOfOptionalHeader; - SectionTableSize = sizeof(COFF::section) * CP.Obj.Sections.size(); - - uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize; - - // Assign each section data address consecutively. - for (std::vector::iterator i = CP.Obj.Sections.begin(), - e = CP.Obj.Sections.end(); - i != e; ++i) { - StringRef SecData = i->SectionData.getHex(); - if (!SecData.empty()) { - i->Header.SizeOfRawData = SecData.size()/2; - i->Header.PointerToRawData = CurrentSectionDataOffset; - CurrentSectionDataOffset += i->Header.SizeOfRawData; - if (!i->Relocations.empty()) { - i->Header.PointerToRelocations = CurrentSectionDataOffset; - i->Header.NumberOfRelocations = i->Relocations.size(); - CurrentSectionDataOffset += i->Header.NumberOfRelocations * - COFF::RelocationSize; - } - // TODO: Handle alignment. - } else { - i->Header.SizeOfRawData = 0; - i->Header.PointerToRawData = 0; - } - } - - uint32_t SymbolTableStart = CurrentSectionDataOffset; - - // Calculate number of symbols. - uint32_t NumberOfSymbols = 0; - for (std::vector::iterator i = CP.Obj.Symbols.begin(), - e = CP.Obj.Symbols.end(); - i != e; ++i) { - unsigned AuxBytes = i->AuxiliaryData.getHex().size() / 2; - if (AuxBytes % COFF::SymbolSize != 0) { - errs() << "AuxiliaryData size not a multiple of symbol size!\n"; - return false; - } - i->Header.NumberOfAuxSymbols = AuxBytes / COFF::SymbolSize; - NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols; - } - - // Store all the allocated start addresses in the header. - CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size(); - CP.Obj.Header.NumberOfSymbols = NumberOfSymbols; - CP.Obj.Header.PointerToSymbolTable = SymbolTableStart; - - *reinterpret_cast(&CP.StringTable[0]) - = CP.StringTable.size(); - - return true; -} - -template -struct binary_le_impl { - value_type Value; - binary_le_impl(value_type V) : Value(V) {} -}; - -template -raw_ostream &operator <<( raw_ostream &OS - , const binary_le_impl &BLE) { - char Buffer[sizeof(BLE.Value)]; - support::endian::write( - Buffer, BLE.Value); - OS.write(Buffer, sizeof(BLE.Value)); - return OS; -} - -template -binary_le_impl binary_le(value_type V) { - return binary_le_impl(V); -} - -static bool writeHexData(StringRef Data, raw_ostream &OS) { - unsigned Size = Data.size(); - if (Size % 2) - return false; - - for (unsigned I = 0; I != Size; I += 2) { - uint8_t Byte; - if (Data.substr(I, 2).getAsInteger(16, Byte)) - return false; - OS.write(Byte); - } - - return true; -} - -bool writeCOFF(COFFParser &CP, raw_ostream &OS) { - OS << binary_le(CP.Obj.Header.Machine) - << binary_le(CP.Obj.Header.NumberOfSections) - << binary_le(CP.Obj.Header.TimeDateStamp) - << binary_le(CP.Obj.Header.PointerToSymbolTable) - << binary_le(CP.Obj.Header.NumberOfSymbols) - << binary_le(CP.Obj.Header.SizeOfOptionalHeader) - << binary_le(CP.Obj.Header.Characteristics); - - // Output section table. - for (std::vector::iterator i = CP.Obj.Sections.begin(), - e = CP.Obj.Sections.end(); - i != e; ++i) { - OS.write(i->Header.Name, COFF::NameSize); - OS << binary_le(i->Header.VirtualSize) - << binary_le(i->Header.VirtualAddress) - << binary_le(i->Header.SizeOfRawData) - << binary_le(i->Header.PointerToRawData) - << binary_le(i->Header.PointerToRelocations) - << binary_le(i->Header.PointerToLineNumbers) - << binary_le(i->Header.NumberOfRelocations) - << binary_le(i->Header.NumberOfLineNumbers) - << binary_le(i->Header.Characteristics); - } - - // Output section data. - for (std::vector::iterator i = CP.Obj.Sections.begin(), - e = CP.Obj.Sections.end(); - i != e; ++i) { - StringRef SecData = i->SectionData.getHex(); - if (!SecData.empty()) { - if (!writeHexData(SecData, OS)) { - errs() << "SectionData must be a collection of pairs of hex bytes"; - return false; - } - } - for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) { - const COFF::relocation &R = i->Relocations[I2]; - OS << binary_le(R.VirtualAddress) - << binary_le(R.SymbolTableIndex) - << binary_le(R.Type); - } - } - - // Output symbol table. - - for (std::vector::const_iterator i = CP.Obj.Symbols.begin(), - e = CP.Obj.Symbols.end(); - i != e; ++i) { - OS.write(i->Header.Name, COFF::NameSize); - OS << binary_le(i->Header.Value) - << binary_le(i->Header.SectionNumber) - << binary_le(i->Header.Type) - << binary_le(i->Header.StorageClass) - << binary_le(i->Header.NumberOfAuxSymbols); - StringRef Data = i->AuxiliaryData.getHex(); - if (!Data.empty()) { - if (!writeHexData(Data, OS)) { - errs() << "AuxiliaryData must be a collection of pairs of hex bytes"; - return false; - } - } - } - - // Output string table. - OS.write(&CP.StringTable[0], CP.StringTable.size()); - return true; -} - -static int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { - yaml::Input YIn(Buf->getBuffer()); - COFFYAML::Object Doc; - YIn >> Doc; - if (YIn.error()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } - - COFFParser CP(Doc); - if (!CP.parse()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } - - if (!layoutCOFF(CP)) { - errs() << "yaml2obj: Failed to layout COFF file!\n"; - return 1; - } - if (!writeCOFF(CP, Out)) { - errs() << "yaml2obj: Failed to write COFF file!\n"; - return 1; - } - return 0; -} int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h new file mode 100644 index 00000000000..7197410b268 --- /dev/null +++ b/tools/yaml2obj/yaml2obj.h @@ -0,0 +1,21 @@ +//===--- yaml2obj.h - -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief Common declarations for yaml2obj +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_YAML2OBJ_H +#define LLVM_TOOLS_YAML2OBJ_H + +namespace llvm { + class raw_ostream; + class MemoryBuffer; +} +int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf); + +#endif