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