1//===- yaml2coff - Convert YAML to a COFF object file ---------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// \brief The COFF component of yaml2obj. 12/// 13//===----------------------------------------------------------------------===// 14 15#include "yaml2obj.h" 16#include "llvm/ADT/SmallString.h" 17#include "llvm/ADT/StringExtras.h" 18#include "llvm/ADT/StringMap.h" 19#include "llvm/ADT/StringSwitch.h" 20#include "llvm/Object/COFFYAML.h" 21#include "llvm/Support/Endian.h" 22#include "llvm/Support/MemoryBuffer.h" 23#include "llvm/Support/SourceMgr.h" 24#include "llvm/Support/raw_ostream.h" 25#include <vector> 26 27using namespace llvm; 28 29/// This parses a yaml stream that represents a COFF object file. 30/// See docs/yaml2obj for the yaml scheema. 31struct COFFParser { 32 COFFParser(COFFYAML::Object &Obj) : Obj(Obj) { 33 // A COFF string table always starts with a 4 byte size field. Offsets into 34 // it include this size, so allocate it now. 35 StringTable.append(4, 0); 36 } 37 38 bool parseSections() { 39 for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(), 40 e = Obj.Sections.end(); i != e; ++i) { 41 COFFYAML::Section &Sec = *i; 42 43 // If the name is less than 8 bytes, store it in place, otherwise 44 // store it in the string table. 45 StringRef Name = Sec.Name; 46 47 if (Name.size() <= COFF::NameSize) { 48 std::copy(Name.begin(), Name.end(), Sec.Header.Name); 49 } else { 50 // Add string to the string table and format the index for output. 51 unsigned Index = getStringIndex(Name); 52 std::string str = utostr(Index); 53 if (str.size() > 7) { 54 errs() << "String table got too large"; 55 return false; 56 } 57 Sec.Header.Name[0] = '/'; 58 std::copy(str.begin(), str.end(), Sec.Header.Name + 1); 59 } 60 61 Sec.Header.Characteristics |= (Log2_32(Sec.Alignment) + 1) << 20; 62 } 63 return true; 64 } 65 66 bool parseSymbols() { 67 for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(), 68 e = Obj.Symbols.end(); i != e; ++i) { 69 COFFYAML::Symbol &Sym = *i; 70 71 // If the name is less than 8 bytes, store it in place, otherwise 72 // store it in the string table. 73 StringRef Name = Sym.Name; 74 if (Name.size() <= COFF::NameSize) { 75 std::copy(Name.begin(), Name.end(), Sym.Header.Name); 76 } else { 77 // Add string to the string table and format the index for output. 78 unsigned Index = getStringIndex(Name); 79 *reinterpret_cast<support::aligned_ulittle32_t*>( 80 Sym.Header.Name + 4) = Index; 81 } 82 83 Sym.Header.Type = Sym.SimpleType; 84 Sym.Header.Type |= Sym.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT; 85 } 86 return true; 87 } 88 89 bool parse() { 90 if (!parseSections()) 91 return false; 92 if (!parseSymbols()) 93 return false; 94 return true; 95 } 96 97 unsigned getStringIndex(StringRef Str) { 98 StringMap<unsigned>::iterator i = StringTableMap.find(Str); 99 if (i == StringTableMap.end()) { 100 unsigned Index = StringTable.size(); 101 StringTable.append(Str.begin(), Str.end()); 102 StringTable.push_back(0); 103 StringTableMap[Str] = Index; 104 return Index; 105 } 106 return i->second; 107 } 108 109 COFFYAML::Object &Obj; 110 111 StringMap<unsigned> StringTableMap; 112 std::string StringTable; 113}; 114 115// Take a CP and assign addresses and sizes to everything. Returns false if the 116// layout is not valid to do. 117static bool layoutCOFF(COFFParser &CP) { 118 uint32_t SectionTableStart = 0; 119 uint32_t SectionTableSize = 0; 120 121 // The section table starts immediately after the header, including the 122 // optional header. 123 SectionTableStart = sizeof(COFF::header) + CP.Obj.Header.SizeOfOptionalHeader; 124 SectionTableSize = sizeof(COFF::section) * CP.Obj.Sections.size(); 125 126 uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize; 127 128 // Assign each section data address consecutively. 129 for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), 130 e = CP.Obj.Sections.end(); 131 i != e; ++i) { 132 if (i->SectionData.binary_size() > 0) { 133 i->Header.SizeOfRawData = i->SectionData.binary_size(); 134 i->Header.PointerToRawData = CurrentSectionDataOffset; 135 CurrentSectionDataOffset += i->Header.SizeOfRawData; 136 if (!i->Relocations.empty()) { 137 i->Header.PointerToRelocations = CurrentSectionDataOffset; 138 i->Header.NumberOfRelocations = i->Relocations.size(); 139 CurrentSectionDataOffset += i->Header.NumberOfRelocations * 140 COFF::RelocationSize; 141 } 142 // TODO: Handle alignment. 143 } else { 144 i->Header.SizeOfRawData = 0; 145 i->Header.PointerToRawData = 0; 146 } 147 } 148 149 uint32_t SymbolTableStart = CurrentSectionDataOffset; 150 151 // Calculate number of symbols. 152 uint32_t NumberOfSymbols = 0; 153 for (std::vector<COFFYAML::Symbol>::iterator i = CP.Obj.Symbols.begin(), 154 e = CP.Obj.Symbols.end(); 155 i != e; ++i) { 156 unsigned AuxBytes = i->AuxiliaryData.binary_size(); 157 if (AuxBytes % COFF::SymbolSize != 0) { 158 errs() << "AuxiliaryData size not a multiple of symbol size!\n"; 159 return false; 160 } 161 i->Header.NumberOfAuxSymbols = AuxBytes / COFF::SymbolSize; 162 NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols; 163 } 164 165 // Store all the allocated start addresses in the header. 166 CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size(); 167 CP.Obj.Header.NumberOfSymbols = NumberOfSymbols; 168 CP.Obj.Header.PointerToSymbolTable = SymbolTableStart; 169 170 *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0]) 171 = CP.StringTable.size(); 172 173 return true; 174} 175 176template <typename value_type> 177struct binary_le_impl { 178 value_type Value; 179 binary_le_impl(value_type V) : Value(V) {} 180}; 181 182template <typename value_type> 183raw_ostream &operator <<( raw_ostream &OS 184 , const binary_le_impl<value_type> &BLE) { 185 char Buffer[sizeof(BLE.Value)]; 186 support::endian::write<value_type, support::little, support::unaligned>( 187 Buffer, BLE.Value); 188 OS.write(Buffer, sizeof(BLE.Value)); 189 return OS; 190} 191 192template <typename value_type> 193binary_le_impl<value_type> binary_le(value_type V) { 194 return binary_le_impl<value_type>(V); 195} 196 197bool writeCOFF(COFFParser &CP, raw_ostream &OS) { 198 OS << binary_le(CP.Obj.Header.Machine) 199 << binary_le(CP.Obj.Header.NumberOfSections) 200 << binary_le(CP.Obj.Header.TimeDateStamp) 201 << binary_le(CP.Obj.Header.PointerToSymbolTable) 202 << binary_le(CP.Obj.Header.NumberOfSymbols) 203 << binary_le(CP.Obj.Header.SizeOfOptionalHeader) 204 << binary_le(CP.Obj.Header.Characteristics); 205 206 // Output section table. 207 for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), 208 e = CP.Obj.Sections.end(); 209 i != e; ++i) { 210 OS.write(i->Header.Name, COFF::NameSize); 211 OS << binary_le(i->Header.VirtualSize) 212 << binary_le(i->Header.VirtualAddress) 213 << binary_le(i->Header.SizeOfRawData) 214 << binary_le(i->Header.PointerToRawData) 215 << binary_le(i->Header.PointerToRelocations) 216 << binary_le(i->Header.PointerToLineNumbers) 217 << binary_le(i->Header.NumberOfRelocations) 218 << binary_le(i->Header.NumberOfLineNumbers) 219 << binary_le(i->Header.Characteristics); 220 } 221 222 unsigned CurSymbol = 0; 223 StringMap<unsigned> SymbolTableIndexMap; 224 for (std::vector<COFFYAML::Symbol>::iterator I = CP.Obj.Symbols.begin(), 225 E = CP.Obj.Symbols.end(); 226 I != E; ++I) { 227 SymbolTableIndexMap[I->Name] = CurSymbol; 228 CurSymbol += 1 + I->Header.NumberOfAuxSymbols; 229 } 230 231 // Output section data. 232 for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), 233 e = CP.Obj.Sections.end(); 234 i != e; ++i) { 235 i->SectionData.writeAsBinary(OS); 236 for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) { 237 const COFFYAML::Relocation &R = i->Relocations[I2]; 238 uint32_t SymbolTableIndex = SymbolTableIndexMap[R.SymbolName]; 239 OS << binary_le(R.VirtualAddress) 240 << binary_le(SymbolTableIndex) 241 << binary_le(R.Type); 242 } 243 } 244 245 // Output symbol table. 246 247 for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(), 248 e = CP.Obj.Symbols.end(); 249 i != e; ++i) { 250 OS.write(i->Header.Name, COFF::NameSize); 251 OS << binary_le(i->Header.Value) 252 << binary_le(i->Header.SectionNumber) 253 << binary_le(i->Header.Type) 254 << binary_le(i->Header.StorageClass) 255 << binary_le(i->Header.NumberOfAuxSymbols); 256 i->AuxiliaryData.writeAsBinary(OS); 257 } 258 259 // Output string table. 260 OS.write(&CP.StringTable[0], CP.StringTable.size()); 261 return true; 262} 263 264int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { 265 yaml::Input YIn(Buf->getBuffer()); 266 COFFYAML::Object Doc; 267 YIn >> Doc; 268 if (YIn.error()) { 269 errs() << "yaml2obj: Failed to parse YAML file!\n"; 270 return 1; 271 } 272 273 COFFParser CP(Doc); 274 if (!CP.parse()) { 275 errs() << "yaml2obj: Failed to parse YAML file!\n"; 276 return 1; 277 } 278 279 if (!layoutCOFF(CP)) { 280 errs() << "yaml2obj: Failed to layout COFF file!\n"; 281 return 1; 282 } 283 if (!writeCOFF(CP, Out)) { 284 errs() << "yaml2obj: Failed to write COFF file!\n"; 285 return 1; 286 } 287 return 0; 288} 289