1 //===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// The xcoff component of yaml2obj. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/BinaryFormat/XCOFF.h" 16 #include "llvm/MC/StringTableBuilder.h" 17 #include "llvm/Object/XCOFFObjectFile.h" 18 #include "llvm/ObjectYAML/ObjectYAML.h" 19 #include "llvm/ObjectYAML/yaml2obj.h" 20 #include "llvm/Support/EndianStream.h" 21 #include "llvm/Support/LEB128.h" 22 #include "llvm/Support/MemoryBuffer.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 using namespace llvm; 26 27 namespace { 28 29 constexpr unsigned DefaultSectionAlign = 4; 30 constexpr int16_t MaxSectionIndex = INT16_MAX; 31 constexpr uint32_t MaxRawDataSize = UINT32_MAX; 32 33 class XCOFFWriter { 34 public: 35 XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH) 36 : Obj(Obj), W(OS, support::big), ErrHandler(EH), 37 StrTblBuilder(StringTableBuilder::XCOFF) { 38 Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64; 39 } 40 bool writeXCOFF(); 41 42 private: 43 bool nameShouldBeInStringTable(StringRef SymbolName); 44 bool initFileHeader(uint64_t CurrentOffset); 45 void initAuxFileHeader(); 46 bool initSectionHeader(uint64_t &CurrentOffset); 47 bool initRelocations(uint64_t &CurrentOffset); 48 bool initStringTable(); 49 bool assignAddressesAndIndices(); 50 void writeFileHeader(); 51 void writeAuxFileHeader(); 52 void writeSectionHeader(); 53 bool writeSectionData(); 54 bool writeRelocations(); 55 bool writeSymbols(); 56 void writeStringTable(); 57 58 XCOFFYAML::Object &Obj; 59 bool Is64Bit = false; 60 support::endian::Writer W; 61 yaml::ErrorHandler ErrHandler; 62 StringTableBuilder StrTblBuilder; 63 uint64_t StartOffset; 64 // Map the section name to its corrresponding section index. 65 DenseMap<StringRef, int16_t> SectionIndexMap = { 66 {StringRef("N_DEBUG"), XCOFF::N_DEBUG}, 67 {StringRef("N_ABS"), XCOFF::N_ABS}, 68 {StringRef("N_UNDEF"), XCOFF::N_UNDEF}}; 69 XCOFFYAML::FileHeader InitFileHdr = Obj.Header; 70 XCOFFYAML::AuxiliaryHeader InitAuxFileHdr; 71 std::vector<XCOFFYAML::Section> InitSections = Obj.Sections; 72 }; 73 74 static void writeName(StringRef StrName, support::endian::Writer W) { 75 char Name[XCOFF::NameSize]; 76 memset(Name, 0, XCOFF::NameSize); 77 char SrcName[] = ""; 78 memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size()); 79 ArrayRef<char> NameRef(Name, XCOFF::NameSize); 80 W.write(NameRef); 81 } 82 83 bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { 84 // For XCOFF64: The symbol name is always in the string table. 85 return (SymbolName.size() > XCOFF::NameSize) || Is64Bit; 86 } 87 88 bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { 89 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 90 if (!InitSections[I].Relocations.empty()) { 91 InitSections[I].NumberOfRelocations = InitSections[I].Relocations.size(); 92 InitSections[I].FileOffsetToRelocations = CurrentOffset; 93 uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64 94 : XCOFF::RelocationSerializationSize32; 95 CurrentOffset += InitSections[I].NumberOfRelocations * RelSize; 96 if (CurrentOffset > MaxRawDataSize) { 97 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 98 "exceeded when writing relocation data"); 99 return false; 100 } 101 } 102 } 103 return true; 104 } 105 106 bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) { 107 uint64_t CurrentSecAddr = 0; 108 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 109 if (CurrentOffset > MaxRawDataSize) { 110 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 111 "exceeded when writing section data"); 112 return false; 113 } 114 115 // Assign indices for sections. 116 if (InitSections[I].SectionName.size() && 117 !SectionIndexMap[InitSections[I].SectionName]) { 118 // The section index starts from 1. 119 SectionIndexMap[InitSections[I].SectionName] = I + 1; 120 if ((I + 1) > MaxSectionIndex) { 121 ErrHandler("exceeded the maximum permitted section index of " + 122 Twine(MaxSectionIndex)); 123 return false; 124 } 125 } 126 127 // Calculate the physical/virtual address. This field should contain 0 for 128 // all sections except the text, data and bss sections. 129 if (InitSections[I].Flags != XCOFF::STYP_TEXT && 130 InitSections[I].Flags != XCOFF::STYP_DATA && 131 InitSections[I].Flags != XCOFF::STYP_BSS) 132 InitSections[I].Address = 0; 133 else 134 InitSections[I].Address = CurrentSecAddr; 135 136 // Calculate the FileOffsetToData and data size for sections. 137 if (InitSections[I].SectionData.binary_size()) { 138 InitSections[I].FileOffsetToData = CurrentOffset; 139 CurrentOffset += InitSections[I].SectionData.binary_size(); 140 // Ensure the offset is aligned to DefaultSectionAlign. 141 CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign); 142 InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData; 143 CurrentSecAddr += InitSections[I].Size; 144 } 145 } 146 return initRelocations(CurrentOffset); 147 } 148 149 bool XCOFFWriter::initStringTable() { 150 if (Obj.StrTbl.RawContent) { 151 size_t RawSize = Obj.StrTbl.RawContent->binary_size(); 152 if (Obj.StrTbl.Strings || Obj.StrTbl.Length) { 153 ErrHandler( 154 "can't specify Strings or Length when RawContent is specified"); 155 return false; 156 } 157 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) { 158 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 159 ") is less than the RawContent data size (" + Twine(RawSize) + 160 ")"); 161 return false; 162 } 163 return true; 164 } 165 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) { 166 ErrHandler("ContentSize shouldn't be less than 4 without RawContent"); 167 return false; 168 } 169 170 // Build the string table. 171 StrTblBuilder.clear(); 172 173 if (Obj.StrTbl.Strings) { 174 // All specified strings should be added to the string table. 175 for (StringRef StringEnt : *Obj.StrTbl.Strings) 176 StrTblBuilder.add(StringEnt); 177 178 size_t StrTblIdx = 0; 179 size_t NumOfStrings = Obj.StrTbl.Strings->size(); 180 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 181 if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 182 if (StrTblIdx < NumOfStrings) { 183 // Overwrite the symbol name with the specified string. 184 YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx]; 185 ++StrTblIdx; 186 } else 187 // Names that are not overwritten are still stored in the string 188 // table. 189 StrTblBuilder.add(YamlSym.SymbolName); 190 } 191 } 192 } else { 193 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 194 if (nameShouldBeInStringTable(YamlSym.SymbolName)) 195 StrTblBuilder.add(YamlSym.SymbolName); 196 } 197 } 198 199 StrTblBuilder.finalize(); 200 201 size_t StrTblSize = StrTblBuilder.getSize(); 202 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) { 203 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 204 ") is less than the size of the data that would otherwise be " 205 "written (" + 206 Twine(StrTblSize) + ")"); 207 return false; 208 } 209 210 return true; 211 } 212 213 bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { 214 // The default format of the object file is XCOFF32. 215 InitFileHdr.Magic = XCOFF::XCOFF32; 216 InitFileHdr.NumberOfSections = Obj.Sections.size(); 217 InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); 218 219 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) 220 // Add the number of auxiliary symbols to the total number. 221 InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries; 222 223 // Calculate SymbolTableOffset for the file header. 224 if (InitFileHdr.NumberOfSymTableEntries) { 225 InitFileHdr.SymbolTableOffset = CurrentOffset; 226 CurrentOffset += 227 InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; 228 if (CurrentOffset > MaxRawDataSize) { 229 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 230 "exceeded when writing symbols"); 231 return false; 232 } 233 } 234 // TODO: Calculate FileOffsetToLineNumbers when line number supported. 235 return true; 236 } 237 238 void XCOFFWriter::initAuxFileHeader() { 239 InitAuxFileHdr = *Obj.AuxHeader; 240 // In general, an object file might contain multiple sections of a given type, 241 // but in a loadable module, there must be exactly one .text, .data, .bss, and 242 // .loader section. A loadable object might also have one .tdata section and 243 // one .tbss section. 244 // Set these section-related values if not set explicitly. We assume that the 245 // input YAML matches the format of the loadable object, but if multiple input 246 // sections still have the same type, the first section with that type 247 // prevails. 248 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 249 switch (InitSections[I].Flags) { 250 case XCOFF::STYP_TEXT: 251 if (!InitAuxFileHdr.TextSize) 252 InitAuxFileHdr.TextSize = InitSections[I].Size; 253 if (!InitAuxFileHdr.TextStartAddr) 254 InitAuxFileHdr.TextStartAddr = InitSections[I].Address; 255 if (!InitAuxFileHdr.SecNumOfText) 256 InitAuxFileHdr.SecNumOfText = I + 1; 257 break; 258 case XCOFF::STYP_DATA: 259 if (!InitAuxFileHdr.InitDataSize) 260 InitAuxFileHdr.InitDataSize = InitSections[I].Size; 261 if (!InitAuxFileHdr.DataStartAddr) 262 InitAuxFileHdr.DataStartAddr = InitSections[I].Address; 263 if (!InitAuxFileHdr.SecNumOfData) 264 InitAuxFileHdr.SecNumOfData = I + 1; 265 break; 266 case XCOFF::STYP_BSS: 267 if (!InitAuxFileHdr.BssDataSize) 268 InitAuxFileHdr.BssDataSize = InitSections[I].Size; 269 if (!InitAuxFileHdr.SecNumOfBSS) 270 InitAuxFileHdr.SecNumOfBSS = I + 1; 271 break; 272 case XCOFF::STYP_TDATA: 273 if (!InitAuxFileHdr.SecNumOfTData) 274 InitAuxFileHdr.SecNumOfTData = I + 1; 275 break; 276 case XCOFF::STYP_TBSS: 277 if (!InitAuxFileHdr.SecNumOfTBSS) 278 InitAuxFileHdr.SecNumOfTBSS = I + 1; 279 break; 280 case XCOFF::STYP_LOADER: 281 if (!InitAuxFileHdr.SecNumOfLoader) 282 InitAuxFileHdr.SecNumOfLoader = I + 1; 283 break; 284 default: 285 break; 286 } 287 } 288 } 289 290 bool XCOFFWriter::assignAddressesAndIndices() { 291 uint64_t FileHdrSize = 292 Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; 293 uint64_t AuxFileHdrSize = 0; 294 if (Obj.AuxHeader) 295 AuxFileHdrSize = Obj.Header.AuxHeaderSize 296 ? Obj.Header.AuxHeaderSize 297 : (Is64Bit ? XCOFF::AuxFileHeaderSize64 298 : XCOFF::AuxFileHeaderSize32); 299 uint64_t SecHdrSize = 300 Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; 301 uint64_t CurrentOffset = 302 FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize; 303 304 // Calculate section header info. 305 if (!initSectionHeader(CurrentOffset)) 306 return false; 307 InitFileHdr.AuxHeaderSize = AuxFileHdrSize; 308 309 // Calculate file header info. 310 if (!initFileHeader(CurrentOffset)) 311 return false; 312 313 // Initialize the auxiliary file header. 314 if (Obj.AuxHeader) 315 initAuxFileHeader(); 316 317 // Initialize the string table. 318 return initStringTable(); 319 } 320 321 void XCOFFWriter::writeFileHeader() { 322 W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); 323 W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections 324 : InitFileHdr.NumberOfSections); 325 W.write<int32_t>(Obj.Header.TimeStamp); 326 if (Is64Bit) { 327 W.write<uint64_t>(Obj.Header.SymbolTableOffset 328 ? Obj.Header.SymbolTableOffset 329 : InitFileHdr.SymbolTableOffset); 330 W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 331 W.write<uint16_t>(Obj.Header.Flags); 332 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 333 ? Obj.Header.NumberOfSymTableEntries 334 : InitFileHdr.NumberOfSymTableEntries); 335 } else { 336 W.write<uint32_t>(Obj.Header.SymbolTableOffset 337 ? Obj.Header.SymbolTableOffset 338 : InitFileHdr.SymbolTableOffset); 339 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 340 ? Obj.Header.NumberOfSymTableEntries 341 : InitFileHdr.NumberOfSymTableEntries); 342 W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 343 W.write<uint16_t>(Obj.Header.Flags); 344 } 345 } 346 347 void XCOFFWriter::writeAuxFileHeader() { 348 W.write<uint16_t>(InitAuxFileHdr.Magic.getValueOr(yaml::Hex16(1))); 349 W.write<uint16_t>(InitAuxFileHdr.Version.getValueOr(yaml::Hex16(1))); 350 if (Is64Bit) { 351 W.OS.write_zeros(4); // Reserved for debugger. 352 W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0))); 353 W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0))); 354 W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0))); 355 } else { 356 W.write<uint32_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0))); 357 W.write<uint32_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0))); 358 W.write<uint32_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0))); 359 W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0))); 360 W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0))); 361 W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0))); 362 W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0))); 363 } 364 W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.getValueOr(0)); 365 W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.getValueOr(0)); 366 W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.getValueOr(0)); 367 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.getValueOr(0)); 368 W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.getValueOr(0)); 369 W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.getValueOr(0)); 370 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.getValueOr(yaml::Hex16(0))); 371 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.getValueOr(yaml::Hex16(0))); 372 W.write<uint16_t>(InitAuxFileHdr.ModuleType.getValueOr(yaml::Hex16(0))); 373 W.write<uint8_t>(InitAuxFileHdr.CpuFlag.getValueOr(yaml::Hex8(0))); 374 W.write<uint8_t>(0); // Reserved for CPU type. 375 if (Is64Bit) { 376 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0))); 377 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0))); 378 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0))); 379 W.write<uint8_t>( 380 InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0x80))); 381 W.write<uint64_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0))); 382 W.write<uint64_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0))); 383 W.write<uint64_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0))); 384 W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0))); 385 W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0))); 386 W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0))); 387 } else { 388 W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0))); 389 W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0))); 390 W.OS.write_zeros(4); // Reserved for debugger. 391 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0))); 392 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0))); 393 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0))); 394 W.write<uint8_t>( 395 InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0))); 396 } 397 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.getValueOr(0)); 398 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.getValueOr(0)); 399 if (Is64Bit) { 400 W.write<uint16_t>(InitAuxFileHdr.Flag.getValueOr(yaml::Hex16(XCOFF::SHR_SYMTAB))); 401 if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64) 402 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64); 403 } else if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) { 404 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32); 405 } 406 } 407 408 void XCOFFWriter::writeSectionHeader() { 409 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 410 XCOFFYAML::Section YamlSec = Obj.Sections[I]; 411 XCOFFYAML::Section DerivedSec = InitSections[I]; 412 writeName(YamlSec.SectionName, W); 413 // Virtual address is the same as physical address. 414 uint64_t SectionAddress = 415 YamlSec.Address ? YamlSec.Address : DerivedSec.Address; 416 if (Is64Bit) { 417 W.write<uint64_t>(SectionAddress); // Physical address 418 W.write<uint64_t>(SectionAddress); // Virtual address 419 W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); 420 W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData 421 : DerivedSec.FileOffsetToData); 422 W.write<uint64_t>(YamlSec.FileOffsetToRelocations 423 ? YamlSec.FileOffsetToRelocations 424 : DerivedSec.FileOffsetToRelocations); 425 W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers); 426 W.write<uint32_t>(YamlSec.NumberOfRelocations 427 ? YamlSec.NumberOfRelocations 428 : DerivedSec.NumberOfRelocations); 429 W.write<uint32_t>(YamlSec.NumberOfLineNumbers); 430 W.write<int32_t>(YamlSec.Flags); 431 W.OS.write_zeros(4); 432 } else { 433 W.write<uint32_t>(SectionAddress); // Physical address 434 W.write<uint32_t>(SectionAddress); // Virtual address 435 W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); 436 W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData 437 : DerivedSec.FileOffsetToData); 438 W.write<uint32_t>(YamlSec.FileOffsetToRelocations 439 ? YamlSec.FileOffsetToRelocations 440 : DerivedSec.FileOffsetToRelocations); 441 W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers); 442 W.write<uint16_t>(YamlSec.NumberOfRelocations 443 ? YamlSec.NumberOfRelocations 444 : DerivedSec.NumberOfRelocations); 445 W.write<uint16_t>(YamlSec.NumberOfLineNumbers); 446 W.write<int32_t>(YamlSec.Flags); 447 } 448 } 449 } 450 451 bool XCOFFWriter::writeSectionData() { 452 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 453 XCOFFYAML::Section YamlSec = Obj.Sections[I]; 454 if (YamlSec.SectionData.binary_size()) { 455 // Fill the padding size with zeros. 456 int64_t PaddingSize = 457 InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset); 458 if (PaddingSize < 0) { 459 ErrHandler("redundant data was written before section data"); 460 return false; 461 } 462 W.OS.write_zeros(PaddingSize); 463 YamlSec.SectionData.writeAsBinary(W.OS); 464 } 465 } 466 return true; 467 } 468 469 bool XCOFFWriter::writeRelocations() { 470 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 471 XCOFFYAML::Section YamlSec = Obj.Sections[I]; 472 if (!YamlSec.Relocations.empty()) { 473 int64_t PaddingSize = 474 InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset); 475 if (PaddingSize < 0) { 476 ErrHandler("redundant data was written before relocations"); 477 return false; 478 } 479 W.OS.write_zeros(PaddingSize); 480 for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { 481 if (Is64Bit) 482 W.write<uint64_t>(YamlRel.VirtualAddress); 483 else 484 W.write<uint32_t>(YamlRel.VirtualAddress); 485 W.write<uint32_t>(YamlRel.SymbolIndex); 486 W.write<uint8_t>(YamlRel.Info); 487 W.write<uint8_t>(YamlRel.Type); 488 } 489 } 490 } 491 return true; 492 } 493 494 bool XCOFFWriter::writeSymbols() { 495 int64_t PaddingSize = 496 (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset); 497 if (PaddingSize < 0) { 498 ErrHandler("redundant data was written before symbols"); 499 return false; 500 } 501 W.OS.write_zeros(PaddingSize); 502 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 503 if (Is64Bit) { 504 W.write<uint64_t>(YamlSym.Value); 505 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 506 } else { 507 if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 508 // For XCOFF32: A value of 0 indicates that the symbol name is in the 509 // string table. 510 W.write<int32_t>(0); 511 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 512 } else { 513 writeName(YamlSym.SymbolName, W); 514 } 515 W.write<uint32_t>(YamlSym.Value); 516 } 517 if (YamlSym.SectionName) { 518 if (!SectionIndexMap.count(*YamlSym.SectionName)) { 519 ErrHandler("the SectionName " + *YamlSym.SectionName + 520 " specified in the symbol does not exist"); 521 return false; 522 } 523 if (YamlSym.SectionIndex && 524 SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) { 525 ErrHandler("the SectionName " + *YamlSym.SectionName + 526 " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) + 527 ") refer to different sections"); 528 return false; 529 } 530 W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]); 531 } else { 532 W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0); 533 } 534 W.write<uint16_t>(YamlSym.Type); 535 W.write<uint8_t>(YamlSym.StorageClass); 536 W.write<uint8_t>(YamlSym.NumberOfAuxEntries); 537 538 // Now output the auxiliary entry. 539 for (uint8_t I = 0, E = YamlSym.NumberOfAuxEntries; I < E; ++I) { 540 // TODO: Auxiliary entry is not supported yet. 541 // The auxiliary entries for a symbol follow its symbol table entry. The 542 // length of each auxiliary entry is the same as a symbol table entry (18 543 // bytes). The format and quantity of auxiliary entries depend on the 544 // storage class (n_sclass) and type (n_type) of the symbol table entry. 545 W.OS.write_zeros(XCOFF::SymbolTableEntrySize); 546 } 547 } 548 return true; 549 } 550 551 void XCOFFWriter::writeStringTable() { 552 if (Obj.StrTbl.RawContent) { 553 Obj.StrTbl.RawContent->writeAsBinary(W.OS); 554 if (Obj.StrTbl.ContentSize) { 555 assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() && 556 "Specified ContentSize is less than the RawContent size."); 557 W.OS.write_zeros(*Obj.StrTbl.ContentSize - 558 Obj.StrTbl.RawContent->binary_size()); 559 } 560 return; 561 } 562 563 size_t StrTblBuilderSize = StrTblBuilder.getSize(); 564 // If neither Length nor ContentSize is specified, write the StrTblBuilder 565 // directly, which contains the auto-generated Length value. 566 if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) { 567 if (StrTblBuilderSize <= 4) 568 return; 569 StrTblBuilder.write(W.OS); 570 return; 571 } 572 573 // Serialize the string table's content to a temporary buffer. 574 std::unique_ptr<WritableMemoryBuffer> Buf = 575 WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize); 576 uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); 577 StrTblBuilder.write(Ptr); 578 // Replace the first 4 bytes, which contain the auto-generated Length value, 579 // with the specified value. 580 memset(Ptr, 0, 4); 581 support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length 582 : *Obj.StrTbl.ContentSize); 583 // Copy the buffer content to the actual output stream. 584 W.OS.write(Buf->getBufferStart(), Buf->getBufferSize()); 585 // Add zeros as padding after strings. 586 if (Obj.StrTbl.ContentSize) { 587 assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize && 588 "Specified ContentSize is less than the StringTableBuilder size."); 589 W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); 590 } 591 } 592 593 bool XCOFFWriter::writeXCOFF() { 594 if (!assignAddressesAndIndices()) 595 return false; 596 StartOffset = W.OS.tell(); 597 writeFileHeader(); 598 if (Obj.AuxHeader) 599 writeAuxFileHeader(); 600 if (!Obj.Sections.empty()) { 601 writeSectionHeader(); 602 if (!writeSectionData()) 603 return false; 604 if (!writeRelocations()) 605 return false; 606 } 607 if (!Obj.Symbols.empty() && !writeSymbols()) 608 return false; 609 writeStringTable(); 610 return true; 611 } 612 613 } // end anonymous namespace 614 615 namespace llvm { 616 namespace yaml { 617 618 bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { 619 XCOFFWriter Writer(Doc, Out, EH); 620 return Writer.writeXCOFF(); 621 } 622 623 } // namespace yaml 624 } // namespace llvm 625