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/MemoryBuffer.h" 22 #include "llvm/Support/raw_ostream.h" 23 24 using namespace llvm; 25 using namespace llvm::object; 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, llvm::endianness::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 void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset, 44 const Twine &fieldName); 45 bool nameShouldBeInStringTable(StringRef SymbolName); 46 bool initFileHeader(uint64_t CurrentOffset); 47 void initAuxFileHeader(); 48 bool initSectionHeaders(uint64_t &CurrentOffset); 49 bool initRelocations(uint64_t &CurrentOffset); 50 bool initStringTable(); 51 bool assignAddressesAndIndices(); 52 53 void writeFileHeader(); 54 void writeAuxFileHeader(); 55 void writeSectionHeaders(); 56 bool writeSectionData(); 57 bool writeRelocations(); 58 bool writeSymbols(); 59 void writeStringTable(); 60 61 bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym); 62 bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym); 63 bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym); 64 bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym); 65 bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym); 66 bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym); 67 bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym); 68 bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym); 69 70 XCOFFYAML::Object &Obj; 71 bool Is64Bit = false; 72 support::endian::Writer W; 73 yaml::ErrorHandler ErrHandler; 74 StringTableBuilder StrTblBuilder; 75 uint64_t StartOffset = 0u; 76 // Map the section name to its corrresponding section index. 77 DenseMap<StringRef, int16_t> SectionIndexMap = { 78 {StringRef("N_DEBUG"), XCOFF::N_DEBUG}, 79 {StringRef("N_ABS"), XCOFF::N_ABS}, 80 {StringRef("N_UNDEF"), XCOFF::N_UNDEF}}; 81 XCOFFYAML::FileHeader InitFileHdr = Obj.Header; 82 XCOFFYAML::AuxiliaryHeader InitAuxFileHdr; 83 std::vector<XCOFFYAML::Section> InitSections = Obj.Sections; 84 }; 85 86 static void writeName(StringRef StrName, support::endian::Writer W) { 87 char Name[XCOFF::NameSize]; 88 memset(Name, 0, XCOFF::NameSize); 89 char SrcName[] = ""; 90 memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size()); 91 ArrayRef<char> NameRef(Name, XCOFF::NameSize); 92 W.write(NameRef); 93 } 94 95 void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset, 96 uint64_t specifiedOffset, 97 const Twine &fieldName) { 98 ErrHandler("current file offset (" + Twine(CurrentOffset) + 99 ") is bigger than the specified " + fieldName + " (" + 100 Twine(specifiedOffset) + ") "); 101 } 102 103 bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { 104 // For XCOFF64: The symbol name is always in the string table. 105 return (SymbolName.size() > XCOFF::NameSize) || Is64Bit; 106 } 107 108 bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { 109 for (XCOFFYAML::Section &InitSection : InitSections) { 110 if (!InitSection.Relocations.empty()) { 111 uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64 112 : XCOFF::RelocationSerializationSize32; 113 uint64_t UsedSize = RelSize * InitSection.Relocations.size(); 114 115 // If NumberOfRelocations was specified, we use it, even if it's 116 // not consistent with the number of provided relocations. 117 if (!InitSection.NumberOfRelocations) 118 InitSection.NumberOfRelocations = InitSection.Relocations.size(); 119 120 // If the YAML file specified an offset to relocations, we use it. 121 if (InitSection.FileOffsetToRelocations) { 122 if (CurrentOffset > InitSection.FileOffsetToRelocations) { 123 reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations, 124 "FileOffsetToRelocations for the " + 125 InitSection.SectionName + " section"); 126 return false; 127 } 128 CurrentOffset = InitSection.FileOffsetToRelocations; 129 } else 130 InitSection.FileOffsetToRelocations = CurrentOffset; 131 CurrentOffset += UsedSize; 132 if (CurrentOffset > MaxRawDataSize) { 133 ErrHandler("maximum object size (" + Twine(MaxRawDataSize) + 134 ") exceeded when writing relocation data for section " + 135 Twine(InitSection.SectionName)); 136 return false; 137 } 138 } 139 } 140 return true; 141 } 142 143 bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) { 144 uint64_t CurrentEndDataAddr = 0; 145 uint64_t CurrentEndTDataAddr = 0; 146 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 147 // Assign indices for sections. 148 if (InitSections[I].SectionName.size()) { 149 int16_t &SectionIndex = SectionIndexMap[InitSections[I].SectionName]; 150 if (!SectionIndex) { 151 // The section index starts from 1. 152 SectionIndex = I + 1; 153 if ((I + 1) > MaxSectionIndex) { 154 ErrHandler("exceeded the maximum permitted section index of " + 155 Twine(MaxSectionIndex)); 156 return false; 157 } 158 } 159 } 160 161 if (!InitSections[I].Size) 162 InitSections[I].Size = InitSections[I].SectionData.binary_size(); 163 164 // Section data addresses (physical/virtual) are related to symbol 165 // addresses and alignments. Furthermore, it is possible to specify the 166 // same starting addresses for the .text, .data, and .tdata sections. 167 // Without examining all the symbols and their addreses and alignments, 168 // it is not possible to compute valid section addresses. The only 169 // condition required by XCOFF is that the .bss section immediately 170 // follows the .data section, and the .tbss section immediately follows 171 // the .tdata section. Therefore, we only assign addresses to the .bss 172 // and .tbss sections if they do not already have non-zero addresses. 173 // (If the YAML file is being used to generate a valid object file, we 174 // expect all section addresses to be specified explicitly.) 175 switch (InitSections[I].Flags) { 176 case XCOFF::STYP_DATA: 177 CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size; 178 break; 179 case XCOFF::STYP_BSS: 180 if (!InitSections[I].Address) 181 InitSections[I].Address = CurrentEndDataAddr; 182 break; 183 case XCOFF::STYP_TDATA: 184 CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size; 185 break; 186 case XCOFF::STYP_TBSS: 187 if (!InitSections[I].Address) 188 InitSections[I].Address = CurrentEndTDataAddr; 189 break; 190 } 191 192 if (InitSections[I].SectionData.binary_size()) { 193 if (InitSections[I].FileOffsetToData) { 194 // Use the providedFileOffsetToData. 195 if (CurrentOffset > InitSections[I].FileOffsetToData) { 196 reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData, 197 "FileOffsetToData for the " + 198 InitSections[I].SectionName + " section"); 199 return false; 200 } 201 CurrentOffset = InitSections[I].FileOffsetToData; 202 } else { 203 CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign); 204 InitSections[I].FileOffsetToData = CurrentOffset; 205 } 206 CurrentOffset += InitSections[I].SectionData.binary_size(); 207 if (CurrentOffset > MaxRawDataSize) { 208 ErrHandler("maximum object size (" + Twine(MaxRawDataSize) + 209 ") exceeded when writing data for section " + Twine(I + 1) + 210 " (" + Twine(InitSections[I].SectionName) + ")"); 211 return false; 212 } 213 } 214 if (InitSections[I].SectionSubtype) { 215 uint32_t DWARFSubtype = 216 static_cast<uint32_t>(*InitSections[I].SectionSubtype); 217 if (InitSections[I].Flags != XCOFF::STYP_DWARF) { 218 ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section"); 219 return false; 220 } 221 unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask 222 : XCOFFSectionHeader32::SectionFlagsTypeMask; 223 if (DWARFSubtype & Mask) { 224 ErrHandler("the low-order bits of DWARFSectionSubtype must be 0"); 225 return false; 226 } 227 InitSections[I].Flags |= DWARFSubtype; 228 } 229 } 230 return initRelocations(CurrentOffset); 231 } 232 233 bool XCOFFWriter::initStringTable() { 234 if (Obj.StrTbl.RawContent) { 235 size_t RawSize = Obj.StrTbl.RawContent->binary_size(); 236 if (Obj.StrTbl.Strings || Obj.StrTbl.Length) { 237 ErrHandler( 238 "can't specify Strings or Length when RawContent is specified"); 239 return false; 240 } 241 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) { 242 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 243 ") is less than the RawContent data size (" + Twine(RawSize) + 244 ")"); 245 return false; 246 } 247 return true; 248 } 249 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) { 250 ErrHandler("ContentSize shouldn't be less than 4 without RawContent"); 251 return false; 252 } 253 254 // Build the string table. 255 StrTblBuilder.clear(); 256 257 if (Obj.StrTbl.Strings) { 258 // Add all specified strings to the string table. 259 for (StringRef StringEnt : *Obj.StrTbl.Strings) 260 StrTblBuilder.add(StringEnt); 261 262 size_t StrTblIdx = 0; 263 size_t NumOfStrings = Obj.StrTbl.Strings->size(); 264 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 265 if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 266 if (StrTblIdx < NumOfStrings) { 267 // Overwrite the symbol name with the specified string. 268 YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx]; 269 ++StrTblIdx; 270 } else 271 // Names that are not overwritten are still stored in the string 272 // table. 273 StrTblBuilder.add(YamlSym.SymbolName); 274 } 275 } 276 } else { 277 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 278 if (nameShouldBeInStringTable(YamlSym.SymbolName)) 279 StrTblBuilder.add(YamlSym.SymbolName); 280 } 281 } 282 283 // Check if the file name in the File Auxiliary Entry should be added to the 284 // string table. 285 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 286 for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 287 YamlSym.AuxEntries) { 288 if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 289 if (nameShouldBeInStringTable(AS->FileNameOrString.value_or(""))) 290 StrTblBuilder.add(AS->FileNameOrString.value_or("")); 291 } 292 } 293 294 StrTblBuilder.finalize(); 295 296 size_t StrTblSize = StrTblBuilder.getSize(); 297 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) { 298 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 299 ") is less than the size of the data that would otherwise be " 300 "written (" + 301 Twine(StrTblSize) + ")"); 302 return false; 303 } 304 305 return true; 306 } 307 308 bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { 309 // The default format of the object file is XCOFF32. 310 InitFileHdr.Magic = XCOFF::XCOFF32; 311 InitFileHdr.NumberOfSections = Obj.Sections.size(); 312 InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); 313 314 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 315 uint32_t AuxCount = YamlSym.AuxEntries.size(); 316 if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) { 317 ErrHandler("specified NumberOfAuxEntries " + 318 Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) + 319 " is less than the actual number " 320 "of auxiliary entries " + 321 Twine(AuxCount)); 322 return false; 323 } 324 YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount); 325 // Add the number of auxiliary symbols to the total number. 326 InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries; 327 } 328 329 // Calculate SymbolTableOffset for the file header. 330 if (InitFileHdr.NumberOfSymTableEntries) { 331 if (Obj.Header.SymbolTableOffset) { 332 if (CurrentOffset > Obj.Header.SymbolTableOffset) { 333 reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset, 334 "SymbolTableOffset"); 335 return false; 336 } 337 CurrentOffset = Obj.Header.SymbolTableOffset; 338 } 339 InitFileHdr.SymbolTableOffset = CurrentOffset; 340 CurrentOffset += 341 InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; 342 if (CurrentOffset > MaxRawDataSize) { 343 ErrHandler("maximum object size of " + Twine(MaxRawDataSize) + 344 " exceeded when writing symbols"); 345 return false; 346 } 347 } 348 // TODO: Calculate FileOffsetToLineNumbers when line number supported. 349 return true; 350 } 351 352 void XCOFFWriter::initAuxFileHeader() { 353 if (Obj.AuxHeader) 354 InitAuxFileHdr = *Obj.AuxHeader; 355 // In general, an object file might contain multiple sections of a given type, 356 // but in a loadable module, there must be exactly one .text, .data, .bss, and 357 // .loader section. A loadable object might also have one .tdata section and 358 // one .tbss section. 359 // Set these section-related values if not set explicitly. We assume that the 360 // input YAML matches the format of the loadable object, but if multiple input 361 // sections still have the same type, the first section with that type 362 // prevails. 363 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 364 switch (InitSections[I].Flags) { 365 case XCOFF::STYP_TEXT: 366 if (!InitAuxFileHdr.TextSize) 367 InitAuxFileHdr.TextSize = InitSections[I].Size; 368 if (!InitAuxFileHdr.TextStartAddr) 369 InitAuxFileHdr.TextStartAddr = InitSections[I].Address; 370 if (!InitAuxFileHdr.SecNumOfText) 371 InitAuxFileHdr.SecNumOfText = I + 1; 372 break; 373 case XCOFF::STYP_DATA: 374 if (!InitAuxFileHdr.InitDataSize) 375 InitAuxFileHdr.InitDataSize = InitSections[I].Size; 376 if (!InitAuxFileHdr.DataStartAddr) 377 InitAuxFileHdr.DataStartAddr = InitSections[I].Address; 378 if (!InitAuxFileHdr.SecNumOfData) 379 InitAuxFileHdr.SecNumOfData = I + 1; 380 break; 381 case XCOFF::STYP_BSS: 382 if (!InitAuxFileHdr.BssDataSize) 383 InitAuxFileHdr.BssDataSize = InitSections[I].Size; 384 if (!InitAuxFileHdr.SecNumOfBSS) 385 InitAuxFileHdr.SecNumOfBSS = I + 1; 386 break; 387 case XCOFF::STYP_TDATA: 388 if (!InitAuxFileHdr.SecNumOfTData) 389 InitAuxFileHdr.SecNumOfTData = I + 1; 390 break; 391 case XCOFF::STYP_TBSS: 392 if (!InitAuxFileHdr.SecNumOfTBSS) 393 InitAuxFileHdr.SecNumOfTBSS = I + 1; 394 break; 395 case XCOFF::STYP_LOADER: 396 if (!InitAuxFileHdr.SecNumOfLoader) 397 InitAuxFileHdr.SecNumOfLoader = I + 1; 398 break; 399 default: 400 break; 401 } 402 } 403 } 404 405 bool XCOFFWriter::assignAddressesAndIndices() { 406 uint64_t FileHdrSize = 407 Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; 408 409 // If AuxHeaderSize is specified in the YAML file, we construct 410 // an auxiliary header. 411 uint64_t AuxFileHdrSize = 0; 412 413 if (Obj.Header.AuxHeaderSize) 414 AuxFileHdrSize = Obj.Header.AuxHeaderSize; 415 else if (Obj.AuxHeader) 416 AuxFileHdrSize = 417 (Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32); 418 uint64_t SecHdrSize = 419 Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; 420 uint64_t CurrentOffset = 421 FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize; 422 423 // Calculate section header info. 424 if (!initSectionHeaders(CurrentOffset)) 425 return false; 426 427 // Calculate file header info. 428 if (!initFileHeader(CurrentOffset)) 429 return false; 430 InitFileHdr.AuxHeaderSize = AuxFileHdrSize; 431 432 // Initialize the auxiliary file header. 433 if (AuxFileHdrSize) 434 initAuxFileHeader(); 435 436 // Initialize the string table. 437 return initStringTable(); 438 } 439 440 void XCOFFWriter::writeFileHeader() { 441 W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); 442 W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections 443 : InitFileHdr.NumberOfSections); 444 W.write<int32_t>(Obj.Header.TimeStamp); 445 if (Is64Bit) { 446 W.write<uint64_t>(InitFileHdr.SymbolTableOffset); 447 W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 448 W.write<uint16_t>(Obj.Header.Flags); 449 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 450 ? Obj.Header.NumberOfSymTableEntries 451 : InitFileHdr.NumberOfSymTableEntries); 452 } else { 453 W.write<uint32_t>(InitFileHdr.SymbolTableOffset); 454 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 455 ? Obj.Header.NumberOfSymTableEntries 456 : InitFileHdr.NumberOfSymTableEntries); 457 W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 458 W.write<uint16_t>(Obj.Header.Flags); 459 } 460 } 461 462 void XCOFFWriter::writeAuxFileHeader() { 463 W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1))); 464 W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1))); 465 if (Is64Bit) { 466 W.OS.write_zeros(4); // Reserved for debugger. 467 W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); 468 W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); 469 W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); 470 } else { 471 W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); 472 W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); 473 W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); 474 W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); 475 W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); 476 W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); 477 // A short 32-bit auxiliary header ends here. 478 if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort) 479 return; 480 W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); 481 } 482 W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0)); 483 W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0)); 484 W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0)); 485 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0)); 486 W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0)); 487 W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0)); 488 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0))); 489 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0))); 490 W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0))); 491 W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0))); 492 W.write<uint8_t>(0); // Reserved for CPU type. 493 if (Is64Bit) { 494 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); 495 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); 496 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); 497 W.write<uint8_t>( 498 InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80))); 499 W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); 500 W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); 501 W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); 502 W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); 503 W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); 504 W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); 505 } else { 506 W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); 507 W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); 508 W.OS.write_zeros(4); // Reserved for debugger. 509 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); 510 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); 511 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); 512 W.write<uint8_t>( 513 InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0))); 514 } 515 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0)); 516 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0)); 517 if (Is64Bit) { 518 W.write<uint16_t>( 519 InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB))); 520 if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64) 521 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64); 522 } else { 523 if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) 524 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32); 525 } 526 } 527 528 void XCOFFWriter::writeSectionHeaders() { 529 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 530 XCOFFYAML::Section DerivedSec = InitSections[I]; 531 writeName(DerivedSec.SectionName, W); 532 if (Is64Bit) { 533 // Virtual address is the same as physical address. 534 W.write<uint64_t>(DerivedSec.Address); // Physical address 535 W.write<uint64_t>(DerivedSec.Address); // Virtual address 536 W.write<uint64_t>(DerivedSec.Size); 537 W.write<uint64_t>(DerivedSec.FileOffsetToData); 538 W.write<uint64_t>(DerivedSec.FileOffsetToRelocations); 539 W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers); 540 W.write<uint32_t>(DerivedSec.NumberOfRelocations); 541 W.write<uint32_t>(DerivedSec.NumberOfLineNumbers); 542 W.write<int32_t>(DerivedSec.Flags); 543 W.OS.write_zeros(4); 544 } else { 545 // Virtual address is the same as physical address. 546 W.write<uint32_t>(DerivedSec.Address); // Physical address 547 W.write<uint32_t>(DerivedSec.Address); // Virtual address 548 W.write<uint32_t>(DerivedSec.Size); 549 W.write<uint32_t>(DerivedSec.FileOffsetToData); 550 W.write<uint32_t>(DerivedSec.FileOffsetToRelocations); 551 W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers); 552 W.write<uint16_t>(DerivedSec.NumberOfRelocations); 553 W.write<uint16_t>(DerivedSec.NumberOfLineNumbers); 554 W.write<int32_t>(DerivedSec.Flags); 555 } 556 } 557 } 558 559 bool XCOFFWriter::writeSectionData() { 560 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 561 XCOFFYAML::Section YamlSec = Obj.Sections[I]; 562 if (YamlSec.SectionData.binary_size()) { 563 // Fill the padding size with zeros. 564 int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData - 565 (W.OS.tell() - StartOffset); 566 if (PaddingSize < 0) { 567 ErrHandler("redundant data was written before section data"); 568 return false; 569 } 570 W.OS.write_zeros(PaddingSize); 571 YamlSec.SectionData.writeAsBinary(W.OS); 572 } 573 } 574 return true; 575 } 576 577 bool XCOFFWriter::writeRelocations() { 578 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 579 XCOFFYAML::Section YamlSec = Obj.Sections[I]; 580 if (!YamlSec.Relocations.empty()) { 581 int64_t PaddingSize = 582 InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset); 583 if (PaddingSize < 0) { 584 ErrHandler("redundant data was written before relocations"); 585 return false; 586 } 587 W.OS.write_zeros(PaddingSize); 588 for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { 589 if (Is64Bit) 590 W.write<uint64_t>(YamlRel.VirtualAddress); 591 else 592 W.write<uint32_t>(YamlRel.VirtualAddress); 593 W.write<uint32_t>(YamlRel.SymbolIndex); 594 W.write<uint8_t>(YamlRel.Info); 595 W.write<uint8_t>(YamlRel.Type); 596 } 597 } 598 } 599 return true; 600 } 601 602 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) { 603 uint8_t SymAlignAndType = 0; 604 if (AuxSym.SymbolAlignmentAndType) { 605 if (AuxSym.SymbolType || AuxSym.SymbolAlignment) { 606 ErrHandler("cannot specify SymbolType or SymbolAlignment if " 607 "SymbolAlignmentAndType is specified"); 608 return false; 609 } 610 SymAlignAndType = *AuxSym.SymbolAlignmentAndType; 611 } else { 612 if (AuxSym.SymbolType) { 613 uint8_t SymbolType = *AuxSym.SymbolType; 614 if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) { 615 ErrHandler("symbol type must be less than " + 616 Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask)); 617 return false; 618 } 619 SymAlignAndType = SymbolType; 620 } 621 if (AuxSym.SymbolAlignment) { 622 const uint8_t ShiftedSymbolAlignmentMask = 623 XCOFFCsectAuxRef::SymbolAlignmentMask >> 624 XCOFFCsectAuxRef::SymbolAlignmentBitOffset; 625 626 if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) { 627 ErrHandler("symbol alignment must be less than " + 628 Twine(1 + ShiftedSymbolAlignmentMask)); 629 return false; 630 } 631 SymAlignAndType |= (*AuxSym.SymbolAlignment 632 << XCOFFCsectAuxRef::SymbolAlignmentBitOffset); 633 } 634 } 635 if (Is64Bit) { 636 W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0)); 637 W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); 638 W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); 639 W.write<uint8_t>(SymAlignAndType); 640 W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); 641 W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0)); 642 W.write<uint8_t>(0); 643 W.write<uint8_t>(XCOFF::AUX_CSECT); 644 } else { 645 W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0)); 646 W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); 647 W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); 648 W.write<uint8_t>(SymAlignAndType); 649 W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); 650 W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0)); 651 W.write<uint16_t>(AuxSym.StabSectNum.value_or(0)); 652 } 653 return true; 654 } 655 656 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) { 657 assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32"); 658 W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); 659 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 660 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 661 W.write<uint8_t>(0); 662 W.write<uint8_t>(XCOFF::AUX_EXCEPT); 663 return true; 664 } 665 666 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) { 667 if (Is64Bit) { 668 W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0)); 669 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 670 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 671 W.write<uint8_t>(0); 672 W.write<uint8_t>(XCOFF::AUX_FCN); 673 } else { 674 W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); 675 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 676 W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0)); 677 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 678 W.OS.write_zeros(2); 679 } 680 return true; 681 } 682 683 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) { 684 StringRef FileName = AuxSym.FileNameOrString.value_or(""); 685 if (nameShouldBeInStringTable(FileName)) { 686 W.write<int32_t>(0); 687 W.write<uint32_t>(StrTblBuilder.getOffset(FileName)); 688 } else { 689 writeName(FileName, W); 690 } 691 W.OS.write_zeros(XCOFF::FileNamePadSize); 692 W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN)); 693 if (Is64Bit) { 694 W.OS.write_zeros(2); 695 W.write<uint8_t>(XCOFF::AUX_FILE); 696 } else { 697 W.OS.write_zeros(3); 698 } 699 return true; 700 } 701 702 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) { 703 if (Is64Bit) { 704 W.write<uint32_t>(AuxSym.LineNum.value_or(0)); 705 W.OS.write_zeros(13); 706 W.write<uint8_t>(XCOFF::AUX_SYM); 707 } else { 708 W.OS.write_zeros(2); 709 W.write<uint16_t>(AuxSym.LineNumHi.value_or(0)); 710 W.write<uint16_t>(AuxSym.LineNumLo.value_or(0)); 711 W.OS.write_zeros(12); 712 } 713 return true; 714 } 715 716 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) { 717 if (Is64Bit) { 718 W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0)); 719 W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 720 W.write<uint8_t>(0); 721 W.write<uint8_t>(XCOFF::AUX_SECT); 722 } else { 723 W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0)); 724 W.OS.write_zeros(4); 725 W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 726 W.OS.write_zeros(6); 727 } 728 return true; 729 } 730 731 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) { 732 assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64"); 733 W.write<uint32_t>(AuxSym.SectionLength.value_or(0)); 734 W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 735 W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0)); 736 W.OS.write_zeros(10); 737 return true; 738 } 739 740 bool XCOFFWriter::writeAuxSymbol( 741 const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) { 742 if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get())) 743 return writeAuxSymbol(*AS); 744 else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get())) 745 return writeAuxSymbol(*AS); 746 else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get())) 747 return writeAuxSymbol(*AS); 748 else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 749 return writeAuxSymbol(*AS); 750 else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get())) 751 return writeAuxSymbol(*AS); 752 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get())) 753 return writeAuxSymbol(*AS); 754 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get())) 755 return writeAuxSymbol(*AS); 756 llvm_unreachable("unknown auxiliary symbol type"); 757 return false; 758 } 759 760 bool XCOFFWriter::writeSymbols() { 761 int64_t PaddingSize = 762 InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset); 763 if (PaddingSize < 0) { 764 ErrHandler("redundant data was written before symbols"); 765 return false; 766 } 767 W.OS.write_zeros(PaddingSize); 768 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 769 if (Is64Bit) { 770 W.write<uint64_t>(YamlSym.Value); 771 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 772 } else { 773 if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 774 // For XCOFF32: A value of 0 indicates that the symbol name is in the 775 // string table. 776 W.write<int32_t>(0); 777 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 778 } else { 779 writeName(YamlSym.SymbolName, W); 780 } 781 W.write<uint32_t>(YamlSym.Value); 782 } 783 if (YamlSym.SectionName) { 784 auto It = SectionIndexMap.find(*YamlSym.SectionName); 785 if (It == SectionIndexMap.end()) { 786 ErrHandler("the SectionName " + *YamlSym.SectionName + 787 " specified in the symbol does not exist"); 788 return false; 789 } 790 if (YamlSym.SectionIndex && It->second != *YamlSym.SectionIndex) { 791 ErrHandler("the SectionName " + *YamlSym.SectionName + 792 " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) + 793 ") refer to different sections"); 794 return false; 795 } 796 W.write<int16_t>(It->second); 797 } else { 798 W.write<int16_t>(YamlSym.SectionIndex.value_or(0)); 799 } 800 W.write<uint16_t>(YamlSym.Type); 801 W.write<uint8_t>(YamlSym.StorageClass); 802 803 uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0); 804 W.write<uint8_t>(NumOfAuxSym); 805 806 if (!NumOfAuxSym && !YamlSym.AuxEntries.size()) 807 continue; 808 809 // Now write auxiliary entries. 810 if (!YamlSym.AuxEntries.size()) { 811 W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym); 812 } else { 813 for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 814 YamlSym.AuxEntries) { 815 if (!writeAuxSymbol(AuxSym)) 816 return false; 817 } 818 // Pad with zeros. 819 if (NumOfAuxSym > YamlSym.AuxEntries.size()) 820 W.OS.write_zeros(XCOFF::SymbolTableEntrySize * 821 (NumOfAuxSym - YamlSym.AuxEntries.size())); 822 } 823 } 824 return true; 825 } 826 827 void XCOFFWriter::writeStringTable() { 828 if (Obj.StrTbl.RawContent) { 829 Obj.StrTbl.RawContent->writeAsBinary(W.OS); 830 if (Obj.StrTbl.ContentSize) { 831 assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() && 832 "Specified ContentSize is less than the RawContent size."); 833 W.OS.write_zeros(*Obj.StrTbl.ContentSize - 834 Obj.StrTbl.RawContent->binary_size()); 835 } 836 return; 837 } 838 839 size_t StrTblBuilderSize = StrTblBuilder.getSize(); 840 // If neither Length nor ContentSize is specified, write the StrTblBuilder 841 // directly, which contains the auto-generated Length value. 842 if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) { 843 if (StrTblBuilderSize <= 4) 844 return; 845 StrTblBuilder.write(W.OS); 846 return; 847 } 848 849 // Serialize the string table's content to a temporary buffer. 850 std::unique_ptr<WritableMemoryBuffer> Buf = 851 WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize); 852 uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); 853 StrTblBuilder.write(Ptr); 854 // Replace the first 4 bytes, which contain the auto-generated Length value, 855 // with the specified value. 856 memset(Ptr, 0, 4); 857 support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length 858 : *Obj.StrTbl.ContentSize); 859 // Copy the buffer content to the actual output stream. 860 W.OS.write(Buf->getBufferStart(), Buf->getBufferSize()); 861 // Add zeros as padding after strings. 862 if (Obj.StrTbl.ContentSize) { 863 assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize && 864 "Specified ContentSize is less than the StringTableBuilder size."); 865 W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); 866 } 867 } 868 869 bool XCOFFWriter::writeXCOFF() { 870 if (!assignAddressesAndIndices()) 871 return false; 872 StartOffset = W.OS.tell(); 873 writeFileHeader(); 874 if (InitFileHdr.AuxHeaderSize) 875 writeAuxFileHeader(); 876 if (!Obj.Sections.empty()) { 877 writeSectionHeaders(); 878 if (!writeSectionData()) 879 return false; 880 if (!writeRelocations()) 881 return false; 882 } 883 if (!Obj.Symbols.empty() && !writeSymbols()) 884 return false; 885 writeStringTable(); 886 return true; 887 } 888 889 } // end anonymous namespace 890 891 namespace llvm { 892 namespace yaml { 893 894 bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { 895 XCOFFWriter Writer(Doc, Out, EH); 896 return Writer.writeXCOFF(); 897 } 898 899 } // namespace yaml 900 } // namespace llvm 901