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