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; 26fe6060f1SDimitry Andric 27fe6060f1SDimitry Andric namespace { 28fe6060f1SDimitry Andric 29fe6060f1SDimitry Andric constexpr unsigned DefaultSectionAlign = 4; 30fe6060f1SDimitry Andric constexpr int16_t MaxSectionIndex = INT16_MAX; 31fe6060f1SDimitry Andric constexpr uint32_t MaxRawDataSize = UINT32_MAX; 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric class XCOFFWriter { 34fe6060f1SDimitry Andric public: 35fe6060f1SDimitry Andric XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH) 36fe6060f1SDimitry Andric : Obj(Obj), W(OS, support::big), ErrHandler(EH), 37349cc55cSDimitry Andric StrTblBuilder(StringTableBuilder::XCOFF) { 38fe6060f1SDimitry Andric Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64; 39fe6060f1SDimitry Andric } 40fe6060f1SDimitry Andric bool writeXCOFF(); 41fe6060f1SDimitry Andric 42fe6060f1SDimitry Andric private: 43fe6060f1SDimitry Andric bool nameShouldBeInStringTable(StringRef SymbolName); 44fe6060f1SDimitry Andric bool initFileHeader(uint64_t CurrentOffset); 45349cc55cSDimitry Andric void initAuxFileHeader(); 46fe6060f1SDimitry Andric bool initSectionHeader(uint64_t &CurrentOffset); 47fe6060f1SDimitry Andric bool initRelocations(uint64_t &CurrentOffset); 48349cc55cSDimitry Andric bool initStringTable(); 49fe6060f1SDimitry Andric bool assignAddressesAndIndices(); 50fe6060f1SDimitry Andric void writeFileHeader(); 51349cc55cSDimitry Andric void writeAuxFileHeader(); 52fe6060f1SDimitry Andric void writeSectionHeader(); 53fe6060f1SDimitry Andric bool writeSectionData(); 54fe6060f1SDimitry Andric bool writeRelocations(); 55fe6060f1SDimitry Andric bool writeSymbols(); 56349cc55cSDimitry Andric void writeStringTable(); 57fe6060f1SDimitry Andric 58fe6060f1SDimitry Andric XCOFFYAML::Object &Obj; 59fe6060f1SDimitry Andric bool Is64Bit = false; 60fe6060f1SDimitry Andric support::endian::Writer W; 61fe6060f1SDimitry Andric yaml::ErrorHandler ErrHandler; 62349cc55cSDimitry Andric StringTableBuilder StrTblBuilder; 63fe6060f1SDimitry Andric uint64_t StartOffset; 64fe6060f1SDimitry Andric // Map the section name to its corrresponding section index. 65fe6060f1SDimitry Andric DenseMap<StringRef, int16_t> SectionIndexMap = { 66fe6060f1SDimitry Andric {StringRef("N_DEBUG"), XCOFF::N_DEBUG}, 67fe6060f1SDimitry Andric {StringRef("N_ABS"), XCOFF::N_ABS}, 68fe6060f1SDimitry Andric {StringRef("N_UNDEF"), XCOFF::N_UNDEF}}; 69fe6060f1SDimitry Andric XCOFFYAML::FileHeader InitFileHdr = Obj.Header; 70349cc55cSDimitry Andric XCOFFYAML::AuxiliaryHeader InitAuxFileHdr; 71fe6060f1SDimitry Andric std::vector<XCOFFYAML::Section> InitSections = Obj.Sections; 72fe6060f1SDimitry Andric }; 73fe6060f1SDimitry Andric 74fe6060f1SDimitry Andric static void writeName(StringRef StrName, support::endian::Writer W) { 75fe6060f1SDimitry Andric char Name[XCOFF::NameSize]; 76fe6060f1SDimitry Andric memset(Name, 0, XCOFF::NameSize); 77fe6060f1SDimitry Andric char SrcName[] = ""; 78fe6060f1SDimitry Andric memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size()); 79fe6060f1SDimitry Andric ArrayRef<char> NameRef(Name, XCOFF::NameSize); 80fe6060f1SDimitry Andric W.write(NameRef); 81fe6060f1SDimitry Andric } 82fe6060f1SDimitry Andric 83fe6060f1SDimitry Andric bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { 84349cc55cSDimitry Andric // For XCOFF64: The symbol name is always in the string table. 85349cc55cSDimitry Andric return (SymbolName.size() > XCOFF::NameSize) || Is64Bit; 86fe6060f1SDimitry Andric } 87fe6060f1SDimitry Andric 88fe6060f1SDimitry Andric bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { 89*0eae32dcSDimitry Andric for (XCOFFYAML::Section &InitSection : InitSections) { 90*0eae32dcSDimitry Andric if (!InitSection.Relocations.empty()) { 91*0eae32dcSDimitry Andric InitSection.NumberOfRelocations = InitSection.Relocations.size(); 92*0eae32dcSDimitry Andric InitSection.FileOffsetToRelocations = CurrentOffset; 93349cc55cSDimitry Andric uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64 94349cc55cSDimitry Andric : XCOFF::RelocationSerializationSize32; 95*0eae32dcSDimitry Andric CurrentOffset += InitSection.NumberOfRelocations * RelSize; 96fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 97fe6060f1SDimitry Andric ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 98fe6060f1SDimitry Andric "exceeded when writing relocation data"); 99fe6060f1SDimitry Andric return false; 100fe6060f1SDimitry Andric } 101fe6060f1SDimitry Andric } 102fe6060f1SDimitry Andric } 103fe6060f1SDimitry Andric return true; 104fe6060f1SDimitry Andric } 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) { 107fe6060f1SDimitry Andric uint64_t CurrentSecAddr = 0; 108fe6060f1SDimitry Andric for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 109fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 110fe6060f1SDimitry Andric ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 111fe6060f1SDimitry Andric "exceeded when writing section data"); 112fe6060f1SDimitry Andric return false; 113fe6060f1SDimitry Andric } 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric // Assign indices for sections. 116fe6060f1SDimitry Andric if (InitSections[I].SectionName.size() && 117fe6060f1SDimitry Andric !SectionIndexMap[InitSections[I].SectionName]) { 118fe6060f1SDimitry Andric // The section index starts from 1. 119fe6060f1SDimitry Andric SectionIndexMap[InitSections[I].SectionName] = I + 1; 120fe6060f1SDimitry Andric if ((I + 1) > MaxSectionIndex) { 121fe6060f1SDimitry Andric ErrHandler("exceeded the maximum permitted section index of " + 122fe6060f1SDimitry Andric Twine(MaxSectionIndex)); 123fe6060f1SDimitry Andric return false; 124fe6060f1SDimitry Andric } 125fe6060f1SDimitry Andric } 126fe6060f1SDimitry Andric 127fe6060f1SDimitry Andric // Calculate the physical/virtual address. This field should contain 0 for 128fe6060f1SDimitry Andric // all sections except the text, data and bss sections. 129fe6060f1SDimitry Andric if (InitSections[I].Flags != XCOFF::STYP_TEXT && 130fe6060f1SDimitry Andric InitSections[I].Flags != XCOFF::STYP_DATA && 131fe6060f1SDimitry Andric InitSections[I].Flags != XCOFF::STYP_BSS) 132fe6060f1SDimitry Andric InitSections[I].Address = 0; 133fe6060f1SDimitry Andric else 134fe6060f1SDimitry Andric InitSections[I].Address = CurrentSecAddr; 135fe6060f1SDimitry Andric 136fe6060f1SDimitry Andric // Calculate the FileOffsetToData and data size for sections. 137fe6060f1SDimitry Andric if (InitSections[I].SectionData.binary_size()) { 138fe6060f1SDimitry Andric InitSections[I].FileOffsetToData = CurrentOffset; 139fe6060f1SDimitry Andric CurrentOffset += InitSections[I].SectionData.binary_size(); 140fe6060f1SDimitry Andric // Ensure the offset is aligned to DefaultSectionAlign. 141fe6060f1SDimitry Andric CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign); 142fe6060f1SDimitry Andric InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData; 143fe6060f1SDimitry Andric CurrentSecAddr += InitSections[I].Size; 144fe6060f1SDimitry Andric } 145fe6060f1SDimitry Andric } 146fe6060f1SDimitry Andric return initRelocations(CurrentOffset); 147fe6060f1SDimitry Andric } 148fe6060f1SDimitry Andric 149349cc55cSDimitry Andric bool XCOFFWriter::initStringTable() { 150349cc55cSDimitry Andric if (Obj.StrTbl.RawContent) { 151349cc55cSDimitry Andric size_t RawSize = Obj.StrTbl.RawContent->binary_size(); 152349cc55cSDimitry Andric if (Obj.StrTbl.Strings || Obj.StrTbl.Length) { 153349cc55cSDimitry Andric ErrHandler( 154349cc55cSDimitry Andric "can't specify Strings or Length when RawContent is specified"); 155349cc55cSDimitry Andric return false; 156349cc55cSDimitry Andric } 157349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) { 158349cc55cSDimitry Andric ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 159349cc55cSDimitry Andric ") is less than the RawContent data size (" + Twine(RawSize) + 160349cc55cSDimitry Andric ")"); 161349cc55cSDimitry Andric return false; 162349cc55cSDimitry Andric } 163349cc55cSDimitry Andric return true; 164349cc55cSDimitry Andric } 165349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) { 166349cc55cSDimitry Andric ErrHandler("ContentSize shouldn't be less than 4 without RawContent"); 167349cc55cSDimitry Andric return false; 168349cc55cSDimitry Andric } 169349cc55cSDimitry Andric 170349cc55cSDimitry Andric // Build the string table. 171349cc55cSDimitry Andric StrTblBuilder.clear(); 172349cc55cSDimitry Andric 173349cc55cSDimitry Andric if (Obj.StrTbl.Strings) { 174349cc55cSDimitry Andric // All specified strings should be added to the string table. 175349cc55cSDimitry Andric for (StringRef StringEnt : *Obj.StrTbl.Strings) 176349cc55cSDimitry Andric StrTblBuilder.add(StringEnt); 177349cc55cSDimitry Andric 178349cc55cSDimitry Andric size_t StrTblIdx = 0; 179349cc55cSDimitry Andric size_t NumOfStrings = Obj.StrTbl.Strings->size(); 180349cc55cSDimitry Andric for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 181349cc55cSDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 182349cc55cSDimitry Andric if (StrTblIdx < NumOfStrings) { 183349cc55cSDimitry Andric // Overwrite the symbol name with the specified string. 184349cc55cSDimitry Andric YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx]; 185349cc55cSDimitry Andric ++StrTblIdx; 186349cc55cSDimitry Andric } else 187349cc55cSDimitry Andric // Names that are not overwritten are still stored in the string 188349cc55cSDimitry Andric // table. 189349cc55cSDimitry Andric StrTblBuilder.add(YamlSym.SymbolName); 190349cc55cSDimitry Andric } 191349cc55cSDimitry Andric } 192349cc55cSDimitry Andric } else { 193349cc55cSDimitry Andric for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 194349cc55cSDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) 195349cc55cSDimitry Andric StrTblBuilder.add(YamlSym.SymbolName); 196349cc55cSDimitry Andric } 197349cc55cSDimitry Andric } 198349cc55cSDimitry Andric 199349cc55cSDimitry Andric StrTblBuilder.finalize(); 200349cc55cSDimitry Andric 201349cc55cSDimitry Andric size_t StrTblSize = StrTblBuilder.getSize(); 202349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) { 203349cc55cSDimitry Andric ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 204349cc55cSDimitry Andric ") is less than the size of the data that would otherwise be " 205349cc55cSDimitry Andric "written (" + 206349cc55cSDimitry Andric Twine(StrTblSize) + ")"); 207349cc55cSDimitry Andric return false; 208349cc55cSDimitry Andric } 209349cc55cSDimitry Andric 210349cc55cSDimitry Andric return true; 211349cc55cSDimitry Andric } 212349cc55cSDimitry Andric 213fe6060f1SDimitry Andric bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { 214fe6060f1SDimitry Andric // The default format of the object file is XCOFF32. 215fe6060f1SDimitry Andric InitFileHdr.Magic = XCOFF::XCOFF32; 216fe6060f1SDimitry Andric InitFileHdr.NumberOfSections = Obj.Sections.size(); 217fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); 218fe6060f1SDimitry Andric 219349cc55cSDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) 220fe6060f1SDimitry Andric // Add the number of auxiliary symbols to the total number. 221fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries; 222fe6060f1SDimitry Andric 223fe6060f1SDimitry Andric // Calculate SymbolTableOffset for the file header. 224fe6060f1SDimitry Andric if (InitFileHdr.NumberOfSymTableEntries) { 225fe6060f1SDimitry Andric InitFileHdr.SymbolTableOffset = CurrentOffset; 226fe6060f1SDimitry Andric CurrentOffset += 227fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; 228fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 229fe6060f1SDimitry Andric ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 230fe6060f1SDimitry Andric "exceeded when writing symbols"); 231fe6060f1SDimitry Andric return false; 232fe6060f1SDimitry Andric } 233fe6060f1SDimitry Andric } 234fe6060f1SDimitry Andric // TODO: Calculate FileOffsetToLineNumbers when line number supported. 235fe6060f1SDimitry Andric return true; 236fe6060f1SDimitry Andric } 237fe6060f1SDimitry Andric 238349cc55cSDimitry Andric void XCOFFWriter::initAuxFileHeader() { 239349cc55cSDimitry Andric InitAuxFileHdr = *Obj.AuxHeader; 240349cc55cSDimitry Andric // In general, an object file might contain multiple sections of a given type, 241349cc55cSDimitry Andric // but in a loadable module, there must be exactly one .text, .data, .bss, and 242349cc55cSDimitry Andric // .loader section. A loadable object might also have one .tdata section and 243349cc55cSDimitry Andric // one .tbss section. 244349cc55cSDimitry Andric // Set these section-related values if not set explicitly. We assume that the 245349cc55cSDimitry Andric // input YAML matches the format of the loadable object, but if multiple input 246349cc55cSDimitry Andric // sections still have the same type, the first section with that type 247349cc55cSDimitry Andric // prevails. 248349cc55cSDimitry Andric for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 249349cc55cSDimitry Andric switch (InitSections[I].Flags) { 250349cc55cSDimitry Andric case XCOFF::STYP_TEXT: 251349cc55cSDimitry Andric if (!InitAuxFileHdr.TextSize) 252349cc55cSDimitry Andric InitAuxFileHdr.TextSize = InitSections[I].Size; 253349cc55cSDimitry Andric if (!InitAuxFileHdr.TextStartAddr) 254349cc55cSDimitry Andric InitAuxFileHdr.TextStartAddr = InitSections[I].Address; 255349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfText) 256349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfText = I + 1; 257349cc55cSDimitry Andric break; 258349cc55cSDimitry Andric case XCOFF::STYP_DATA: 259349cc55cSDimitry Andric if (!InitAuxFileHdr.InitDataSize) 260349cc55cSDimitry Andric InitAuxFileHdr.InitDataSize = InitSections[I].Size; 261349cc55cSDimitry Andric if (!InitAuxFileHdr.DataStartAddr) 262349cc55cSDimitry Andric InitAuxFileHdr.DataStartAddr = InitSections[I].Address; 263349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfData) 264349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfData = I + 1; 265349cc55cSDimitry Andric break; 266349cc55cSDimitry Andric case XCOFF::STYP_BSS: 267349cc55cSDimitry Andric if (!InitAuxFileHdr.BssDataSize) 268349cc55cSDimitry Andric InitAuxFileHdr.BssDataSize = InitSections[I].Size; 269349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfBSS) 270349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfBSS = I + 1; 271349cc55cSDimitry Andric break; 272349cc55cSDimitry Andric case XCOFF::STYP_TDATA: 273349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTData) 274349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTData = I + 1; 275349cc55cSDimitry Andric break; 276349cc55cSDimitry Andric case XCOFF::STYP_TBSS: 277349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTBSS) 278349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTBSS = I + 1; 279349cc55cSDimitry Andric break; 280349cc55cSDimitry Andric case XCOFF::STYP_LOADER: 281349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfLoader) 282349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfLoader = I + 1; 283349cc55cSDimitry Andric break; 284349cc55cSDimitry Andric default: 285349cc55cSDimitry Andric break; 286349cc55cSDimitry Andric } 287349cc55cSDimitry Andric } 288349cc55cSDimitry Andric } 289349cc55cSDimitry Andric 290fe6060f1SDimitry Andric bool XCOFFWriter::assignAddressesAndIndices() { 291349cc55cSDimitry Andric uint64_t FileHdrSize = 292349cc55cSDimitry Andric Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; 293349cc55cSDimitry Andric uint64_t AuxFileHdrSize = 0; 294349cc55cSDimitry Andric if (Obj.AuxHeader) 295349cc55cSDimitry Andric AuxFileHdrSize = Obj.Header.AuxHeaderSize 296349cc55cSDimitry Andric ? Obj.Header.AuxHeaderSize 297349cc55cSDimitry Andric : (Is64Bit ? XCOFF::AuxFileHeaderSize64 298349cc55cSDimitry Andric : XCOFF::AuxFileHeaderSize32); 299349cc55cSDimitry Andric uint64_t SecHdrSize = 300349cc55cSDimitry Andric Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; 301fe6060f1SDimitry Andric uint64_t CurrentOffset = 302349cc55cSDimitry Andric FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize; 303fe6060f1SDimitry Andric 304fe6060f1SDimitry Andric // Calculate section header info. 305fe6060f1SDimitry Andric if (!initSectionHeader(CurrentOffset)) 306fe6060f1SDimitry Andric return false; 307349cc55cSDimitry Andric InitFileHdr.AuxHeaderSize = AuxFileHdrSize; 308349cc55cSDimitry Andric 309fe6060f1SDimitry Andric // Calculate file header info. 310349cc55cSDimitry Andric if (!initFileHeader(CurrentOffset)) 311349cc55cSDimitry Andric return false; 312349cc55cSDimitry Andric 313349cc55cSDimitry Andric // Initialize the auxiliary file header. 314349cc55cSDimitry Andric if (Obj.AuxHeader) 315349cc55cSDimitry Andric initAuxFileHeader(); 316349cc55cSDimitry Andric 317349cc55cSDimitry Andric // Initialize the string table. 318349cc55cSDimitry Andric return initStringTable(); 319fe6060f1SDimitry Andric } 320fe6060f1SDimitry Andric 321fe6060f1SDimitry Andric void XCOFFWriter::writeFileHeader() { 322fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); 323fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections 324fe6060f1SDimitry Andric : InitFileHdr.NumberOfSections); 325fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.TimeStamp); 326349cc55cSDimitry Andric if (Is64Bit) { 327349cc55cSDimitry Andric W.write<uint64_t>(Obj.Header.SymbolTableOffset 328349cc55cSDimitry Andric ? Obj.Header.SymbolTableOffset 329349cc55cSDimitry Andric : InitFileHdr.SymbolTableOffset); 330349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 331349cc55cSDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 332349cc55cSDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 333349cc55cSDimitry Andric ? Obj.Header.NumberOfSymTableEntries 334349cc55cSDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 335349cc55cSDimitry Andric } else { 336fe6060f1SDimitry Andric W.write<uint32_t>(Obj.Header.SymbolTableOffset 337fe6060f1SDimitry Andric ? Obj.Header.SymbolTableOffset 338fe6060f1SDimitry Andric : InitFileHdr.SymbolTableOffset); 339fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 340fe6060f1SDimitry Andric ? Obj.Header.NumberOfSymTableEntries 341fe6060f1SDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 342349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 343fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 344fe6060f1SDimitry Andric } 345349cc55cSDimitry Andric } 346349cc55cSDimitry Andric 347349cc55cSDimitry Andric void XCOFFWriter::writeAuxFileHeader() { 348349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Magic.getValueOr(yaml::Hex16(1))); 349349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Version.getValueOr(yaml::Hex16(1))); 350349cc55cSDimitry Andric if (Is64Bit) { 351349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 352349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0))); 353349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0))); 354349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0))); 355349cc55cSDimitry Andric } else { 356349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0))); 357349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0))); 358349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0))); 359349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0))); 360349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0))); 361349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0))); 362349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0))); 363349cc55cSDimitry Andric } 364349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.getValueOr(0)); 365349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.getValueOr(0)); 366349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.getValueOr(0)); 367349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.getValueOr(0)); 368349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.getValueOr(0)); 369349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.getValueOr(0)); 370349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.getValueOr(yaml::Hex16(0))); 371349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.getValueOr(yaml::Hex16(0))); 372349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.ModuleType.getValueOr(yaml::Hex16(0))); 373349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.CpuFlag.getValueOr(yaml::Hex8(0))); 374349cc55cSDimitry Andric W.write<uint8_t>(0); // Reserved for CPU type. 375349cc55cSDimitry Andric if (Is64Bit) { 376349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0))); 377349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0))); 378349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0))); 379349cc55cSDimitry Andric W.write<uint8_t>( 380349cc55cSDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0x80))); 381349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0))); 382349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0))); 383349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0))); 384349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0))); 385349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0))); 386349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0))); 387349cc55cSDimitry Andric } else { 388349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0))); 389349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0))); 390349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 391349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0))); 392349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0))); 393349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0))); 394349cc55cSDimitry Andric W.write<uint8_t>( 395349cc55cSDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0))); 396349cc55cSDimitry Andric } 397349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.getValueOr(0)); 398349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.getValueOr(0)); 399349cc55cSDimitry Andric if (Is64Bit) { 400349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Flag.getValueOr(yaml::Hex16(XCOFF::SHR_SYMTAB))); 401349cc55cSDimitry Andric if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64) 402349cc55cSDimitry Andric W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64); 403349cc55cSDimitry Andric } else if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) { 404349cc55cSDimitry Andric W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32); 405349cc55cSDimitry Andric } 406349cc55cSDimitry Andric } 407fe6060f1SDimitry Andric 408fe6060f1SDimitry Andric void XCOFFWriter::writeSectionHeader() { 409fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 410fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 411fe6060f1SDimitry Andric XCOFFYAML::Section DerivedSec = InitSections[I]; 412fe6060f1SDimitry Andric writeName(YamlSec.SectionName, W); 413fe6060f1SDimitry Andric // Virtual address is the same as physical address. 414349cc55cSDimitry Andric uint64_t SectionAddress = 415fe6060f1SDimitry Andric YamlSec.Address ? YamlSec.Address : DerivedSec.Address; 416349cc55cSDimitry Andric if (Is64Bit) { 417349cc55cSDimitry Andric W.write<uint64_t>(SectionAddress); // Physical address 418349cc55cSDimitry Andric W.write<uint64_t>(SectionAddress); // Virtual address 419349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); 420349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData 421349cc55cSDimitry Andric : DerivedSec.FileOffsetToData); 422349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.FileOffsetToRelocations 423349cc55cSDimitry Andric ? YamlSec.FileOffsetToRelocations 424349cc55cSDimitry Andric : DerivedSec.FileOffsetToRelocations); 425349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers); 426349cc55cSDimitry Andric W.write<uint32_t>(YamlSec.NumberOfRelocations 427349cc55cSDimitry Andric ? YamlSec.NumberOfRelocations 428349cc55cSDimitry Andric : DerivedSec.NumberOfRelocations); 429349cc55cSDimitry Andric W.write<uint32_t>(YamlSec.NumberOfLineNumbers); 430349cc55cSDimitry Andric W.write<int32_t>(YamlSec.Flags); 431349cc55cSDimitry Andric W.OS.write_zeros(4); 432349cc55cSDimitry Andric } else { 433fe6060f1SDimitry Andric W.write<uint32_t>(SectionAddress); // Physical address 434fe6060f1SDimitry Andric W.write<uint32_t>(SectionAddress); // Virtual address 435fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); 436fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData 437fe6060f1SDimitry Andric : DerivedSec.FileOffsetToData); 438fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.FileOffsetToRelocations 439fe6060f1SDimitry Andric ? YamlSec.FileOffsetToRelocations 440fe6060f1SDimitry Andric : DerivedSec.FileOffsetToRelocations); 441fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers); 442fe6060f1SDimitry Andric W.write<uint16_t>(YamlSec.NumberOfRelocations 443fe6060f1SDimitry Andric ? YamlSec.NumberOfRelocations 444fe6060f1SDimitry Andric : DerivedSec.NumberOfRelocations); 445fe6060f1SDimitry Andric W.write<uint16_t>(YamlSec.NumberOfLineNumbers); 446fe6060f1SDimitry Andric W.write<int32_t>(YamlSec.Flags); 447fe6060f1SDimitry Andric } 448fe6060f1SDimitry Andric } 449349cc55cSDimitry Andric } 450fe6060f1SDimitry Andric 451fe6060f1SDimitry Andric bool XCOFFWriter::writeSectionData() { 452fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 453fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 454fe6060f1SDimitry Andric if (YamlSec.SectionData.binary_size()) { 455fe6060f1SDimitry Andric // Fill the padding size with zeros. 456fe6060f1SDimitry Andric int64_t PaddingSize = 457fe6060f1SDimitry Andric InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset); 458fe6060f1SDimitry Andric if (PaddingSize < 0) { 459fe6060f1SDimitry Andric ErrHandler("redundant data was written before section data"); 460fe6060f1SDimitry Andric return false; 461fe6060f1SDimitry Andric } 462fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 463fe6060f1SDimitry Andric YamlSec.SectionData.writeAsBinary(W.OS); 464fe6060f1SDimitry Andric } 465fe6060f1SDimitry Andric } 466fe6060f1SDimitry Andric return true; 467fe6060f1SDimitry Andric } 468fe6060f1SDimitry Andric 469fe6060f1SDimitry Andric bool XCOFFWriter::writeRelocations() { 470fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 471fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 472fe6060f1SDimitry Andric if (!YamlSec.Relocations.empty()) { 473fe6060f1SDimitry Andric int64_t PaddingSize = 474fe6060f1SDimitry Andric InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset); 475fe6060f1SDimitry Andric if (PaddingSize < 0) { 476fe6060f1SDimitry Andric ErrHandler("redundant data was written before relocations"); 477fe6060f1SDimitry Andric return false; 478fe6060f1SDimitry Andric } 479fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 480fe6060f1SDimitry Andric for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { 481349cc55cSDimitry Andric if (Is64Bit) 482349cc55cSDimitry Andric W.write<uint64_t>(YamlRel.VirtualAddress); 483349cc55cSDimitry Andric else 484fe6060f1SDimitry Andric W.write<uint32_t>(YamlRel.VirtualAddress); 485fe6060f1SDimitry Andric W.write<uint32_t>(YamlRel.SymbolIndex); 486fe6060f1SDimitry Andric W.write<uint8_t>(YamlRel.Info); 487fe6060f1SDimitry Andric W.write<uint8_t>(YamlRel.Type); 488fe6060f1SDimitry Andric } 489fe6060f1SDimitry Andric } 490fe6060f1SDimitry Andric } 491fe6060f1SDimitry Andric return true; 492fe6060f1SDimitry Andric } 493fe6060f1SDimitry Andric 494fe6060f1SDimitry Andric bool XCOFFWriter::writeSymbols() { 495fe6060f1SDimitry Andric int64_t PaddingSize = 496fe6060f1SDimitry Andric (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset); 497fe6060f1SDimitry Andric if (PaddingSize < 0) { 498fe6060f1SDimitry Andric ErrHandler("redundant data was written before symbols"); 499fe6060f1SDimitry Andric return false; 500fe6060f1SDimitry Andric } 501fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 502fe6060f1SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 503349cc55cSDimitry Andric if (Is64Bit) { 504349cc55cSDimitry Andric W.write<uint64_t>(YamlSym.Value); 505349cc55cSDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 506349cc55cSDimitry Andric } else { 507fe6060f1SDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 508fe6060f1SDimitry Andric // For XCOFF32: A value of 0 indicates that the symbol name is in the 509fe6060f1SDimitry Andric // string table. 510fe6060f1SDimitry Andric W.write<int32_t>(0); 511349cc55cSDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 512fe6060f1SDimitry Andric } else { 513fe6060f1SDimitry Andric writeName(YamlSym.SymbolName, W); 514fe6060f1SDimitry Andric } 515fe6060f1SDimitry Andric W.write<uint32_t>(YamlSym.Value); 516349cc55cSDimitry Andric } 517349cc55cSDimitry Andric if (YamlSym.SectionName) { 518349cc55cSDimitry Andric if (!SectionIndexMap.count(*YamlSym.SectionName)) { 519349cc55cSDimitry Andric ErrHandler("the SectionName " + *YamlSym.SectionName + 520349cc55cSDimitry Andric " specified in the symbol does not exist"); 521349cc55cSDimitry Andric return false; 522349cc55cSDimitry Andric } 523349cc55cSDimitry Andric if (YamlSym.SectionIndex && 524349cc55cSDimitry Andric SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) { 525349cc55cSDimitry Andric ErrHandler("the SectionName " + *YamlSym.SectionName + 526349cc55cSDimitry Andric " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) + 527349cc55cSDimitry Andric ") refer to different sections"); 528349cc55cSDimitry Andric return false; 529349cc55cSDimitry Andric } 530349cc55cSDimitry Andric W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]); 531349cc55cSDimitry Andric } else { 532349cc55cSDimitry Andric W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0); 533349cc55cSDimitry Andric } 534fe6060f1SDimitry Andric W.write<uint16_t>(YamlSym.Type); 535fe6060f1SDimitry Andric W.write<uint8_t>(YamlSym.StorageClass); 536fe6060f1SDimitry Andric W.write<uint8_t>(YamlSym.NumberOfAuxEntries); 537fe6060f1SDimitry Andric 538fe6060f1SDimitry Andric // Now output the auxiliary entry. 539fe6060f1SDimitry Andric for (uint8_t I = 0, E = YamlSym.NumberOfAuxEntries; I < E; ++I) { 540fe6060f1SDimitry Andric // TODO: Auxiliary entry is not supported yet. 541fe6060f1SDimitry Andric // The auxiliary entries for a symbol follow its symbol table entry. The 542fe6060f1SDimitry Andric // length of each auxiliary entry is the same as a symbol table entry (18 543fe6060f1SDimitry Andric // bytes). The format and quantity of auxiliary entries depend on the 544fe6060f1SDimitry Andric // storage class (n_sclass) and type (n_type) of the symbol table entry. 545349cc55cSDimitry Andric W.OS.write_zeros(XCOFF::SymbolTableEntrySize); 546fe6060f1SDimitry Andric } 547fe6060f1SDimitry Andric } 548fe6060f1SDimitry Andric return true; 549fe6060f1SDimitry Andric } 550fe6060f1SDimitry Andric 551349cc55cSDimitry Andric void XCOFFWriter::writeStringTable() { 552349cc55cSDimitry Andric if (Obj.StrTbl.RawContent) { 553349cc55cSDimitry Andric Obj.StrTbl.RawContent->writeAsBinary(W.OS); 554349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize) { 555349cc55cSDimitry Andric assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() && 556349cc55cSDimitry Andric "Specified ContentSize is less than the RawContent size."); 557349cc55cSDimitry Andric W.OS.write_zeros(*Obj.StrTbl.ContentSize - 558349cc55cSDimitry Andric Obj.StrTbl.RawContent->binary_size()); 559fe6060f1SDimitry Andric } 560349cc55cSDimitry Andric return; 561349cc55cSDimitry Andric } 562349cc55cSDimitry Andric 563349cc55cSDimitry Andric size_t StrTblBuilderSize = StrTblBuilder.getSize(); 564349cc55cSDimitry Andric // If neither Length nor ContentSize is specified, write the StrTblBuilder 565349cc55cSDimitry Andric // directly, which contains the auto-generated Length value. 566349cc55cSDimitry Andric if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) { 567349cc55cSDimitry Andric if (StrTblBuilderSize <= 4) 568349cc55cSDimitry Andric return; 569349cc55cSDimitry Andric StrTblBuilder.write(W.OS); 570349cc55cSDimitry Andric return; 571349cc55cSDimitry Andric } 572349cc55cSDimitry Andric 573349cc55cSDimitry Andric // Serialize the string table's content to a temporary buffer. 574349cc55cSDimitry Andric std::unique_ptr<WritableMemoryBuffer> Buf = 575349cc55cSDimitry Andric WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize); 576349cc55cSDimitry Andric uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); 577349cc55cSDimitry Andric StrTblBuilder.write(Ptr); 578349cc55cSDimitry Andric // Replace the first 4 bytes, which contain the auto-generated Length value, 579349cc55cSDimitry Andric // with the specified value. 580349cc55cSDimitry Andric memset(Ptr, 0, 4); 581349cc55cSDimitry Andric support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length 582349cc55cSDimitry Andric : *Obj.StrTbl.ContentSize); 583349cc55cSDimitry Andric // Copy the buffer content to the actual output stream. 584349cc55cSDimitry Andric W.OS.write(Buf->getBufferStart(), Buf->getBufferSize()); 585349cc55cSDimitry Andric // Add zeros as padding after strings. 586349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize) { 587349cc55cSDimitry Andric assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize && 588349cc55cSDimitry Andric "Specified ContentSize is less than the StringTableBuilder size."); 589349cc55cSDimitry Andric W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); 590349cc55cSDimitry Andric } 591349cc55cSDimitry Andric } 592349cc55cSDimitry Andric 593349cc55cSDimitry Andric bool XCOFFWriter::writeXCOFF() { 594fe6060f1SDimitry Andric if (!assignAddressesAndIndices()) 595fe6060f1SDimitry Andric return false; 596fe6060f1SDimitry Andric StartOffset = W.OS.tell(); 597fe6060f1SDimitry Andric writeFileHeader(); 598349cc55cSDimitry Andric if (Obj.AuxHeader) 599349cc55cSDimitry Andric writeAuxFileHeader(); 600fe6060f1SDimitry Andric if (!Obj.Sections.empty()) { 601fe6060f1SDimitry Andric writeSectionHeader(); 602fe6060f1SDimitry Andric if (!writeSectionData()) 603fe6060f1SDimitry Andric return false; 604fe6060f1SDimitry Andric if (!writeRelocations()) 605fe6060f1SDimitry Andric return false; 606fe6060f1SDimitry Andric } 607fe6060f1SDimitry Andric if (!Obj.Symbols.empty() && !writeSymbols()) 608fe6060f1SDimitry Andric return false; 609349cc55cSDimitry Andric writeStringTable(); 610fe6060f1SDimitry Andric return true; 611fe6060f1SDimitry Andric } 612fe6060f1SDimitry Andric 613fe6060f1SDimitry Andric } // end anonymous namespace 614fe6060f1SDimitry Andric 615fe6060f1SDimitry Andric namespace llvm { 616fe6060f1SDimitry Andric namespace yaml { 617fe6060f1SDimitry Andric 618fe6060f1SDimitry Andric bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { 619fe6060f1SDimitry Andric XCOFFWriter Writer(Doc, Out, EH); 620fe6060f1SDimitry Andric return Writer.writeXCOFF(); 621fe6060f1SDimitry Andric } 622fe6060f1SDimitry Andric 623fe6060f1SDimitry Andric } // namespace yaml 624fe6060f1SDimitry Andric } // namespace llvm 625