1fe6060f1SDimitry Andric //===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric /// 9fe6060f1SDimitry Andric /// \file 10fe6060f1SDimitry Andric /// The xcoff component of yaml2obj. 11fe6060f1SDimitry Andric /// 12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13fe6060f1SDimitry Andric 14fe6060f1SDimitry Andric #include "llvm/ADT/DenseMap.h" 15fe6060f1SDimitry Andric #include "llvm/BinaryFormat/XCOFF.h" 16fe6060f1SDimitry Andric #include "llvm/MC/StringTableBuilder.h" 17fe6060f1SDimitry Andric #include "llvm/Object/XCOFFObjectFile.h" 18fe6060f1SDimitry Andric #include "llvm/ObjectYAML/ObjectYAML.h" 19fe6060f1SDimitry Andric #include "llvm/ObjectYAML/yaml2obj.h" 20fe6060f1SDimitry Andric #include "llvm/Support/EndianStream.h" 21fe6060f1SDimitry Andric #include "llvm/Support/LEB128.h" 22349cc55cSDimitry Andric #include "llvm/Support/MemoryBuffer.h" 23349cc55cSDimitry Andric #include "llvm/Support/raw_ostream.h" 24fe6060f1SDimitry Andric 25fe6060f1SDimitry Andric using namespace llvm; 26*0fca6ea1SDimitry Andric using namespace llvm::object; 27fe6060f1SDimitry Andric 28fe6060f1SDimitry Andric namespace { 29fe6060f1SDimitry Andric 30fe6060f1SDimitry Andric constexpr unsigned DefaultSectionAlign = 4; 31fe6060f1SDimitry Andric constexpr int16_t MaxSectionIndex = INT16_MAX; 32fe6060f1SDimitry Andric constexpr uint32_t MaxRawDataSize = UINT32_MAX; 33fe6060f1SDimitry Andric 34fe6060f1SDimitry Andric class XCOFFWriter { 35fe6060f1SDimitry Andric public: 36fe6060f1SDimitry Andric XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH) 375f757f3fSDimitry Andric : Obj(Obj), W(OS, llvm::endianness::big), ErrHandler(EH), 38349cc55cSDimitry Andric StrTblBuilder(StringTableBuilder::XCOFF) { 39fe6060f1SDimitry Andric Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64; 40fe6060f1SDimitry Andric } 41fe6060f1SDimitry Andric bool writeXCOFF(); 42fe6060f1SDimitry Andric 43fe6060f1SDimitry Andric private: 44*0fca6ea1SDimitry Andric void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset, 45*0fca6ea1SDimitry Andric const Twine &fieldName); 46fe6060f1SDimitry Andric bool nameShouldBeInStringTable(StringRef SymbolName); 47fe6060f1SDimitry Andric bool initFileHeader(uint64_t CurrentOffset); 48349cc55cSDimitry Andric void initAuxFileHeader(); 49*0fca6ea1SDimitry Andric bool initSectionHeaders(uint64_t &CurrentOffset); 50fe6060f1SDimitry Andric bool initRelocations(uint64_t &CurrentOffset); 51349cc55cSDimitry Andric bool initStringTable(); 52fe6060f1SDimitry Andric bool assignAddressesAndIndices(); 5304eeddc0SDimitry Andric 54fe6060f1SDimitry Andric void writeFileHeader(); 55349cc55cSDimitry Andric void writeAuxFileHeader(); 56*0fca6ea1SDimitry Andric void writeSectionHeaders(); 57fe6060f1SDimitry Andric bool writeSectionData(); 58fe6060f1SDimitry Andric bool writeRelocations(); 59fe6060f1SDimitry Andric bool writeSymbols(); 60349cc55cSDimitry Andric void writeStringTable(); 61fe6060f1SDimitry Andric 62*0fca6ea1SDimitry Andric bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym); 63*0fca6ea1SDimitry Andric bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym); 64*0fca6ea1SDimitry Andric bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym); 65*0fca6ea1SDimitry Andric bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym); 66*0fca6ea1SDimitry Andric bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym); 67*0fca6ea1SDimitry Andric bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym); 68*0fca6ea1SDimitry Andric bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym); 69*0fca6ea1SDimitry Andric bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym); 7004eeddc0SDimitry Andric 71fe6060f1SDimitry Andric XCOFFYAML::Object &Obj; 72fe6060f1SDimitry Andric bool Is64Bit = false; 73fe6060f1SDimitry Andric support::endian::Writer W; 74fe6060f1SDimitry Andric yaml::ErrorHandler ErrHandler; 75349cc55cSDimitry Andric StringTableBuilder StrTblBuilder; 7606c3fb27SDimitry Andric uint64_t StartOffset = 0u; 77fe6060f1SDimitry Andric // Map the section name to its corrresponding section index. 78fe6060f1SDimitry Andric DenseMap<StringRef, int16_t> SectionIndexMap = { 79fe6060f1SDimitry Andric {StringRef("N_DEBUG"), XCOFF::N_DEBUG}, 80fe6060f1SDimitry Andric {StringRef("N_ABS"), XCOFF::N_ABS}, 81fe6060f1SDimitry Andric {StringRef("N_UNDEF"), XCOFF::N_UNDEF}}; 82fe6060f1SDimitry Andric XCOFFYAML::FileHeader InitFileHdr = Obj.Header; 83349cc55cSDimitry Andric XCOFFYAML::AuxiliaryHeader InitAuxFileHdr; 84fe6060f1SDimitry Andric std::vector<XCOFFYAML::Section> InitSections = Obj.Sections; 85fe6060f1SDimitry Andric }; 86fe6060f1SDimitry Andric 87fe6060f1SDimitry Andric static void writeName(StringRef StrName, support::endian::Writer W) { 88fe6060f1SDimitry Andric char Name[XCOFF::NameSize]; 89fe6060f1SDimitry Andric memset(Name, 0, XCOFF::NameSize); 90fe6060f1SDimitry Andric char SrcName[] = ""; 91fe6060f1SDimitry Andric memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size()); 92fe6060f1SDimitry Andric ArrayRef<char> NameRef(Name, XCOFF::NameSize); 93fe6060f1SDimitry Andric W.write(NameRef); 94fe6060f1SDimitry Andric } 95fe6060f1SDimitry Andric 96*0fca6ea1SDimitry Andric void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset, 97*0fca6ea1SDimitry Andric uint64_t specifiedOffset, 98*0fca6ea1SDimitry Andric const Twine &fieldName) { 99*0fca6ea1SDimitry Andric ErrHandler("current file offset (" + Twine(CurrentOffset) + 100*0fca6ea1SDimitry Andric ") is bigger than the specified " + fieldName + " (" + 101*0fca6ea1SDimitry Andric Twine(specifiedOffset) + ") "); 102*0fca6ea1SDimitry Andric } 103*0fca6ea1SDimitry Andric 104fe6060f1SDimitry Andric bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { 105349cc55cSDimitry Andric // For XCOFF64: The symbol name is always in the string table. 106349cc55cSDimitry Andric return (SymbolName.size() > XCOFF::NameSize) || Is64Bit; 107fe6060f1SDimitry Andric } 108fe6060f1SDimitry Andric 109fe6060f1SDimitry Andric bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { 1100eae32dcSDimitry Andric for (XCOFFYAML::Section &InitSection : InitSections) { 1110eae32dcSDimitry Andric if (!InitSection.Relocations.empty()) { 112349cc55cSDimitry Andric uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64 113349cc55cSDimitry Andric : XCOFF::RelocationSerializationSize32; 114*0fca6ea1SDimitry Andric uint64_t UsedSize = RelSize * InitSection.Relocations.size(); 115*0fca6ea1SDimitry Andric 116*0fca6ea1SDimitry Andric // If NumberOfRelocations was specified, we use it, even if it's 117*0fca6ea1SDimitry Andric // not consistent with the number of provided relocations. 118*0fca6ea1SDimitry Andric if (!InitSection.NumberOfRelocations) 119*0fca6ea1SDimitry Andric InitSection.NumberOfRelocations = InitSection.Relocations.size(); 120*0fca6ea1SDimitry Andric 121*0fca6ea1SDimitry Andric // If the YAML file specified an offset to relocations, we use it. 122*0fca6ea1SDimitry Andric if (InitSection.FileOffsetToRelocations) { 123*0fca6ea1SDimitry Andric if (CurrentOffset > InitSection.FileOffsetToRelocations) { 124*0fca6ea1SDimitry Andric reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations, 125*0fca6ea1SDimitry Andric "FileOffsetToRelocations for the " + 126*0fca6ea1SDimitry Andric InitSection.SectionName + " section"); 127*0fca6ea1SDimitry Andric return false; 128*0fca6ea1SDimitry Andric } 129*0fca6ea1SDimitry Andric CurrentOffset = InitSection.FileOffsetToRelocations; 130*0fca6ea1SDimitry Andric } else 131*0fca6ea1SDimitry Andric InitSection.FileOffsetToRelocations = CurrentOffset; 132*0fca6ea1SDimitry Andric CurrentOffset += UsedSize; 133fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 134*0fca6ea1SDimitry Andric ErrHandler("maximum object size (" + Twine(MaxRawDataSize) + 135*0fca6ea1SDimitry Andric ") exceeded when writing relocation data for section " + 136*0fca6ea1SDimitry Andric Twine(InitSection.SectionName)); 137fe6060f1SDimitry Andric return false; 138fe6060f1SDimitry Andric } 139fe6060f1SDimitry Andric } 140fe6060f1SDimitry Andric } 141fe6060f1SDimitry Andric return true; 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric 144*0fca6ea1SDimitry Andric bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) { 145*0fca6ea1SDimitry Andric uint64_t CurrentEndDataAddr = 0; 146*0fca6ea1SDimitry Andric uint64_t CurrentEndTDataAddr = 0; 147fe6060f1SDimitry Andric for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 148fe6060f1SDimitry Andric // Assign indices for sections. 149fe6060f1SDimitry Andric if (InitSections[I].SectionName.size() && 150fe6060f1SDimitry Andric !SectionIndexMap[InitSections[I].SectionName]) { 151fe6060f1SDimitry Andric // The section index starts from 1. 152fe6060f1SDimitry Andric SectionIndexMap[InitSections[I].SectionName] = I + 1; 153fe6060f1SDimitry Andric if ((I + 1) > MaxSectionIndex) { 154fe6060f1SDimitry Andric ErrHandler("exceeded the maximum permitted section index of " + 155fe6060f1SDimitry Andric Twine(MaxSectionIndex)); 156fe6060f1SDimitry Andric return false; 157fe6060f1SDimitry Andric } 158fe6060f1SDimitry Andric } 159fe6060f1SDimitry Andric 160*0fca6ea1SDimitry Andric if (!InitSections[I].Size) 161*0fca6ea1SDimitry Andric InitSections[I].Size = InitSections[I].SectionData.binary_size(); 162fe6060f1SDimitry Andric 163*0fca6ea1SDimitry Andric // Section data addresses (physical/virtual) are related to symbol 164*0fca6ea1SDimitry Andric // addresses and alignments. Furthermore, it is possible to specify the 165*0fca6ea1SDimitry Andric // same starting addresses for the .text, .data, and .tdata sections. 166*0fca6ea1SDimitry Andric // Without examining all the symbols and their addreses and alignments, 167*0fca6ea1SDimitry Andric // it is not possible to compute valid section addresses. The only 168*0fca6ea1SDimitry Andric // condition required by XCOFF is that the .bss section immediately 169*0fca6ea1SDimitry Andric // follows the .data section, and the .tbss section immediately follows 170*0fca6ea1SDimitry Andric // the .tdata section. Therefore, we only assign addresses to the .bss 171*0fca6ea1SDimitry Andric // and .tbss sections if they do not already have non-zero addresses. 172*0fca6ea1SDimitry Andric // (If the YAML file is being used to generate a valid object file, we 173*0fca6ea1SDimitry Andric // expect all section addresses to be specified explicitly.) 174*0fca6ea1SDimitry Andric switch (InitSections[I].Flags) { 175*0fca6ea1SDimitry Andric case XCOFF::STYP_DATA: 176*0fca6ea1SDimitry Andric CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size; 177*0fca6ea1SDimitry Andric break; 178*0fca6ea1SDimitry Andric case XCOFF::STYP_BSS: 179*0fca6ea1SDimitry Andric if (!InitSections[I].Address) 180*0fca6ea1SDimitry Andric InitSections[I].Address = CurrentEndDataAddr; 181*0fca6ea1SDimitry Andric break; 182*0fca6ea1SDimitry Andric case XCOFF::STYP_TDATA: 183*0fca6ea1SDimitry Andric CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size; 184*0fca6ea1SDimitry Andric break; 185*0fca6ea1SDimitry Andric case XCOFF::STYP_TBSS: 186*0fca6ea1SDimitry Andric if (!InitSections[I].Address) 187*0fca6ea1SDimitry Andric InitSections[I].Address = CurrentEndTDataAddr; 188*0fca6ea1SDimitry Andric break; 189*0fca6ea1SDimitry Andric } 190*0fca6ea1SDimitry Andric 191fe6060f1SDimitry Andric if (InitSections[I].SectionData.binary_size()) { 192*0fca6ea1SDimitry Andric if (InitSections[I].FileOffsetToData) { 193*0fca6ea1SDimitry Andric // Use the providedFileOffsetToData. 194*0fca6ea1SDimitry Andric if (CurrentOffset > InitSections[I].FileOffsetToData) { 195*0fca6ea1SDimitry Andric reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData, 196*0fca6ea1SDimitry Andric "FileOffsetToData for the " + 197*0fca6ea1SDimitry Andric InitSections[I].SectionName + " section"); 198*0fca6ea1SDimitry Andric return false; 199*0fca6ea1SDimitry Andric } 200*0fca6ea1SDimitry Andric CurrentOffset = InitSections[I].FileOffsetToData; 201*0fca6ea1SDimitry Andric } else { 202fe6060f1SDimitry Andric CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign); 203*0fca6ea1SDimitry Andric InitSections[I].FileOffsetToData = CurrentOffset; 204*0fca6ea1SDimitry Andric } 205*0fca6ea1SDimitry Andric CurrentOffset += InitSections[I].SectionData.binary_size(); 206*0fca6ea1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 207*0fca6ea1SDimitry Andric ErrHandler("maximum object size (" + Twine(MaxRawDataSize) + 208*0fca6ea1SDimitry Andric ") exceeded when writing data for section " + Twine(I + 1) + 209*0fca6ea1SDimitry Andric " (" + Twine(InitSections[I].SectionName) + ")"); 210*0fca6ea1SDimitry Andric return false; 211*0fca6ea1SDimitry Andric } 212*0fca6ea1SDimitry Andric } 213*0fca6ea1SDimitry Andric if (InitSections[I].SectionSubtype) { 214*0fca6ea1SDimitry Andric uint32_t DWARFSubtype = 215*0fca6ea1SDimitry Andric static_cast<uint32_t>(*InitSections[I].SectionSubtype); 216*0fca6ea1SDimitry Andric if (InitSections[I].Flags != XCOFF::STYP_DWARF) { 217*0fca6ea1SDimitry Andric ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section"); 218*0fca6ea1SDimitry Andric return false; 219*0fca6ea1SDimitry Andric } 220*0fca6ea1SDimitry Andric unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask 221*0fca6ea1SDimitry Andric : XCOFFSectionHeader32::SectionFlagsTypeMask; 222*0fca6ea1SDimitry Andric if (DWARFSubtype & Mask) { 223*0fca6ea1SDimitry Andric ErrHandler("the low-order bits of DWARFSectionSubtype must be 0"); 224*0fca6ea1SDimitry Andric return false; 225*0fca6ea1SDimitry Andric } 226*0fca6ea1SDimitry Andric InitSections[I].Flags |= DWARFSubtype; 227fe6060f1SDimitry Andric } 228fe6060f1SDimitry Andric } 229fe6060f1SDimitry Andric return initRelocations(CurrentOffset); 230fe6060f1SDimitry Andric } 231fe6060f1SDimitry Andric 232349cc55cSDimitry Andric bool XCOFFWriter::initStringTable() { 233349cc55cSDimitry Andric if (Obj.StrTbl.RawContent) { 234349cc55cSDimitry Andric size_t RawSize = Obj.StrTbl.RawContent->binary_size(); 235349cc55cSDimitry Andric if (Obj.StrTbl.Strings || Obj.StrTbl.Length) { 236349cc55cSDimitry Andric ErrHandler( 237349cc55cSDimitry Andric "can't specify Strings or Length when RawContent is specified"); 238349cc55cSDimitry Andric return false; 239349cc55cSDimitry Andric } 240349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) { 241349cc55cSDimitry Andric ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 242349cc55cSDimitry Andric ") is less than the RawContent data size (" + Twine(RawSize) + 243349cc55cSDimitry Andric ")"); 244349cc55cSDimitry Andric return false; 245349cc55cSDimitry Andric } 246349cc55cSDimitry Andric return true; 247349cc55cSDimitry Andric } 248349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) { 249349cc55cSDimitry Andric ErrHandler("ContentSize shouldn't be less than 4 without RawContent"); 250349cc55cSDimitry Andric return false; 251349cc55cSDimitry Andric } 252349cc55cSDimitry Andric 253349cc55cSDimitry Andric // Build the string table. 254349cc55cSDimitry Andric StrTblBuilder.clear(); 255349cc55cSDimitry Andric 256349cc55cSDimitry Andric if (Obj.StrTbl.Strings) { 257*0fca6ea1SDimitry Andric // Add all specified strings to the string table. 258349cc55cSDimitry Andric for (StringRef StringEnt : *Obj.StrTbl.Strings) 259349cc55cSDimitry Andric StrTblBuilder.add(StringEnt); 260349cc55cSDimitry Andric 261349cc55cSDimitry Andric size_t StrTblIdx = 0; 262349cc55cSDimitry Andric size_t NumOfStrings = Obj.StrTbl.Strings->size(); 263349cc55cSDimitry Andric for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 264349cc55cSDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 265349cc55cSDimitry Andric if (StrTblIdx < NumOfStrings) { 266349cc55cSDimitry Andric // Overwrite the symbol name with the specified string. 267349cc55cSDimitry Andric YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx]; 268349cc55cSDimitry Andric ++StrTblIdx; 269349cc55cSDimitry Andric } else 270349cc55cSDimitry Andric // Names that are not overwritten are still stored in the string 271349cc55cSDimitry Andric // table. 272349cc55cSDimitry Andric StrTblBuilder.add(YamlSym.SymbolName); 273349cc55cSDimitry Andric } 274349cc55cSDimitry Andric } 275349cc55cSDimitry Andric } else { 27604eeddc0SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 277349cc55cSDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) 278349cc55cSDimitry Andric StrTblBuilder.add(YamlSym.SymbolName); 279349cc55cSDimitry Andric } 280349cc55cSDimitry Andric } 281349cc55cSDimitry Andric 28204eeddc0SDimitry Andric // Check if the file name in the File Auxiliary Entry should be added to the 28304eeddc0SDimitry Andric // string table. 28404eeddc0SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 28504eeddc0SDimitry Andric for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 28604eeddc0SDimitry Andric YamlSym.AuxEntries) { 28704eeddc0SDimitry Andric if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 28881ad6265SDimitry Andric if (nameShouldBeInStringTable(AS->FileNameOrString.value_or(""))) 28981ad6265SDimitry Andric StrTblBuilder.add(AS->FileNameOrString.value_or("")); 29004eeddc0SDimitry Andric } 29104eeddc0SDimitry Andric } 29204eeddc0SDimitry Andric 293349cc55cSDimitry Andric StrTblBuilder.finalize(); 294349cc55cSDimitry Andric 295349cc55cSDimitry Andric size_t StrTblSize = StrTblBuilder.getSize(); 296349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) { 297349cc55cSDimitry Andric ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 298349cc55cSDimitry Andric ") is less than the size of the data that would otherwise be " 299349cc55cSDimitry Andric "written (" + 300349cc55cSDimitry Andric Twine(StrTblSize) + ")"); 301349cc55cSDimitry Andric return false; 302349cc55cSDimitry Andric } 303349cc55cSDimitry Andric 304349cc55cSDimitry Andric return true; 305349cc55cSDimitry Andric } 306349cc55cSDimitry Andric 307fe6060f1SDimitry Andric bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { 308fe6060f1SDimitry Andric // The default format of the object file is XCOFF32. 309fe6060f1SDimitry Andric InitFileHdr.Magic = XCOFF::XCOFF32; 310fe6060f1SDimitry Andric InitFileHdr.NumberOfSections = Obj.Sections.size(); 311fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); 312fe6060f1SDimitry Andric 31304eeddc0SDimitry Andric for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 31404eeddc0SDimitry Andric uint32_t AuxCount = YamlSym.AuxEntries.size(); 31504eeddc0SDimitry Andric if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) { 31604eeddc0SDimitry Andric ErrHandler("specified NumberOfAuxEntries " + 31704eeddc0SDimitry Andric Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) + 31804eeddc0SDimitry Andric " is less than the actual number " 31904eeddc0SDimitry Andric "of auxiliary entries " + 32004eeddc0SDimitry Andric Twine(AuxCount)); 32104eeddc0SDimitry Andric return false; 32204eeddc0SDimitry Andric } 32381ad6265SDimitry Andric YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount); 324fe6060f1SDimitry Andric // Add the number of auxiliary symbols to the total number. 32504eeddc0SDimitry Andric InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries; 32604eeddc0SDimitry Andric } 327fe6060f1SDimitry Andric 328fe6060f1SDimitry Andric // Calculate SymbolTableOffset for the file header. 329fe6060f1SDimitry Andric if (InitFileHdr.NumberOfSymTableEntries) { 330*0fca6ea1SDimitry Andric if (Obj.Header.SymbolTableOffset) { 331*0fca6ea1SDimitry Andric if (CurrentOffset > Obj.Header.SymbolTableOffset) { 332*0fca6ea1SDimitry Andric reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset, 333*0fca6ea1SDimitry Andric "SymbolTableOffset"); 334*0fca6ea1SDimitry Andric return false; 335*0fca6ea1SDimitry Andric } 336*0fca6ea1SDimitry Andric CurrentOffset = Obj.Header.SymbolTableOffset; 337*0fca6ea1SDimitry Andric } 338fe6060f1SDimitry Andric InitFileHdr.SymbolTableOffset = CurrentOffset; 339fe6060f1SDimitry Andric CurrentOffset += 340fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; 341fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 342fe6060f1SDimitry Andric ErrHandler("maximum object size of " + Twine(MaxRawDataSize) + 343fe6060f1SDimitry Andric " exceeded when writing symbols"); 344fe6060f1SDimitry Andric return false; 345fe6060f1SDimitry Andric } 346fe6060f1SDimitry Andric } 347fe6060f1SDimitry Andric // TODO: Calculate FileOffsetToLineNumbers when line number supported. 348fe6060f1SDimitry Andric return true; 349fe6060f1SDimitry Andric } 350fe6060f1SDimitry Andric 351349cc55cSDimitry Andric void XCOFFWriter::initAuxFileHeader() { 352*0fca6ea1SDimitry Andric if (Obj.AuxHeader) 353349cc55cSDimitry Andric InitAuxFileHdr = *Obj.AuxHeader; 354349cc55cSDimitry Andric // In general, an object file might contain multiple sections of a given type, 355349cc55cSDimitry Andric // but in a loadable module, there must be exactly one .text, .data, .bss, and 356349cc55cSDimitry Andric // .loader section. A loadable object might also have one .tdata section and 357349cc55cSDimitry Andric // one .tbss section. 358349cc55cSDimitry Andric // Set these section-related values if not set explicitly. We assume that the 359349cc55cSDimitry Andric // input YAML matches the format of the loadable object, but if multiple input 360349cc55cSDimitry Andric // sections still have the same type, the first section with that type 361349cc55cSDimitry Andric // prevails. 362349cc55cSDimitry Andric for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 363349cc55cSDimitry Andric switch (InitSections[I].Flags) { 364349cc55cSDimitry Andric case XCOFF::STYP_TEXT: 365349cc55cSDimitry Andric if (!InitAuxFileHdr.TextSize) 366349cc55cSDimitry Andric InitAuxFileHdr.TextSize = InitSections[I].Size; 367349cc55cSDimitry Andric if (!InitAuxFileHdr.TextStartAddr) 368349cc55cSDimitry Andric InitAuxFileHdr.TextStartAddr = InitSections[I].Address; 369349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfText) 370349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfText = I + 1; 371349cc55cSDimitry Andric break; 372349cc55cSDimitry Andric case XCOFF::STYP_DATA: 373349cc55cSDimitry Andric if (!InitAuxFileHdr.InitDataSize) 374349cc55cSDimitry Andric InitAuxFileHdr.InitDataSize = InitSections[I].Size; 375349cc55cSDimitry Andric if (!InitAuxFileHdr.DataStartAddr) 376349cc55cSDimitry Andric InitAuxFileHdr.DataStartAddr = InitSections[I].Address; 377349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfData) 378349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfData = I + 1; 379349cc55cSDimitry Andric break; 380349cc55cSDimitry Andric case XCOFF::STYP_BSS: 381349cc55cSDimitry Andric if (!InitAuxFileHdr.BssDataSize) 382349cc55cSDimitry Andric InitAuxFileHdr.BssDataSize = InitSections[I].Size; 383349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfBSS) 384349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfBSS = I + 1; 385349cc55cSDimitry Andric break; 386349cc55cSDimitry Andric case XCOFF::STYP_TDATA: 387349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTData) 388349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTData = I + 1; 389349cc55cSDimitry Andric break; 390349cc55cSDimitry Andric case XCOFF::STYP_TBSS: 391349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTBSS) 392349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTBSS = I + 1; 393349cc55cSDimitry Andric break; 394349cc55cSDimitry Andric case XCOFF::STYP_LOADER: 395349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfLoader) 396349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfLoader = I + 1; 397349cc55cSDimitry Andric break; 398349cc55cSDimitry Andric default: 399349cc55cSDimitry Andric break; 400349cc55cSDimitry Andric } 401349cc55cSDimitry Andric } 402349cc55cSDimitry Andric } 403349cc55cSDimitry Andric 404fe6060f1SDimitry Andric bool XCOFFWriter::assignAddressesAndIndices() { 405349cc55cSDimitry Andric uint64_t FileHdrSize = 406349cc55cSDimitry Andric Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; 407*0fca6ea1SDimitry Andric 408*0fca6ea1SDimitry Andric // If AuxHeaderSize is specified in the YAML file, we construct 409*0fca6ea1SDimitry Andric // an auxiliary header. 410349cc55cSDimitry Andric uint64_t AuxFileHdrSize = 0; 411*0fca6ea1SDimitry Andric 412*0fca6ea1SDimitry Andric if (Obj.Header.AuxHeaderSize) 413*0fca6ea1SDimitry Andric AuxFileHdrSize = Obj.Header.AuxHeaderSize; 414*0fca6ea1SDimitry Andric else if (Obj.AuxHeader) 415*0fca6ea1SDimitry Andric AuxFileHdrSize = 416*0fca6ea1SDimitry Andric (Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32); 417349cc55cSDimitry Andric uint64_t SecHdrSize = 418349cc55cSDimitry Andric Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; 419fe6060f1SDimitry Andric uint64_t CurrentOffset = 420349cc55cSDimitry Andric FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize; 421fe6060f1SDimitry Andric 422fe6060f1SDimitry Andric // Calculate section header info. 423*0fca6ea1SDimitry Andric if (!initSectionHeaders(CurrentOffset)) 424fe6060f1SDimitry Andric return false; 425349cc55cSDimitry Andric 426fe6060f1SDimitry Andric // Calculate file header info. 427349cc55cSDimitry Andric if (!initFileHeader(CurrentOffset)) 428349cc55cSDimitry Andric return false; 429*0fca6ea1SDimitry Andric InitFileHdr.AuxHeaderSize = AuxFileHdrSize; 430349cc55cSDimitry Andric 431349cc55cSDimitry Andric // Initialize the auxiliary file header. 432*0fca6ea1SDimitry Andric if (AuxFileHdrSize) 433349cc55cSDimitry Andric initAuxFileHeader(); 434349cc55cSDimitry Andric 435349cc55cSDimitry Andric // Initialize the string table. 436349cc55cSDimitry Andric return initStringTable(); 437fe6060f1SDimitry Andric } 438fe6060f1SDimitry Andric 439fe6060f1SDimitry Andric void XCOFFWriter::writeFileHeader() { 440fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); 441fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections 442fe6060f1SDimitry Andric : InitFileHdr.NumberOfSections); 443fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.TimeStamp); 444349cc55cSDimitry Andric if (Is64Bit) { 445*0fca6ea1SDimitry Andric W.write<uint64_t>(InitFileHdr.SymbolTableOffset); 446349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 447349cc55cSDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 448349cc55cSDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 449349cc55cSDimitry Andric ? Obj.Header.NumberOfSymTableEntries 450349cc55cSDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 451349cc55cSDimitry Andric } else { 452*0fca6ea1SDimitry Andric W.write<uint32_t>(InitFileHdr.SymbolTableOffset); 453fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 454fe6060f1SDimitry Andric ? Obj.Header.NumberOfSymTableEntries 455fe6060f1SDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 456349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 457fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 458fe6060f1SDimitry Andric } 459349cc55cSDimitry Andric } 460349cc55cSDimitry Andric 461349cc55cSDimitry Andric void XCOFFWriter::writeAuxFileHeader() { 46281ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1))); 46381ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1))); 464349cc55cSDimitry Andric if (Is64Bit) { 465349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 46681ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); 46781ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); 46881ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); 469349cc55cSDimitry Andric } else { 47081ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); 47181ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); 47281ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); 47381ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); 47481ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); 47581ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); 476*0fca6ea1SDimitry Andric // A short 32-bit auxiliary header ends here. 477*0fca6ea1SDimitry Andric if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort) 478*0fca6ea1SDimitry Andric return; 47981ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); 480349cc55cSDimitry Andric } 48181ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0)); 48281ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0)); 48381ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0)); 48481ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0)); 48581ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0)); 48681ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0)); 48781ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0))); 48881ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0))); 48981ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0))); 49081ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0))); 491349cc55cSDimitry Andric W.write<uint8_t>(0); // Reserved for CPU type. 492349cc55cSDimitry Andric if (Is64Bit) { 49381ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); 49481ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); 49581ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); 496349cc55cSDimitry Andric W.write<uint8_t>( 49781ad6265SDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80))); 49881ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); 49981ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); 50081ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); 50181ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); 50281ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); 50381ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); 504349cc55cSDimitry Andric } else { 50581ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); 50681ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); 507349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 50881ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); 50981ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); 51081ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); 511349cc55cSDimitry Andric W.write<uint8_t>( 51281ad6265SDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0))); 513349cc55cSDimitry Andric } 51481ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0)); 51581ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0)); 516349cc55cSDimitry Andric if (Is64Bit) { 51781ad6265SDimitry Andric W.write<uint16_t>( 51881ad6265SDimitry Andric InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB))); 519349cc55cSDimitry Andric if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64) 520349cc55cSDimitry Andric W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64); 521*0fca6ea1SDimitry Andric } else { 522*0fca6ea1SDimitry Andric if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) 523349cc55cSDimitry Andric W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32); 524349cc55cSDimitry Andric } 525349cc55cSDimitry Andric } 526fe6060f1SDimitry Andric 527*0fca6ea1SDimitry Andric void XCOFFWriter::writeSectionHeaders() { 528fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 529fe6060f1SDimitry Andric XCOFFYAML::Section DerivedSec = InitSections[I]; 530*0fca6ea1SDimitry Andric writeName(DerivedSec.SectionName, W); 531349cc55cSDimitry Andric if (Is64Bit) { 532*0fca6ea1SDimitry Andric // Virtual address is the same as physical address. 533*0fca6ea1SDimitry Andric W.write<uint64_t>(DerivedSec.Address); // Physical address 534*0fca6ea1SDimitry Andric W.write<uint64_t>(DerivedSec.Address); // Virtual address 535*0fca6ea1SDimitry Andric W.write<uint64_t>(DerivedSec.Size); 536*0fca6ea1SDimitry Andric W.write<uint64_t>(DerivedSec.FileOffsetToData); 537*0fca6ea1SDimitry Andric W.write<uint64_t>(DerivedSec.FileOffsetToRelocations); 538*0fca6ea1SDimitry Andric W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers); 539*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.NumberOfRelocations); 540*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.NumberOfLineNumbers); 541*0fca6ea1SDimitry Andric W.write<int32_t>(DerivedSec.Flags); 542349cc55cSDimitry Andric W.OS.write_zeros(4); 543349cc55cSDimitry Andric } else { 544*0fca6ea1SDimitry Andric // Virtual address is the same as physical address. 545*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.Address); // Physical address 546*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.Address); // Virtual address 547*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.Size); 548*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.FileOffsetToData); 549*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.FileOffsetToRelocations); 550*0fca6ea1SDimitry Andric W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers); 551*0fca6ea1SDimitry Andric W.write<uint16_t>(DerivedSec.NumberOfRelocations); 552*0fca6ea1SDimitry Andric W.write<uint16_t>(DerivedSec.NumberOfLineNumbers); 553*0fca6ea1SDimitry Andric W.write<int32_t>(DerivedSec.Flags); 554fe6060f1SDimitry Andric } 555fe6060f1SDimitry Andric } 556349cc55cSDimitry Andric } 557fe6060f1SDimitry Andric 558fe6060f1SDimitry Andric bool XCOFFWriter::writeSectionData() { 559fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 560fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 561fe6060f1SDimitry Andric if (YamlSec.SectionData.binary_size()) { 562fe6060f1SDimitry Andric // Fill the padding size with zeros. 563*0fca6ea1SDimitry Andric int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData - 564*0fca6ea1SDimitry Andric (W.OS.tell() - StartOffset); 565fe6060f1SDimitry Andric if (PaddingSize < 0) { 566fe6060f1SDimitry Andric ErrHandler("redundant data was written before section data"); 567fe6060f1SDimitry Andric return false; 568fe6060f1SDimitry Andric } 569fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 570fe6060f1SDimitry Andric YamlSec.SectionData.writeAsBinary(W.OS); 571fe6060f1SDimitry Andric } 572fe6060f1SDimitry Andric } 573fe6060f1SDimitry Andric return true; 574fe6060f1SDimitry Andric } 575fe6060f1SDimitry Andric 576fe6060f1SDimitry Andric bool XCOFFWriter::writeRelocations() { 577fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 578fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 579fe6060f1SDimitry Andric if (!YamlSec.Relocations.empty()) { 580fe6060f1SDimitry Andric int64_t PaddingSize = 581fe6060f1SDimitry Andric InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset); 582fe6060f1SDimitry Andric if (PaddingSize < 0) { 583fe6060f1SDimitry Andric ErrHandler("redundant data was written before relocations"); 584fe6060f1SDimitry Andric return false; 585fe6060f1SDimitry Andric } 586fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 587fe6060f1SDimitry Andric for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { 588349cc55cSDimitry Andric if (Is64Bit) 589349cc55cSDimitry Andric W.write<uint64_t>(YamlRel.VirtualAddress); 590349cc55cSDimitry Andric else 591fe6060f1SDimitry Andric W.write<uint32_t>(YamlRel.VirtualAddress); 592fe6060f1SDimitry Andric W.write<uint32_t>(YamlRel.SymbolIndex); 593fe6060f1SDimitry Andric W.write<uint8_t>(YamlRel.Info); 594fe6060f1SDimitry Andric W.write<uint8_t>(YamlRel.Type); 595fe6060f1SDimitry Andric } 596fe6060f1SDimitry Andric } 597fe6060f1SDimitry Andric } 598fe6060f1SDimitry Andric return true; 599fe6060f1SDimitry Andric } 600fe6060f1SDimitry Andric 601*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) { 602*0fca6ea1SDimitry Andric uint8_t SymAlignAndType = 0; 603*0fca6ea1SDimitry Andric if (AuxSym.SymbolAlignmentAndType) { 604*0fca6ea1SDimitry Andric if (AuxSym.SymbolType || AuxSym.SymbolAlignment) { 605*0fca6ea1SDimitry Andric ErrHandler("cannot specify SymbolType or SymbolAlignment if " 606*0fca6ea1SDimitry Andric "SymbolAlignmentAndType is specified"); 607*0fca6ea1SDimitry Andric return false; 608*0fca6ea1SDimitry Andric } 609*0fca6ea1SDimitry Andric SymAlignAndType = *AuxSym.SymbolAlignmentAndType; 610*0fca6ea1SDimitry Andric } else { 611*0fca6ea1SDimitry Andric if (AuxSym.SymbolType) { 612*0fca6ea1SDimitry Andric uint8_t SymbolType = *AuxSym.SymbolType; 613*0fca6ea1SDimitry Andric if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) { 614*0fca6ea1SDimitry Andric ErrHandler("symbol type must be less than " + 615*0fca6ea1SDimitry Andric Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask)); 616*0fca6ea1SDimitry Andric return false; 617*0fca6ea1SDimitry Andric } 618*0fca6ea1SDimitry Andric SymAlignAndType = SymbolType; 619*0fca6ea1SDimitry Andric } 620*0fca6ea1SDimitry Andric if (AuxSym.SymbolAlignment) { 621*0fca6ea1SDimitry Andric const uint8_t ShiftedSymbolAlignmentMask = 622*0fca6ea1SDimitry Andric XCOFFCsectAuxRef::SymbolAlignmentMask >> 623*0fca6ea1SDimitry Andric XCOFFCsectAuxRef::SymbolAlignmentBitOffset; 624*0fca6ea1SDimitry Andric 625*0fca6ea1SDimitry Andric if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) { 626*0fca6ea1SDimitry Andric ErrHandler("symbol alignment must be less than " + 627*0fca6ea1SDimitry Andric Twine(1 + ShiftedSymbolAlignmentMask)); 628*0fca6ea1SDimitry Andric return false; 629*0fca6ea1SDimitry Andric } 630*0fca6ea1SDimitry Andric SymAlignAndType |= (*AuxSym.SymbolAlignment 631*0fca6ea1SDimitry Andric << XCOFFCsectAuxRef::SymbolAlignmentBitOffset); 632*0fca6ea1SDimitry Andric } 633*0fca6ea1SDimitry Andric } 63404eeddc0SDimitry Andric if (Is64Bit) { 63581ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0)); 63681ad6265SDimitry Andric W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); 63781ad6265SDimitry Andric W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); 638*0fca6ea1SDimitry Andric W.write<uint8_t>(SymAlignAndType); 63981ad6265SDimitry Andric W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); 64081ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0)); 64104eeddc0SDimitry Andric W.write<uint8_t>(0); 64204eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_CSECT); 64304eeddc0SDimitry Andric } else { 64481ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0)); 64581ad6265SDimitry Andric W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); 64681ad6265SDimitry Andric W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); 647*0fca6ea1SDimitry Andric W.write<uint8_t>(SymAlignAndType); 64881ad6265SDimitry Andric W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); 64981ad6265SDimitry Andric W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0)); 65081ad6265SDimitry Andric W.write<uint16_t>(AuxSym.StabSectNum.value_or(0)); 65104eeddc0SDimitry Andric } 652*0fca6ea1SDimitry Andric return true; 65304eeddc0SDimitry Andric } 65404eeddc0SDimitry Andric 655*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) { 65604eeddc0SDimitry Andric assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32"); 65781ad6265SDimitry Andric W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); 65881ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 65981ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 66004eeddc0SDimitry Andric W.write<uint8_t>(0); 66104eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_EXCEPT); 662*0fca6ea1SDimitry Andric return true; 66304eeddc0SDimitry Andric } 66404eeddc0SDimitry Andric 665*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) { 66604eeddc0SDimitry Andric if (Is64Bit) { 66781ad6265SDimitry Andric W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0)); 66881ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 66981ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 67004eeddc0SDimitry Andric W.write<uint8_t>(0); 67104eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_FCN); 67204eeddc0SDimitry Andric } else { 67381ad6265SDimitry Andric W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); 67481ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 67581ad6265SDimitry Andric W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0)); 67681ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 67704eeddc0SDimitry Andric W.OS.write_zeros(2); 67804eeddc0SDimitry Andric } 679*0fca6ea1SDimitry Andric return true; 68004eeddc0SDimitry Andric } 68104eeddc0SDimitry Andric 682*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) { 68381ad6265SDimitry Andric StringRef FileName = AuxSym.FileNameOrString.value_or(""); 68404eeddc0SDimitry Andric if (nameShouldBeInStringTable(FileName)) { 68504eeddc0SDimitry Andric W.write<int32_t>(0); 68604eeddc0SDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(FileName)); 68704eeddc0SDimitry Andric } else { 68804eeddc0SDimitry Andric writeName(FileName, W); 68904eeddc0SDimitry Andric } 69004eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::FileNamePadSize); 69181ad6265SDimitry Andric W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN)); 69204eeddc0SDimitry Andric if (Is64Bit) { 69304eeddc0SDimitry Andric W.OS.write_zeros(2); 69404eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_FILE); 69504eeddc0SDimitry Andric } else { 69604eeddc0SDimitry Andric W.OS.write_zeros(3); 69704eeddc0SDimitry Andric } 698*0fca6ea1SDimitry Andric return true; 69904eeddc0SDimitry Andric } 70004eeddc0SDimitry Andric 701*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) { 70204eeddc0SDimitry Andric if (Is64Bit) { 70381ad6265SDimitry Andric W.write<uint32_t>(AuxSym.LineNum.value_or(0)); 70404eeddc0SDimitry Andric W.OS.write_zeros(13); 70504eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_SYM); 70604eeddc0SDimitry Andric } else { 70704eeddc0SDimitry Andric W.OS.write_zeros(2); 70881ad6265SDimitry Andric W.write<uint16_t>(AuxSym.LineNumHi.value_or(0)); 70981ad6265SDimitry Andric W.write<uint16_t>(AuxSym.LineNumLo.value_or(0)); 71004eeddc0SDimitry Andric W.OS.write_zeros(12); 71104eeddc0SDimitry Andric } 712*0fca6ea1SDimitry Andric return true; 71304eeddc0SDimitry Andric } 71404eeddc0SDimitry Andric 715*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) { 71604eeddc0SDimitry Andric if (Is64Bit) { 71781ad6265SDimitry Andric W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0)); 71881ad6265SDimitry Andric W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 71904eeddc0SDimitry Andric W.write<uint8_t>(0); 72004eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_SECT); 72104eeddc0SDimitry Andric } else { 72281ad6265SDimitry Andric W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0)); 72304eeddc0SDimitry Andric W.OS.write_zeros(4); 72481ad6265SDimitry Andric W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 72504eeddc0SDimitry Andric W.OS.write_zeros(6); 72604eeddc0SDimitry Andric } 727*0fca6ea1SDimitry Andric return true; 72804eeddc0SDimitry Andric } 72904eeddc0SDimitry Andric 730*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) { 73104eeddc0SDimitry Andric assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64"); 73281ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionLength.value_or(0)); 73381ad6265SDimitry Andric W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 73481ad6265SDimitry Andric W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0)); 73504eeddc0SDimitry Andric W.OS.write_zeros(10); 736*0fca6ea1SDimitry Andric return true; 73704eeddc0SDimitry Andric } 73804eeddc0SDimitry Andric 739*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol( 74004eeddc0SDimitry Andric const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) { 74104eeddc0SDimitry Andric if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get())) 742*0fca6ea1SDimitry Andric return writeAuxSymbol(*AS); 74304eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get())) 744*0fca6ea1SDimitry Andric return writeAuxSymbol(*AS); 74504eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get())) 746*0fca6ea1SDimitry Andric return writeAuxSymbol(*AS); 74704eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 748*0fca6ea1SDimitry Andric return writeAuxSymbol(*AS); 74904eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get())) 750*0fca6ea1SDimitry Andric return writeAuxSymbol(*AS); 75104eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get())) 752*0fca6ea1SDimitry Andric return writeAuxSymbol(*AS); 75304eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get())) 754*0fca6ea1SDimitry Andric return writeAuxSymbol(*AS); 75504eeddc0SDimitry Andric llvm_unreachable("unknown auxiliary symbol type"); 756*0fca6ea1SDimitry Andric return false; 75704eeddc0SDimitry Andric } 75804eeddc0SDimitry Andric 759fe6060f1SDimitry Andric bool XCOFFWriter::writeSymbols() { 760fe6060f1SDimitry Andric int64_t PaddingSize = 761*0fca6ea1SDimitry Andric InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset); 762fe6060f1SDimitry Andric if (PaddingSize < 0) { 763fe6060f1SDimitry Andric ErrHandler("redundant data was written before symbols"); 764fe6060f1SDimitry Andric return false; 765fe6060f1SDimitry Andric } 766fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 767fe6060f1SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 768349cc55cSDimitry Andric if (Is64Bit) { 769349cc55cSDimitry Andric W.write<uint64_t>(YamlSym.Value); 770349cc55cSDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 771349cc55cSDimitry Andric } else { 772fe6060f1SDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 773fe6060f1SDimitry Andric // For XCOFF32: A value of 0 indicates that the symbol name is in the 774fe6060f1SDimitry Andric // string table. 775fe6060f1SDimitry Andric W.write<int32_t>(0); 776349cc55cSDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 777fe6060f1SDimitry Andric } else { 778fe6060f1SDimitry Andric writeName(YamlSym.SymbolName, W); 779fe6060f1SDimitry Andric } 780fe6060f1SDimitry Andric W.write<uint32_t>(YamlSym.Value); 781349cc55cSDimitry Andric } 782349cc55cSDimitry Andric if (YamlSym.SectionName) { 783349cc55cSDimitry Andric if (!SectionIndexMap.count(*YamlSym.SectionName)) { 784349cc55cSDimitry Andric ErrHandler("the SectionName " + *YamlSym.SectionName + 785349cc55cSDimitry Andric " specified in the symbol does not exist"); 786349cc55cSDimitry Andric return false; 787349cc55cSDimitry Andric } 788349cc55cSDimitry Andric if (YamlSym.SectionIndex && 789349cc55cSDimitry Andric SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) { 790349cc55cSDimitry Andric ErrHandler("the SectionName " + *YamlSym.SectionName + 791349cc55cSDimitry Andric " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) + 792349cc55cSDimitry Andric ") refer to different sections"); 793349cc55cSDimitry Andric return false; 794349cc55cSDimitry Andric } 795349cc55cSDimitry Andric W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]); 796349cc55cSDimitry Andric } else { 797349cc55cSDimitry Andric W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0); 798349cc55cSDimitry Andric } 799fe6060f1SDimitry Andric W.write<uint16_t>(YamlSym.Type); 800fe6060f1SDimitry Andric W.write<uint8_t>(YamlSym.StorageClass); 801fe6060f1SDimitry Andric 80281ad6265SDimitry Andric uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0); 80304eeddc0SDimitry Andric W.write<uint8_t>(NumOfAuxSym); 80404eeddc0SDimitry Andric 80504eeddc0SDimitry Andric if (!NumOfAuxSym && !YamlSym.AuxEntries.size()) 80604eeddc0SDimitry Andric continue; 80704eeddc0SDimitry Andric 80804eeddc0SDimitry Andric // Now write auxiliary entries. 80904eeddc0SDimitry Andric if (!YamlSym.AuxEntries.size()) { 81004eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym); 81104eeddc0SDimitry Andric } else { 81204eeddc0SDimitry Andric for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 81304eeddc0SDimitry Andric YamlSym.AuxEntries) { 814*0fca6ea1SDimitry Andric if (!writeAuxSymbol(AuxSym)) 815*0fca6ea1SDimitry Andric return false; 81604eeddc0SDimitry Andric } 81704eeddc0SDimitry Andric // Pad with zeros. 81804eeddc0SDimitry Andric if (NumOfAuxSym > YamlSym.AuxEntries.size()) 81904eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::SymbolTableEntrySize * 82004eeddc0SDimitry Andric (NumOfAuxSym - YamlSym.AuxEntries.size())); 821fe6060f1SDimitry Andric } 822fe6060f1SDimitry Andric } 823fe6060f1SDimitry Andric return true; 824fe6060f1SDimitry Andric } 825fe6060f1SDimitry Andric 826349cc55cSDimitry Andric void XCOFFWriter::writeStringTable() { 827349cc55cSDimitry Andric if (Obj.StrTbl.RawContent) { 828349cc55cSDimitry Andric Obj.StrTbl.RawContent->writeAsBinary(W.OS); 829349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize) { 830349cc55cSDimitry Andric assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() && 831349cc55cSDimitry Andric "Specified ContentSize is less than the RawContent size."); 832349cc55cSDimitry Andric W.OS.write_zeros(*Obj.StrTbl.ContentSize - 833349cc55cSDimitry Andric Obj.StrTbl.RawContent->binary_size()); 834fe6060f1SDimitry Andric } 835349cc55cSDimitry Andric return; 836349cc55cSDimitry Andric } 837349cc55cSDimitry Andric 838349cc55cSDimitry Andric size_t StrTblBuilderSize = StrTblBuilder.getSize(); 839349cc55cSDimitry Andric // If neither Length nor ContentSize is specified, write the StrTblBuilder 840349cc55cSDimitry Andric // directly, which contains the auto-generated Length value. 841349cc55cSDimitry Andric if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) { 842349cc55cSDimitry Andric if (StrTblBuilderSize <= 4) 843349cc55cSDimitry Andric return; 844349cc55cSDimitry Andric StrTblBuilder.write(W.OS); 845349cc55cSDimitry Andric return; 846349cc55cSDimitry Andric } 847349cc55cSDimitry Andric 848349cc55cSDimitry Andric // Serialize the string table's content to a temporary buffer. 849349cc55cSDimitry Andric std::unique_ptr<WritableMemoryBuffer> Buf = 850349cc55cSDimitry Andric WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize); 851349cc55cSDimitry Andric uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); 852349cc55cSDimitry Andric StrTblBuilder.write(Ptr); 853349cc55cSDimitry Andric // Replace the first 4 bytes, which contain the auto-generated Length value, 854349cc55cSDimitry Andric // with the specified value. 855349cc55cSDimitry Andric memset(Ptr, 0, 4); 856349cc55cSDimitry Andric support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length 857349cc55cSDimitry Andric : *Obj.StrTbl.ContentSize); 858349cc55cSDimitry Andric // Copy the buffer content to the actual output stream. 859349cc55cSDimitry Andric W.OS.write(Buf->getBufferStart(), Buf->getBufferSize()); 860349cc55cSDimitry Andric // Add zeros as padding after strings. 861349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize) { 862349cc55cSDimitry Andric assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize && 863349cc55cSDimitry Andric "Specified ContentSize is less than the StringTableBuilder size."); 864349cc55cSDimitry Andric W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); 865349cc55cSDimitry Andric } 866349cc55cSDimitry Andric } 867349cc55cSDimitry Andric 868349cc55cSDimitry Andric bool XCOFFWriter::writeXCOFF() { 869fe6060f1SDimitry Andric if (!assignAddressesAndIndices()) 870fe6060f1SDimitry Andric return false; 871fe6060f1SDimitry Andric StartOffset = W.OS.tell(); 872fe6060f1SDimitry Andric writeFileHeader(); 873*0fca6ea1SDimitry Andric if (InitFileHdr.AuxHeaderSize) 874349cc55cSDimitry Andric writeAuxFileHeader(); 875fe6060f1SDimitry Andric if (!Obj.Sections.empty()) { 876*0fca6ea1SDimitry Andric writeSectionHeaders(); 877fe6060f1SDimitry Andric if (!writeSectionData()) 878fe6060f1SDimitry Andric return false; 879fe6060f1SDimitry Andric if (!writeRelocations()) 880fe6060f1SDimitry Andric return false; 881fe6060f1SDimitry Andric } 882fe6060f1SDimitry Andric if (!Obj.Symbols.empty() && !writeSymbols()) 883fe6060f1SDimitry Andric return false; 884349cc55cSDimitry Andric writeStringTable(); 885fe6060f1SDimitry Andric return true; 886fe6060f1SDimitry Andric } 887fe6060f1SDimitry Andric 888fe6060f1SDimitry Andric } // end anonymous namespace 889fe6060f1SDimitry Andric 890fe6060f1SDimitry Andric namespace llvm { 891fe6060f1SDimitry Andric namespace yaml { 892fe6060f1SDimitry Andric 893fe6060f1SDimitry Andric bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { 894fe6060f1SDimitry Andric XCOFFWriter Writer(Doc, Out, EH); 895fe6060f1SDimitry Andric return Writer.writeXCOFF(); 896fe6060f1SDimitry Andric } 897fe6060f1SDimitry Andric 898fe6060f1SDimitry Andric } // namespace yaml 899fe6060f1SDimitry Andric } // namespace llvm 900