| //===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | /// | 
 | /// \file | 
 | /// The xcoff component of yaml2obj. | 
 | /// | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/ADT/DenseMap.h" | 
 | #include "llvm/BinaryFormat/XCOFF.h" | 
 | #include "llvm/MC/StringTableBuilder.h" | 
 | #include "llvm/Object/XCOFFObjectFile.h" | 
 | #include "llvm/ObjectYAML/ObjectYAML.h" | 
 | #include "llvm/ObjectYAML/yaml2obj.h" | 
 | #include "llvm/Support/EndianStream.h" | 
 | #include "llvm/Support/MemoryBuffer.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 |  | 
 | using namespace llvm; | 
 | using namespace llvm::object; | 
 |  | 
 | namespace { | 
 |  | 
 | constexpr unsigned DefaultSectionAlign = 4; | 
 | constexpr int16_t MaxSectionIndex = INT16_MAX; | 
 | constexpr uint32_t MaxRawDataSize = UINT32_MAX; | 
 |  | 
 | class XCOFFWriter { | 
 | public: | 
 |   XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH) | 
 |       : Obj(Obj), W(OS, llvm::endianness::big), ErrHandler(EH), | 
 |         StrTblBuilder(StringTableBuilder::XCOFF) { | 
 |     Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64; | 
 |   } | 
 |   bool writeXCOFF(); | 
 |  | 
 | private: | 
 |   void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset, | 
 |                        const Twine &fieldName); | 
 |   bool nameShouldBeInStringTable(StringRef SymbolName); | 
 |   bool initFileHeader(uint64_t CurrentOffset); | 
 |   void initAuxFileHeader(); | 
 |   bool initSectionHeaders(uint64_t &CurrentOffset); | 
 |   bool initRelocations(uint64_t &CurrentOffset); | 
 |   bool initStringTable(); | 
 |   bool assignAddressesAndIndices(); | 
 |  | 
 |   void writeFileHeader(); | 
 |   void writeAuxFileHeader(); | 
 |   void writeSectionHeaders(); | 
 |   bool writeSectionData(); | 
 |   bool writeRelocations(); | 
 |   bool writeSymbols(); | 
 |   void writeStringTable(); | 
 |  | 
 |   bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym); | 
 |   bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym); | 
 |   bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym); | 
 |   bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym); | 
 |   bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym); | 
 |   bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym); | 
 |   bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym); | 
 |   bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym); | 
 |  | 
 |   XCOFFYAML::Object &Obj; | 
 |   bool Is64Bit = false; | 
 |   support::endian::Writer W; | 
 |   yaml::ErrorHandler ErrHandler; | 
 |   StringTableBuilder StrTblBuilder; | 
 |   uint64_t StartOffset = 0u; | 
 |   // Map the section name to its corrresponding section index. | 
 |   DenseMap<StringRef, int16_t> SectionIndexMap = { | 
 |       {StringRef("N_DEBUG"), XCOFF::N_DEBUG}, | 
 |       {StringRef("N_ABS"), XCOFF::N_ABS}, | 
 |       {StringRef("N_UNDEF"), XCOFF::N_UNDEF}}; | 
 |   XCOFFYAML::FileHeader InitFileHdr = Obj.Header; | 
 |   XCOFFYAML::AuxiliaryHeader InitAuxFileHdr; | 
 |   std::vector<XCOFFYAML::Section> InitSections = Obj.Sections; | 
 | }; | 
 |  | 
 | static void writeName(StringRef StrName, support::endian::Writer W) { | 
 |   char Name[XCOFF::NameSize]; | 
 |   memset(Name, 0, XCOFF::NameSize); | 
 |   char SrcName[] = ""; | 
 |   memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size()); | 
 |   ArrayRef<char> NameRef(Name, XCOFF::NameSize); | 
 |   W.write(NameRef); | 
 | } | 
 |  | 
 | void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset, | 
 |                                   uint64_t specifiedOffset, | 
 |                                   const Twine &fieldName) { | 
 |   ErrHandler("current file offset (" + Twine(CurrentOffset) + | 
 |              ") is bigger than the specified " + fieldName + " (" + | 
 |              Twine(specifiedOffset) + ") "); | 
 | } | 
 |  | 
 | bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { | 
 |   // For XCOFF64: The symbol name is always in the string table. | 
 |   return (SymbolName.size() > XCOFF::NameSize) || Is64Bit; | 
 | } | 
 |  | 
 | bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { | 
 |   for (XCOFFYAML::Section &InitSection : InitSections) { | 
 |     if (!InitSection.Relocations.empty()) { | 
 |       uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64 | 
 |                                  : XCOFF::RelocationSerializationSize32; | 
 |       uint64_t UsedSize = RelSize * InitSection.Relocations.size(); | 
 |  | 
 |       // If NumberOfRelocations was specified, we use it, even if it's | 
 |       // not consistent with the number of provided relocations. | 
 |       if (!InitSection.NumberOfRelocations) | 
 |         InitSection.NumberOfRelocations = InitSection.Relocations.size(); | 
 |  | 
 |       // If the YAML file specified an offset to relocations, we use it. | 
 |       if (InitSection.FileOffsetToRelocations) { | 
 |         if (CurrentOffset > InitSection.FileOffsetToRelocations) { | 
 |           reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations, | 
 |                           "FileOffsetToRelocations for the " + | 
 |                               InitSection.SectionName + " section"); | 
 |           return false; | 
 |         } | 
 |         CurrentOffset = InitSection.FileOffsetToRelocations; | 
 |       } else | 
 |         InitSection.FileOffsetToRelocations = CurrentOffset; | 
 |       CurrentOffset += UsedSize; | 
 |       if (CurrentOffset > MaxRawDataSize) { | 
 |         ErrHandler("maximum object size (" + Twine(MaxRawDataSize) + | 
 |                    ") exceeded when writing relocation data for section " + | 
 |                    Twine(InitSection.SectionName)); | 
 |         return false; | 
 |       } | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) { | 
 |   uint64_t CurrentEndDataAddr = 0; | 
 |   uint64_t CurrentEndTDataAddr = 0; | 
 |   for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { | 
 |     // Assign indices for sections. | 
 |     if (InitSections[I].SectionName.size()) { | 
 |       int16_t &SectionIndex = SectionIndexMap[InitSections[I].SectionName]; | 
 |       if (!SectionIndex) { | 
 |         // The section index starts from 1. | 
 |         SectionIndex = I + 1; | 
 |         if ((I + 1) > MaxSectionIndex) { | 
 |           ErrHandler("exceeded the maximum permitted section index of " + | 
 |                      Twine(MaxSectionIndex)); | 
 |           return false; | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     if (!InitSections[I].Size) | 
 |       InitSections[I].Size = InitSections[I].SectionData.binary_size(); | 
 |  | 
 |     // Section data addresses (physical/virtual) are related to symbol | 
 |     // addresses and alignments. Furthermore, it is possible to specify the | 
 |     // same starting addresses for the .text, .data, and .tdata sections. | 
 |     // Without examining all the symbols and their addreses and alignments, | 
 |     // it is not possible to compute valid section addresses. The only | 
 |     // condition required by XCOFF is that the .bss section immediately | 
 |     // follows the .data section, and the .tbss section immediately follows | 
 |     // the .tdata section. Therefore, we only assign addresses to the .bss | 
 |     // and .tbss sections if they do not already have non-zero addresses. | 
 |     // (If the YAML file is being used to generate a valid object file, we | 
 |     // expect all section addresses to be specified explicitly.) | 
 |     switch (InitSections[I].Flags) { | 
 |     case XCOFF::STYP_DATA: | 
 |       CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size; | 
 |       break; | 
 |     case XCOFF::STYP_BSS: | 
 |       if (!InitSections[I].Address) | 
 |         InitSections[I].Address = CurrentEndDataAddr; | 
 |       break; | 
 |     case XCOFF::STYP_TDATA: | 
 |       CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size; | 
 |       break; | 
 |     case XCOFF::STYP_TBSS: | 
 |       if (!InitSections[I].Address) | 
 |         InitSections[I].Address = CurrentEndTDataAddr; | 
 |       break; | 
 |     } | 
 |  | 
 |     if (InitSections[I].SectionData.binary_size()) { | 
 |       if (InitSections[I].FileOffsetToData) { | 
 |         // Use the providedFileOffsetToData. | 
 |         if (CurrentOffset > InitSections[I].FileOffsetToData) { | 
 |           reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData, | 
 |                           "FileOffsetToData for the " + | 
 |                               InitSections[I].SectionName + " section"); | 
 |           return false; | 
 |         } | 
 |         CurrentOffset = InitSections[I].FileOffsetToData; | 
 |       } else { | 
 |         CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign); | 
 |         InitSections[I].FileOffsetToData = CurrentOffset; | 
 |       } | 
 |       CurrentOffset += InitSections[I].SectionData.binary_size(); | 
 |       if (CurrentOffset > MaxRawDataSize) { | 
 |         ErrHandler("maximum object size (" + Twine(MaxRawDataSize) + | 
 |                    ") exceeded when writing data for section " + Twine(I + 1) + | 
 |                    " (" + Twine(InitSections[I].SectionName) + ")"); | 
 |         return false; | 
 |       } | 
 |     } | 
 |     if (InitSections[I].SectionSubtype) { | 
 |       uint32_t DWARFSubtype = | 
 |           static_cast<uint32_t>(*InitSections[I].SectionSubtype); | 
 |       if (InitSections[I].Flags != XCOFF::STYP_DWARF) { | 
 |         ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section"); | 
 |         return false; | 
 |       } | 
 |       unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask | 
 |                               : XCOFFSectionHeader32::SectionFlagsTypeMask; | 
 |       if (DWARFSubtype & Mask) { | 
 |         ErrHandler("the low-order bits of DWARFSectionSubtype must be 0"); | 
 |         return false; | 
 |       } | 
 |       InitSections[I].Flags |= DWARFSubtype; | 
 |     } | 
 |   } | 
 |   return initRelocations(CurrentOffset); | 
 | } | 
 |  | 
 | bool XCOFFWriter::initStringTable() { | 
 |   if (Obj.StrTbl.RawContent) { | 
 |     size_t RawSize = Obj.StrTbl.RawContent->binary_size(); | 
 |     if (Obj.StrTbl.Strings || Obj.StrTbl.Length) { | 
 |       ErrHandler( | 
 |           "can't specify Strings or Length when RawContent is specified"); | 
 |       return false; | 
 |     } | 
 |     if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) { | 
 |       ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + | 
 |                  ") is less than the RawContent data size (" + Twine(RawSize) + | 
 |                  ")"); | 
 |       return false; | 
 |     } | 
 |     return true; | 
 |   } | 
 |   if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) { | 
 |     ErrHandler("ContentSize shouldn't be less than 4 without RawContent"); | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Build the string table. | 
 |   StrTblBuilder.clear(); | 
 |  | 
 |   if (Obj.StrTbl.Strings) { | 
 |     // Add all specified strings to the string table. | 
 |     for (StringRef StringEnt : *Obj.StrTbl.Strings) | 
 |       StrTblBuilder.add(StringEnt); | 
 |  | 
 |     size_t StrTblIdx = 0; | 
 |     size_t NumOfStrings = Obj.StrTbl.Strings->size(); | 
 |     for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { | 
 |       if (nameShouldBeInStringTable(YamlSym.SymbolName)) { | 
 |         if (StrTblIdx < NumOfStrings) { | 
 |           // Overwrite the symbol name with the specified string. | 
 |           YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx]; | 
 |           ++StrTblIdx; | 
 |         } else | 
 |           // Names that are not overwritten are still stored in the string | 
 |           // table. | 
 |           StrTblBuilder.add(YamlSym.SymbolName); | 
 |       } | 
 |     } | 
 |   } else { | 
 |     for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { | 
 |       if (nameShouldBeInStringTable(YamlSym.SymbolName)) | 
 |         StrTblBuilder.add(YamlSym.SymbolName); | 
 |     } | 
 |   } | 
 |  | 
 |   // Check if the file name in the File Auxiliary Entry should be added to the | 
 |   // string table. | 
 |   for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { | 
 |     for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : | 
 |          YamlSym.AuxEntries) { | 
 |       if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) | 
 |         if (nameShouldBeInStringTable(AS->FileNameOrString.value_or(""))) | 
 |           StrTblBuilder.add(AS->FileNameOrString.value_or("")); | 
 |     } | 
 |   } | 
 |  | 
 |   StrTblBuilder.finalize(); | 
 |  | 
 |   size_t StrTblSize = StrTblBuilder.getSize(); | 
 |   if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) { | 
 |     ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + | 
 |                ") is less than the size of the data that would otherwise be " | 
 |                "written (" + | 
 |                Twine(StrTblSize) + ")"); | 
 |     return false; | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { | 
 |   // The default format of the object file is XCOFF32. | 
 |   InitFileHdr.Magic = XCOFF::XCOFF32; | 
 |   InitFileHdr.NumberOfSections = Obj.Sections.size(); | 
 |   InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); | 
 |  | 
 |   for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { | 
 |     uint32_t AuxCount = YamlSym.AuxEntries.size(); | 
 |     if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) { | 
 |       ErrHandler("specified NumberOfAuxEntries " + | 
 |                  Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) + | 
 |                  " is less than the actual number " | 
 |                  "of auxiliary entries " + | 
 |                  Twine(AuxCount)); | 
 |       return false; | 
 |     } | 
 |     YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount); | 
 |     // Add the number of auxiliary symbols to the total number. | 
 |     InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries; | 
 |   } | 
 |  | 
 |   // Calculate SymbolTableOffset for the file header. | 
 |   if (InitFileHdr.NumberOfSymTableEntries) { | 
 |     if (Obj.Header.SymbolTableOffset) { | 
 |       if (CurrentOffset > Obj.Header.SymbolTableOffset) { | 
 |         reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset, | 
 |                         "SymbolTableOffset"); | 
 |         return false; | 
 |       } | 
 |       CurrentOffset = Obj.Header.SymbolTableOffset; | 
 |     } | 
 |     InitFileHdr.SymbolTableOffset = CurrentOffset; | 
 |     CurrentOffset += | 
 |         InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; | 
 |     if (CurrentOffset > MaxRawDataSize) { | 
 |       ErrHandler("maximum object size of " + Twine(MaxRawDataSize) + | 
 |                  " exceeded when writing symbols"); | 
 |       return false; | 
 |     } | 
 |   } | 
 |   // TODO: Calculate FileOffsetToLineNumbers when line number supported. | 
 |   return true; | 
 | } | 
 |  | 
 | void XCOFFWriter::initAuxFileHeader() { | 
 |   if (Obj.AuxHeader) | 
 |     InitAuxFileHdr = *Obj.AuxHeader; | 
 |   // In general, an object file might contain multiple sections of a given type, | 
 |   // but in a loadable module, there must be exactly one .text, .data, .bss, and | 
 |   // .loader section. A loadable object might also have one .tdata section and | 
 |   // one .tbss section. | 
 |   // Set these section-related values if not set explicitly. We assume that the | 
 |   // input YAML matches the format of the loadable object, but if multiple input | 
 |   // sections still have the same type, the first section with that type | 
 |   // prevails. | 
 |   for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { | 
 |     switch (InitSections[I].Flags) { | 
 |     case XCOFF::STYP_TEXT: | 
 |       if (!InitAuxFileHdr.TextSize) | 
 |         InitAuxFileHdr.TextSize = InitSections[I].Size; | 
 |       if (!InitAuxFileHdr.TextStartAddr) | 
 |         InitAuxFileHdr.TextStartAddr = InitSections[I].Address; | 
 |       if (!InitAuxFileHdr.SecNumOfText) | 
 |         InitAuxFileHdr.SecNumOfText = I + 1; | 
 |       break; | 
 |     case XCOFF::STYP_DATA: | 
 |       if (!InitAuxFileHdr.InitDataSize) | 
 |         InitAuxFileHdr.InitDataSize = InitSections[I].Size; | 
 |       if (!InitAuxFileHdr.DataStartAddr) | 
 |         InitAuxFileHdr.DataStartAddr = InitSections[I].Address; | 
 |       if (!InitAuxFileHdr.SecNumOfData) | 
 |         InitAuxFileHdr.SecNumOfData = I + 1; | 
 |       break; | 
 |     case XCOFF::STYP_BSS: | 
 |       if (!InitAuxFileHdr.BssDataSize) | 
 |         InitAuxFileHdr.BssDataSize = InitSections[I].Size; | 
 |       if (!InitAuxFileHdr.SecNumOfBSS) | 
 |         InitAuxFileHdr.SecNumOfBSS = I + 1; | 
 |       break; | 
 |     case XCOFF::STYP_TDATA: | 
 |       if (!InitAuxFileHdr.SecNumOfTData) | 
 |         InitAuxFileHdr.SecNumOfTData = I + 1; | 
 |       break; | 
 |     case XCOFF::STYP_TBSS: | 
 |       if (!InitAuxFileHdr.SecNumOfTBSS) | 
 |         InitAuxFileHdr.SecNumOfTBSS = I + 1; | 
 |       break; | 
 |     case XCOFF::STYP_LOADER: | 
 |       if (!InitAuxFileHdr.SecNumOfLoader) | 
 |         InitAuxFileHdr.SecNumOfLoader = I + 1; | 
 |       break; | 
 |     default: | 
 |       break; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | bool XCOFFWriter::assignAddressesAndIndices() { | 
 |   uint64_t FileHdrSize = | 
 |       Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; | 
 |  | 
 |   // If AuxHeaderSize is specified in the YAML file, we construct | 
 |   // an auxiliary header. | 
 |   uint64_t AuxFileHdrSize = 0; | 
 |  | 
 |   if (Obj.Header.AuxHeaderSize) | 
 |     AuxFileHdrSize = Obj.Header.AuxHeaderSize; | 
 |   else if (Obj.AuxHeader) | 
 |     AuxFileHdrSize = | 
 |         (Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32); | 
 |   uint64_t SecHdrSize = | 
 |       Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; | 
 |   uint64_t CurrentOffset = | 
 |       FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize; | 
 |  | 
 |   // Calculate section header info. | 
 |   if (!initSectionHeaders(CurrentOffset)) | 
 |     return false; | 
 |  | 
 |   // Calculate file header info. | 
 |   if (!initFileHeader(CurrentOffset)) | 
 |     return false; | 
 |   InitFileHdr.AuxHeaderSize = AuxFileHdrSize; | 
 |  | 
 |   // Initialize the auxiliary file header. | 
 |   if (AuxFileHdrSize) | 
 |     initAuxFileHeader(); | 
 |  | 
 |   // Initialize the string table. | 
 |   return initStringTable(); | 
 | } | 
 |  | 
 | void XCOFFWriter::writeFileHeader() { | 
 |   W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); | 
 |   W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections | 
 |                                                 : InitFileHdr.NumberOfSections); | 
 |   W.write<int32_t>(Obj.Header.TimeStamp); | 
 |   if (Is64Bit) { | 
 |     W.write<uint64_t>(InitFileHdr.SymbolTableOffset); | 
 |     W.write<uint16_t>(InitFileHdr.AuxHeaderSize); | 
 |     W.write<uint16_t>(Obj.Header.Flags); | 
 |     W.write<int32_t>(Obj.Header.NumberOfSymTableEntries | 
 |                          ? Obj.Header.NumberOfSymTableEntries | 
 |                          : InitFileHdr.NumberOfSymTableEntries); | 
 |   } else { | 
 |     W.write<uint32_t>(InitFileHdr.SymbolTableOffset); | 
 |     W.write<int32_t>(Obj.Header.NumberOfSymTableEntries | 
 |                          ? Obj.Header.NumberOfSymTableEntries | 
 |                          : InitFileHdr.NumberOfSymTableEntries); | 
 |     W.write<uint16_t>(InitFileHdr.AuxHeaderSize); | 
 |     W.write<uint16_t>(Obj.Header.Flags); | 
 |   } | 
 | } | 
 |  | 
 | void XCOFFWriter::writeAuxFileHeader() { | 
 |   W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1))); | 
 |   W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1))); | 
 |   if (Is64Bit) { | 
 |     W.OS.write_zeros(4); // Reserved for debugger. | 
 |     W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); | 
 |   } else { | 
 |     W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); | 
 |     W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); | 
 |     W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); | 
 |     // A short 32-bit auxiliary header ends here. | 
 |     if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort) | 
 |       return; | 
 |     W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); | 
 |   } | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0)); | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0)); | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0)); | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0)); | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0)); | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0)); | 
 |   W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0))); | 
 |   W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0))); | 
 |   W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0))); | 
 |   W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0))); | 
 |   W.write<uint8_t>(0); // Reserved for CPU type. | 
 |   if (Is64Bit) { | 
 |     W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); | 
 |     W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); | 
 |     W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); | 
 |     W.write<uint8_t>( | 
 |         InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); | 
 |   } else { | 
 |     W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); | 
 |     W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); | 
 |     W.OS.write_zeros(4); // Reserved for debugger. | 
 |     W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); | 
 |     W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); | 
 |     W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); | 
 |     W.write<uint8_t>( | 
 |         InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0))); | 
 |   } | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0)); | 
 |   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0)); | 
 |   if (Is64Bit) { | 
 |     W.write<uint16_t>( | 
 |         InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB))); | 
 |     if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64) | 
 |       W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64); | 
 |   } else { | 
 |     if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) | 
 |       W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32); | 
 |   } | 
 | } | 
 |  | 
 | void XCOFFWriter::writeSectionHeaders() { | 
 |   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { | 
 |     XCOFFYAML::Section DerivedSec = InitSections[I]; | 
 |     writeName(DerivedSec.SectionName, W); | 
 |     if (Is64Bit) { | 
 |       // Virtual address is the same as physical address. | 
 |       W.write<uint64_t>(DerivedSec.Address); // Physical address | 
 |       W.write<uint64_t>(DerivedSec.Address); // Virtual address | 
 |       W.write<uint64_t>(DerivedSec.Size); | 
 |       W.write<uint64_t>(DerivedSec.FileOffsetToData); | 
 |       W.write<uint64_t>(DerivedSec.FileOffsetToRelocations); | 
 |       W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers); | 
 |       W.write<uint32_t>(DerivedSec.NumberOfRelocations); | 
 |       W.write<uint32_t>(DerivedSec.NumberOfLineNumbers); | 
 |       W.write<int32_t>(DerivedSec.Flags); | 
 |       W.OS.write_zeros(4); | 
 |     } else { | 
 |       // Virtual address is the same as physical address. | 
 |       W.write<uint32_t>(DerivedSec.Address); // Physical address | 
 |       W.write<uint32_t>(DerivedSec.Address); // Virtual address | 
 |       W.write<uint32_t>(DerivedSec.Size); | 
 |       W.write<uint32_t>(DerivedSec.FileOffsetToData); | 
 |       W.write<uint32_t>(DerivedSec.FileOffsetToRelocations); | 
 |       W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers); | 
 |       W.write<uint16_t>(DerivedSec.NumberOfRelocations); | 
 |       W.write<uint16_t>(DerivedSec.NumberOfLineNumbers); | 
 |       W.write<int32_t>(DerivedSec.Flags); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeSectionData() { | 
 |   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { | 
 |     XCOFFYAML::Section YamlSec = Obj.Sections[I]; | 
 |     if (YamlSec.SectionData.binary_size()) { | 
 |       // Fill the padding size with zeros. | 
 |       int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData - | 
 |                             (W.OS.tell() - StartOffset); | 
 |       if (PaddingSize < 0) { | 
 |         ErrHandler("redundant data was written before section data"); | 
 |         return false; | 
 |       } | 
 |       W.OS.write_zeros(PaddingSize); | 
 |       YamlSec.SectionData.writeAsBinary(W.OS); | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeRelocations() { | 
 |   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { | 
 |     XCOFFYAML::Section YamlSec = Obj.Sections[I]; | 
 |     if (!YamlSec.Relocations.empty()) { | 
 |       int64_t PaddingSize = | 
 |           InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset); | 
 |       if (PaddingSize < 0) { | 
 |         ErrHandler("redundant data was written before relocations"); | 
 |         return false; | 
 |       } | 
 |       W.OS.write_zeros(PaddingSize); | 
 |       for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { | 
 |         if (Is64Bit) | 
 |           W.write<uint64_t>(YamlRel.VirtualAddress); | 
 |         else | 
 |           W.write<uint32_t>(YamlRel.VirtualAddress); | 
 |         W.write<uint32_t>(YamlRel.SymbolIndex); | 
 |         W.write<uint8_t>(YamlRel.Info); | 
 |         W.write<uint8_t>(YamlRel.Type); | 
 |       } | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) { | 
 |   uint8_t SymAlignAndType = 0; | 
 |   if (AuxSym.SymbolAlignmentAndType) { | 
 |     if (AuxSym.SymbolType || AuxSym.SymbolAlignment) { | 
 |       ErrHandler("cannot specify SymbolType or SymbolAlignment if " | 
 |                  "SymbolAlignmentAndType is specified"); | 
 |       return false; | 
 |     } | 
 |     SymAlignAndType = *AuxSym.SymbolAlignmentAndType; | 
 |   } else { | 
 |     if (AuxSym.SymbolType) { | 
 |       uint8_t SymbolType = *AuxSym.SymbolType; | 
 |       if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) { | 
 |         ErrHandler("symbol type must be less than " + | 
 |                    Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask)); | 
 |         return false; | 
 |       } | 
 |       SymAlignAndType = SymbolType; | 
 |     } | 
 |     if (AuxSym.SymbolAlignment) { | 
 |       const uint8_t ShiftedSymbolAlignmentMask = | 
 |           XCOFFCsectAuxRef::SymbolAlignmentMask >> | 
 |           XCOFFCsectAuxRef::SymbolAlignmentBitOffset; | 
 |  | 
 |       if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) { | 
 |         ErrHandler("symbol alignment must be less than " + | 
 |                    Twine(1 + ShiftedSymbolAlignmentMask)); | 
 |         return false; | 
 |       } | 
 |       SymAlignAndType |= (*AuxSym.SymbolAlignment | 
 |                           << XCOFFCsectAuxRef::SymbolAlignmentBitOffset); | 
 |     } | 
 |   } | 
 |   if (Is64Bit) { | 
 |     W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0)); | 
 |     W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); | 
 |     W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); | 
 |     W.write<uint8_t>(SymAlignAndType); | 
 |     W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); | 
 |     W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0)); | 
 |     W.write<uint8_t>(0); | 
 |     W.write<uint8_t>(XCOFF::AUX_CSECT); | 
 |   } else { | 
 |     W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0)); | 
 |     W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); | 
 |     W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); | 
 |     W.write<uint8_t>(SymAlignAndType); | 
 |     W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); | 
 |     W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0)); | 
 |     W.write<uint16_t>(AuxSym.StabSectNum.value_or(0)); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) { | 
 |   assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32"); | 
 |   W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); | 
 |   W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); | 
 |   W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); | 
 |   W.write<uint8_t>(0); | 
 |   W.write<uint8_t>(XCOFF::AUX_EXCEPT); | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) { | 
 |   if (Is64Bit) { | 
 |     W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0)); | 
 |     W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); | 
 |     W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); | 
 |     W.write<uint8_t>(0); | 
 |     W.write<uint8_t>(XCOFF::AUX_FCN); | 
 |   } else { | 
 |     W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); | 
 |     W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); | 
 |     W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0)); | 
 |     W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); | 
 |     W.OS.write_zeros(2); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) { | 
 |   StringRef FileName = AuxSym.FileNameOrString.value_or(""); | 
 |   if (nameShouldBeInStringTable(FileName)) { | 
 |     W.write<int32_t>(0); | 
 |     W.write<uint32_t>(StrTblBuilder.getOffset(FileName)); | 
 |   } else { | 
 |     writeName(FileName, W); | 
 |   } | 
 |   W.OS.write_zeros(XCOFF::FileNamePadSize); | 
 |   W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN)); | 
 |   if (Is64Bit) { | 
 |     W.OS.write_zeros(2); | 
 |     W.write<uint8_t>(XCOFF::AUX_FILE); | 
 |   } else { | 
 |     W.OS.write_zeros(3); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) { | 
 |   if (Is64Bit) { | 
 |     W.write<uint32_t>(AuxSym.LineNum.value_or(0)); | 
 |     W.OS.write_zeros(13); | 
 |     W.write<uint8_t>(XCOFF::AUX_SYM); | 
 |   } else { | 
 |     W.OS.write_zeros(2); | 
 |     W.write<uint16_t>(AuxSym.LineNumHi.value_or(0)); | 
 |     W.write<uint16_t>(AuxSym.LineNumLo.value_or(0)); | 
 |     W.OS.write_zeros(12); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) { | 
 |   if (Is64Bit) { | 
 |     W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0)); | 
 |     W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0)); | 
 |     W.write<uint8_t>(0); | 
 |     W.write<uint8_t>(XCOFF::AUX_SECT); | 
 |   } else { | 
 |     W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0)); | 
 |     W.OS.write_zeros(4); | 
 |     W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0)); | 
 |     W.OS.write_zeros(6); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) { | 
 |   assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64"); | 
 |   W.write<uint32_t>(AuxSym.SectionLength.value_or(0)); | 
 |   W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0)); | 
 |   W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0)); | 
 |   W.OS.write_zeros(10); | 
 |   return true; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeAuxSymbol( | 
 |     const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) { | 
 |   if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get())) | 
 |     return writeAuxSymbol(*AS); | 
 |   else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get())) | 
 |     return writeAuxSymbol(*AS); | 
 |   else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get())) | 
 |     return writeAuxSymbol(*AS); | 
 |   else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) | 
 |     return writeAuxSymbol(*AS); | 
 |   else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get())) | 
 |     return writeAuxSymbol(*AS); | 
 |   else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get())) | 
 |     return writeAuxSymbol(*AS); | 
 |   else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get())) | 
 |     return writeAuxSymbol(*AS); | 
 |   llvm_unreachable("unknown auxiliary symbol type"); | 
 |   return false; | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeSymbols() { | 
 |   int64_t PaddingSize = | 
 |       InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset); | 
 |   if (PaddingSize < 0) { | 
 |     ErrHandler("redundant data was written before symbols"); | 
 |     return false; | 
 |   } | 
 |   W.OS.write_zeros(PaddingSize); | 
 |   for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { | 
 |     if (Is64Bit) { | 
 |       W.write<uint64_t>(YamlSym.Value); | 
 |       W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); | 
 |     } else { | 
 |       if (nameShouldBeInStringTable(YamlSym.SymbolName)) { | 
 |         // For XCOFF32: A value of 0 indicates that the symbol name is in the | 
 |         // string table. | 
 |         W.write<int32_t>(0); | 
 |         W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); | 
 |       } else { | 
 |         writeName(YamlSym.SymbolName, W); | 
 |       } | 
 |       W.write<uint32_t>(YamlSym.Value); | 
 |     } | 
 |     if (YamlSym.SectionName) { | 
 |       auto It = SectionIndexMap.find(*YamlSym.SectionName); | 
 |       if (It == SectionIndexMap.end()) { | 
 |         ErrHandler("the SectionName " + *YamlSym.SectionName + | 
 |                    " specified in the symbol does not exist"); | 
 |         return false; | 
 |       } | 
 |       if (YamlSym.SectionIndex && It->second != *YamlSym.SectionIndex) { | 
 |         ErrHandler("the SectionName " + *YamlSym.SectionName + | 
 |                    " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) + | 
 |                    ") refer to different sections"); | 
 |         return false; | 
 |       } | 
 |       W.write<int16_t>(It->second); | 
 |     } else { | 
 |       W.write<int16_t>(YamlSym.SectionIndex.value_or(0)); | 
 |     } | 
 |     W.write<uint16_t>(YamlSym.Type); | 
 |     W.write<uint8_t>(YamlSym.StorageClass); | 
 |  | 
 |     uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0); | 
 |     W.write<uint8_t>(NumOfAuxSym); | 
 |  | 
 |     if (!NumOfAuxSym && !YamlSym.AuxEntries.size()) | 
 |       continue; | 
 |  | 
 |     // Now write auxiliary entries. | 
 |     if (!YamlSym.AuxEntries.size()) { | 
 |       W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym); | 
 |     } else { | 
 |       for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : | 
 |            YamlSym.AuxEntries) { | 
 |         if (!writeAuxSymbol(AuxSym)) | 
 |           return false; | 
 |       } | 
 |       // Pad with zeros. | 
 |       if (NumOfAuxSym > YamlSym.AuxEntries.size()) | 
 |         W.OS.write_zeros(XCOFF::SymbolTableEntrySize * | 
 |                          (NumOfAuxSym - YamlSym.AuxEntries.size())); | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | void XCOFFWriter::writeStringTable() { | 
 |   if (Obj.StrTbl.RawContent) { | 
 |     Obj.StrTbl.RawContent->writeAsBinary(W.OS); | 
 |     if (Obj.StrTbl.ContentSize) { | 
 |       assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() && | 
 |              "Specified ContentSize is less than the RawContent size."); | 
 |       W.OS.write_zeros(*Obj.StrTbl.ContentSize - | 
 |                        Obj.StrTbl.RawContent->binary_size()); | 
 |     } | 
 |     return; | 
 |   } | 
 |  | 
 |   size_t StrTblBuilderSize = StrTblBuilder.getSize(); | 
 |   // If neither Length nor ContentSize is specified, write the StrTblBuilder | 
 |   // directly, which contains the auto-generated Length value. | 
 |   if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) { | 
 |     if (StrTblBuilderSize <= 4) | 
 |       return; | 
 |     StrTblBuilder.write(W.OS); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Serialize the string table's content to a temporary buffer. | 
 |   std::unique_ptr<WritableMemoryBuffer> Buf = | 
 |       WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize); | 
 |   uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); | 
 |   StrTblBuilder.write(Ptr); | 
 |   // Replace the first 4 bytes, which contain the auto-generated Length value, | 
 |   // with the specified value. | 
 |   memset(Ptr, 0, 4); | 
 |   support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length | 
 |                                                     : *Obj.StrTbl.ContentSize); | 
 |   // Copy the buffer content to the actual output stream. | 
 |   W.OS.write(Buf->getBufferStart(), Buf->getBufferSize()); | 
 |   // Add zeros as padding after strings. | 
 |   if (Obj.StrTbl.ContentSize) { | 
 |     assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize && | 
 |            "Specified ContentSize is less than the StringTableBuilder size."); | 
 |     W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); | 
 |   } | 
 | } | 
 |  | 
 | bool XCOFFWriter::writeXCOFF() { | 
 |   if (!assignAddressesAndIndices()) | 
 |     return false; | 
 |   StartOffset = W.OS.tell(); | 
 |   writeFileHeader(); | 
 |   if (InitFileHdr.AuxHeaderSize) | 
 |     writeAuxFileHeader(); | 
 |   if (!Obj.Sections.empty()) { | 
 |     writeSectionHeaders(); | 
 |     if (!writeSectionData()) | 
 |       return false; | 
 |     if (!writeRelocations()) | 
 |       return false; | 
 |   } | 
 |   if (!Obj.Symbols.empty() && !writeSymbols()) | 
 |     return false; | 
 |   writeStringTable(); | 
 |   return true; | 
 | } | 
 |  | 
 | } // end anonymous namespace | 
 |  | 
 | namespace llvm { | 
 | namespace yaml { | 
 |  | 
 | bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { | 
 |   XCOFFWriter Writer(Doc, Out, EH); | 
 |   return Writer.writeXCOFF(); | 
 | } | 
 |  | 
 | } // namespace yaml | 
 | } // namespace llvm |