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