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(); 5004eeddc0SDimitry Andric 51fe6060f1SDimitry Andric void writeFileHeader(); 52349cc55cSDimitry Andric void writeAuxFileHeader(); 53fe6060f1SDimitry Andric void writeSectionHeader(); 54fe6060f1SDimitry Andric bool writeSectionData(); 55fe6060f1SDimitry Andric bool writeRelocations(); 56fe6060f1SDimitry Andric bool writeSymbols(); 57349cc55cSDimitry Andric void writeStringTable(); 58fe6060f1SDimitry Andric 5904eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym); 6004eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym); 6104eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym); 6204eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym); 6304eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym); 6404eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym); 6504eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym); 6604eeddc0SDimitry Andric void writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym); 6704eeddc0SDimitry Andric 68fe6060f1SDimitry Andric XCOFFYAML::Object &Obj; 69fe6060f1SDimitry Andric bool Is64Bit = false; 70fe6060f1SDimitry Andric support::endian::Writer W; 71fe6060f1SDimitry Andric yaml::ErrorHandler ErrHandler; 72349cc55cSDimitry Andric StringTableBuilder StrTblBuilder; 73*06c3fb27SDimitry Andric uint64_t StartOffset = 0u; 74fe6060f1SDimitry Andric // Map the section name to its corrresponding section index. 75fe6060f1SDimitry Andric DenseMap<StringRef, int16_t> SectionIndexMap = { 76fe6060f1SDimitry Andric {StringRef("N_DEBUG"), XCOFF::N_DEBUG}, 77fe6060f1SDimitry Andric {StringRef("N_ABS"), XCOFF::N_ABS}, 78fe6060f1SDimitry Andric {StringRef("N_UNDEF"), XCOFF::N_UNDEF}}; 79fe6060f1SDimitry Andric XCOFFYAML::FileHeader InitFileHdr = Obj.Header; 80349cc55cSDimitry Andric XCOFFYAML::AuxiliaryHeader InitAuxFileHdr; 81fe6060f1SDimitry Andric std::vector<XCOFFYAML::Section> InitSections = Obj.Sections; 82fe6060f1SDimitry Andric }; 83fe6060f1SDimitry Andric 84fe6060f1SDimitry Andric static void writeName(StringRef StrName, support::endian::Writer W) { 85fe6060f1SDimitry Andric char Name[XCOFF::NameSize]; 86fe6060f1SDimitry Andric memset(Name, 0, XCOFF::NameSize); 87fe6060f1SDimitry Andric char SrcName[] = ""; 88fe6060f1SDimitry Andric memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size()); 89fe6060f1SDimitry Andric ArrayRef<char> NameRef(Name, XCOFF::NameSize); 90fe6060f1SDimitry Andric W.write(NameRef); 91fe6060f1SDimitry Andric } 92fe6060f1SDimitry Andric 93fe6060f1SDimitry Andric bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { 94349cc55cSDimitry Andric // For XCOFF64: The symbol name is always in the string table. 95349cc55cSDimitry Andric return (SymbolName.size() > XCOFF::NameSize) || Is64Bit; 96fe6060f1SDimitry Andric } 97fe6060f1SDimitry Andric 98fe6060f1SDimitry Andric bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { 990eae32dcSDimitry Andric for (XCOFFYAML::Section &InitSection : InitSections) { 1000eae32dcSDimitry Andric if (!InitSection.Relocations.empty()) { 1010eae32dcSDimitry Andric InitSection.NumberOfRelocations = InitSection.Relocations.size(); 1020eae32dcSDimitry Andric InitSection.FileOffsetToRelocations = CurrentOffset; 103349cc55cSDimitry Andric uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64 104349cc55cSDimitry Andric : XCOFF::RelocationSerializationSize32; 1050eae32dcSDimitry Andric CurrentOffset += InitSection.NumberOfRelocations * RelSize; 106fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 107fe6060f1SDimitry Andric ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 108fe6060f1SDimitry Andric "exceeded when writing relocation data"); 109fe6060f1SDimitry Andric return false; 110fe6060f1SDimitry Andric } 111fe6060f1SDimitry Andric } 112fe6060f1SDimitry Andric } 113fe6060f1SDimitry Andric return true; 114fe6060f1SDimitry Andric } 115fe6060f1SDimitry Andric 116fe6060f1SDimitry Andric bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) { 117fe6060f1SDimitry Andric uint64_t CurrentSecAddr = 0; 118fe6060f1SDimitry Andric for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 119fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 120fe6060f1SDimitry Andric ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 121fe6060f1SDimitry Andric "exceeded when writing section data"); 122fe6060f1SDimitry Andric return false; 123fe6060f1SDimitry Andric } 124fe6060f1SDimitry Andric 125fe6060f1SDimitry Andric // Assign indices for sections. 126fe6060f1SDimitry Andric if (InitSections[I].SectionName.size() && 127fe6060f1SDimitry Andric !SectionIndexMap[InitSections[I].SectionName]) { 128fe6060f1SDimitry Andric // The section index starts from 1. 129fe6060f1SDimitry Andric SectionIndexMap[InitSections[I].SectionName] = I + 1; 130fe6060f1SDimitry Andric if ((I + 1) > MaxSectionIndex) { 131fe6060f1SDimitry Andric ErrHandler("exceeded the maximum permitted section index of " + 132fe6060f1SDimitry Andric Twine(MaxSectionIndex)); 133fe6060f1SDimitry Andric return false; 134fe6060f1SDimitry Andric } 135fe6060f1SDimitry Andric } 136fe6060f1SDimitry Andric 137fe6060f1SDimitry Andric // Calculate the physical/virtual address. This field should contain 0 for 138fe6060f1SDimitry Andric // all sections except the text, data and bss sections. 139fe6060f1SDimitry Andric if (InitSections[I].Flags != XCOFF::STYP_TEXT && 140fe6060f1SDimitry Andric InitSections[I].Flags != XCOFF::STYP_DATA && 141fe6060f1SDimitry Andric InitSections[I].Flags != XCOFF::STYP_BSS) 142fe6060f1SDimitry Andric InitSections[I].Address = 0; 143fe6060f1SDimitry Andric else 144fe6060f1SDimitry Andric InitSections[I].Address = CurrentSecAddr; 145fe6060f1SDimitry Andric 146fe6060f1SDimitry Andric // Calculate the FileOffsetToData and data size for sections. 147fe6060f1SDimitry Andric if (InitSections[I].SectionData.binary_size()) { 148fe6060f1SDimitry Andric InitSections[I].FileOffsetToData = CurrentOffset; 149fe6060f1SDimitry Andric CurrentOffset += InitSections[I].SectionData.binary_size(); 150fe6060f1SDimitry Andric // Ensure the offset is aligned to DefaultSectionAlign. 151fe6060f1SDimitry Andric CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign); 152fe6060f1SDimitry Andric InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData; 153fe6060f1SDimitry Andric CurrentSecAddr += InitSections[I].Size; 154fe6060f1SDimitry Andric } 155fe6060f1SDimitry Andric } 156fe6060f1SDimitry Andric return initRelocations(CurrentOffset); 157fe6060f1SDimitry Andric } 158fe6060f1SDimitry Andric 159349cc55cSDimitry Andric bool XCOFFWriter::initStringTable() { 160349cc55cSDimitry Andric if (Obj.StrTbl.RawContent) { 161349cc55cSDimitry Andric size_t RawSize = Obj.StrTbl.RawContent->binary_size(); 162349cc55cSDimitry Andric if (Obj.StrTbl.Strings || Obj.StrTbl.Length) { 163349cc55cSDimitry Andric ErrHandler( 164349cc55cSDimitry Andric "can't specify Strings or Length when RawContent is specified"); 165349cc55cSDimitry Andric return false; 166349cc55cSDimitry Andric } 167349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) { 168349cc55cSDimitry Andric ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 169349cc55cSDimitry Andric ") is less than the RawContent data size (" + Twine(RawSize) + 170349cc55cSDimitry Andric ")"); 171349cc55cSDimitry Andric return false; 172349cc55cSDimitry Andric } 173349cc55cSDimitry Andric return true; 174349cc55cSDimitry Andric } 175349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) { 176349cc55cSDimitry Andric ErrHandler("ContentSize shouldn't be less than 4 without RawContent"); 177349cc55cSDimitry Andric return false; 178349cc55cSDimitry Andric } 179349cc55cSDimitry Andric 180349cc55cSDimitry Andric // Build the string table. 181349cc55cSDimitry Andric StrTblBuilder.clear(); 182349cc55cSDimitry Andric 183349cc55cSDimitry Andric if (Obj.StrTbl.Strings) { 184349cc55cSDimitry Andric // All specified strings should be added to the string table. 185349cc55cSDimitry Andric for (StringRef StringEnt : *Obj.StrTbl.Strings) 186349cc55cSDimitry Andric StrTblBuilder.add(StringEnt); 187349cc55cSDimitry Andric 188349cc55cSDimitry Andric size_t StrTblIdx = 0; 189349cc55cSDimitry Andric size_t NumOfStrings = Obj.StrTbl.Strings->size(); 190349cc55cSDimitry Andric for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 191349cc55cSDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 192349cc55cSDimitry Andric if (StrTblIdx < NumOfStrings) { 193349cc55cSDimitry Andric // Overwrite the symbol name with the specified string. 194349cc55cSDimitry Andric YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx]; 195349cc55cSDimitry Andric ++StrTblIdx; 196349cc55cSDimitry Andric } else 197349cc55cSDimitry Andric // Names that are not overwritten are still stored in the string 198349cc55cSDimitry Andric // table. 199349cc55cSDimitry Andric StrTblBuilder.add(YamlSym.SymbolName); 200349cc55cSDimitry Andric } 201349cc55cSDimitry Andric } 202349cc55cSDimitry Andric } else { 20304eeddc0SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 204349cc55cSDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) 205349cc55cSDimitry Andric StrTblBuilder.add(YamlSym.SymbolName); 206349cc55cSDimitry Andric } 207349cc55cSDimitry Andric } 208349cc55cSDimitry Andric 20904eeddc0SDimitry Andric // Check if the file name in the File Auxiliary Entry should be added to the 21004eeddc0SDimitry Andric // string table. 21104eeddc0SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 21204eeddc0SDimitry Andric for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 21304eeddc0SDimitry Andric YamlSym.AuxEntries) { 21404eeddc0SDimitry Andric if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 21581ad6265SDimitry Andric if (nameShouldBeInStringTable(AS->FileNameOrString.value_or(""))) 21681ad6265SDimitry Andric StrTblBuilder.add(AS->FileNameOrString.value_or("")); 21704eeddc0SDimitry Andric } 21804eeddc0SDimitry Andric } 21904eeddc0SDimitry Andric 220349cc55cSDimitry Andric StrTblBuilder.finalize(); 221349cc55cSDimitry Andric 222349cc55cSDimitry Andric size_t StrTblSize = StrTblBuilder.getSize(); 223349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) { 224349cc55cSDimitry Andric ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + 225349cc55cSDimitry Andric ") is less than the size of the data that would otherwise be " 226349cc55cSDimitry Andric "written (" + 227349cc55cSDimitry Andric Twine(StrTblSize) + ")"); 228349cc55cSDimitry Andric return false; 229349cc55cSDimitry Andric } 230349cc55cSDimitry Andric 231349cc55cSDimitry Andric return true; 232349cc55cSDimitry Andric } 233349cc55cSDimitry Andric 234fe6060f1SDimitry Andric bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { 235fe6060f1SDimitry Andric // The default format of the object file is XCOFF32. 236fe6060f1SDimitry Andric InitFileHdr.Magic = XCOFF::XCOFF32; 237fe6060f1SDimitry Andric InitFileHdr.NumberOfSections = Obj.Sections.size(); 238fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); 239fe6060f1SDimitry Andric 24004eeddc0SDimitry Andric for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 24104eeddc0SDimitry Andric uint32_t AuxCount = YamlSym.AuxEntries.size(); 24204eeddc0SDimitry Andric if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) { 24304eeddc0SDimitry Andric ErrHandler("specified NumberOfAuxEntries " + 24404eeddc0SDimitry Andric Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) + 24504eeddc0SDimitry Andric " is less than the actual number " 24604eeddc0SDimitry Andric "of auxiliary entries " + 24704eeddc0SDimitry Andric Twine(AuxCount)); 24804eeddc0SDimitry Andric return false; 24904eeddc0SDimitry Andric } 25081ad6265SDimitry Andric YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount); 251fe6060f1SDimitry Andric // Add the number of auxiliary symbols to the total number. 25204eeddc0SDimitry Andric InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries; 25304eeddc0SDimitry Andric } 254fe6060f1SDimitry Andric 255fe6060f1SDimitry Andric // Calculate SymbolTableOffset for the file header. 256fe6060f1SDimitry Andric if (InitFileHdr.NumberOfSymTableEntries) { 257fe6060f1SDimitry Andric InitFileHdr.SymbolTableOffset = CurrentOffset; 258fe6060f1SDimitry Andric CurrentOffset += 259fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; 260fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 261fe6060f1SDimitry Andric ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 262fe6060f1SDimitry Andric "exceeded when writing symbols"); 263fe6060f1SDimitry Andric return false; 264fe6060f1SDimitry Andric } 265fe6060f1SDimitry Andric } 266fe6060f1SDimitry Andric // TODO: Calculate FileOffsetToLineNumbers when line number supported. 267fe6060f1SDimitry Andric return true; 268fe6060f1SDimitry Andric } 269fe6060f1SDimitry Andric 270349cc55cSDimitry Andric void XCOFFWriter::initAuxFileHeader() { 271349cc55cSDimitry Andric InitAuxFileHdr = *Obj.AuxHeader; 272349cc55cSDimitry Andric // In general, an object file might contain multiple sections of a given type, 273349cc55cSDimitry Andric // but in a loadable module, there must be exactly one .text, .data, .bss, and 274349cc55cSDimitry Andric // .loader section. A loadable object might also have one .tdata section and 275349cc55cSDimitry Andric // one .tbss section. 276349cc55cSDimitry Andric // Set these section-related values if not set explicitly. We assume that the 277349cc55cSDimitry Andric // input YAML matches the format of the loadable object, but if multiple input 278349cc55cSDimitry Andric // sections still have the same type, the first section with that type 279349cc55cSDimitry Andric // prevails. 280349cc55cSDimitry Andric for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 281349cc55cSDimitry Andric switch (InitSections[I].Flags) { 282349cc55cSDimitry Andric case XCOFF::STYP_TEXT: 283349cc55cSDimitry Andric if (!InitAuxFileHdr.TextSize) 284349cc55cSDimitry Andric InitAuxFileHdr.TextSize = InitSections[I].Size; 285349cc55cSDimitry Andric if (!InitAuxFileHdr.TextStartAddr) 286349cc55cSDimitry Andric InitAuxFileHdr.TextStartAddr = InitSections[I].Address; 287349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfText) 288349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfText = I + 1; 289349cc55cSDimitry Andric break; 290349cc55cSDimitry Andric case XCOFF::STYP_DATA: 291349cc55cSDimitry Andric if (!InitAuxFileHdr.InitDataSize) 292349cc55cSDimitry Andric InitAuxFileHdr.InitDataSize = InitSections[I].Size; 293349cc55cSDimitry Andric if (!InitAuxFileHdr.DataStartAddr) 294349cc55cSDimitry Andric InitAuxFileHdr.DataStartAddr = InitSections[I].Address; 295349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfData) 296349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfData = I + 1; 297349cc55cSDimitry Andric break; 298349cc55cSDimitry Andric case XCOFF::STYP_BSS: 299349cc55cSDimitry Andric if (!InitAuxFileHdr.BssDataSize) 300349cc55cSDimitry Andric InitAuxFileHdr.BssDataSize = InitSections[I].Size; 301349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfBSS) 302349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfBSS = I + 1; 303349cc55cSDimitry Andric break; 304349cc55cSDimitry Andric case XCOFF::STYP_TDATA: 305349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTData) 306349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTData = I + 1; 307349cc55cSDimitry Andric break; 308349cc55cSDimitry Andric case XCOFF::STYP_TBSS: 309349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTBSS) 310349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTBSS = I + 1; 311349cc55cSDimitry Andric break; 312349cc55cSDimitry Andric case XCOFF::STYP_LOADER: 313349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfLoader) 314349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfLoader = I + 1; 315349cc55cSDimitry Andric break; 316349cc55cSDimitry Andric default: 317349cc55cSDimitry Andric break; 318349cc55cSDimitry Andric } 319349cc55cSDimitry Andric } 320349cc55cSDimitry Andric } 321349cc55cSDimitry Andric 322fe6060f1SDimitry Andric bool XCOFFWriter::assignAddressesAndIndices() { 323349cc55cSDimitry Andric uint64_t FileHdrSize = 324349cc55cSDimitry Andric Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; 325349cc55cSDimitry Andric uint64_t AuxFileHdrSize = 0; 326349cc55cSDimitry Andric if (Obj.AuxHeader) 327349cc55cSDimitry Andric AuxFileHdrSize = Obj.Header.AuxHeaderSize 328349cc55cSDimitry Andric ? Obj.Header.AuxHeaderSize 329349cc55cSDimitry Andric : (Is64Bit ? XCOFF::AuxFileHeaderSize64 330349cc55cSDimitry Andric : XCOFF::AuxFileHeaderSize32); 331349cc55cSDimitry Andric uint64_t SecHdrSize = 332349cc55cSDimitry Andric Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; 333fe6060f1SDimitry Andric uint64_t CurrentOffset = 334349cc55cSDimitry Andric FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize; 335fe6060f1SDimitry Andric 336fe6060f1SDimitry Andric // Calculate section header info. 337fe6060f1SDimitry Andric if (!initSectionHeader(CurrentOffset)) 338fe6060f1SDimitry Andric return false; 339349cc55cSDimitry Andric InitFileHdr.AuxHeaderSize = AuxFileHdrSize; 340349cc55cSDimitry Andric 341fe6060f1SDimitry Andric // Calculate file header info. 342349cc55cSDimitry Andric if (!initFileHeader(CurrentOffset)) 343349cc55cSDimitry Andric return false; 344349cc55cSDimitry Andric 345349cc55cSDimitry Andric // Initialize the auxiliary file header. 346349cc55cSDimitry Andric if (Obj.AuxHeader) 347349cc55cSDimitry Andric initAuxFileHeader(); 348349cc55cSDimitry Andric 349349cc55cSDimitry Andric // Initialize the string table. 350349cc55cSDimitry Andric return initStringTable(); 351fe6060f1SDimitry Andric } 352fe6060f1SDimitry Andric 353fe6060f1SDimitry Andric void XCOFFWriter::writeFileHeader() { 354fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); 355fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections 356fe6060f1SDimitry Andric : InitFileHdr.NumberOfSections); 357fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.TimeStamp); 358349cc55cSDimitry Andric if (Is64Bit) { 359349cc55cSDimitry Andric W.write<uint64_t>(Obj.Header.SymbolTableOffset 360349cc55cSDimitry Andric ? Obj.Header.SymbolTableOffset 361349cc55cSDimitry Andric : InitFileHdr.SymbolTableOffset); 362349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 363349cc55cSDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 364349cc55cSDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 365349cc55cSDimitry Andric ? Obj.Header.NumberOfSymTableEntries 366349cc55cSDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 367349cc55cSDimitry Andric } else { 368fe6060f1SDimitry Andric W.write<uint32_t>(Obj.Header.SymbolTableOffset 369fe6060f1SDimitry Andric ? Obj.Header.SymbolTableOffset 370fe6060f1SDimitry Andric : InitFileHdr.SymbolTableOffset); 371fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 372fe6060f1SDimitry Andric ? Obj.Header.NumberOfSymTableEntries 373fe6060f1SDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 374349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 375fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 376fe6060f1SDimitry Andric } 377349cc55cSDimitry Andric } 378349cc55cSDimitry Andric 379349cc55cSDimitry Andric void XCOFFWriter::writeAuxFileHeader() { 38081ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1))); 38181ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1))); 382349cc55cSDimitry Andric if (Is64Bit) { 383349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 38481ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); 38581ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); 38681ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); 387349cc55cSDimitry Andric } else { 38881ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); 38981ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); 39081ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); 39181ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); 39281ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0))); 39381ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0))); 39481ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0))); 395349cc55cSDimitry Andric } 39681ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0)); 39781ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0)); 39881ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0)); 39981ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0)); 40081ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0)); 40181ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0)); 40281ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0))); 40381ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0))); 40481ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0))); 40581ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0))); 406349cc55cSDimitry Andric W.write<uint8_t>(0); // Reserved for CPU type. 407349cc55cSDimitry Andric if (Is64Bit) { 40881ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); 40981ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); 41081ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); 411349cc55cSDimitry Andric W.write<uint8_t>( 41281ad6265SDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80))); 41381ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0))); 41481ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0))); 41581ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0))); 41681ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0))); 41781ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); 41881ad6265SDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); 419349cc55cSDimitry Andric } else { 42081ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0))); 42181ad6265SDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0))); 422349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 42381ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0))); 42481ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0))); 42581ad6265SDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0))); 426349cc55cSDimitry Andric W.write<uint8_t>( 42781ad6265SDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0))); 428349cc55cSDimitry Andric } 42981ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0)); 43081ad6265SDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0)); 431349cc55cSDimitry Andric if (Is64Bit) { 43281ad6265SDimitry Andric W.write<uint16_t>( 43381ad6265SDimitry Andric InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB))); 434349cc55cSDimitry Andric if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64) 435349cc55cSDimitry Andric W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64); 436349cc55cSDimitry Andric } else if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) { 437349cc55cSDimitry Andric W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32); 438349cc55cSDimitry Andric } 439349cc55cSDimitry Andric } 440fe6060f1SDimitry Andric 441fe6060f1SDimitry Andric void XCOFFWriter::writeSectionHeader() { 442fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 443fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 444fe6060f1SDimitry Andric XCOFFYAML::Section DerivedSec = InitSections[I]; 445fe6060f1SDimitry Andric writeName(YamlSec.SectionName, W); 446fe6060f1SDimitry Andric // Virtual address is the same as physical address. 447349cc55cSDimitry Andric uint64_t SectionAddress = 448fe6060f1SDimitry Andric YamlSec.Address ? YamlSec.Address : DerivedSec.Address; 449349cc55cSDimitry Andric if (Is64Bit) { 450349cc55cSDimitry Andric W.write<uint64_t>(SectionAddress); // Physical address 451349cc55cSDimitry Andric W.write<uint64_t>(SectionAddress); // Virtual address 452349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); 453349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData 454349cc55cSDimitry Andric : DerivedSec.FileOffsetToData); 455349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.FileOffsetToRelocations 456349cc55cSDimitry Andric ? YamlSec.FileOffsetToRelocations 457349cc55cSDimitry Andric : DerivedSec.FileOffsetToRelocations); 458349cc55cSDimitry Andric W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers); 459349cc55cSDimitry Andric W.write<uint32_t>(YamlSec.NumberOfRelocations 460349cc55cSDimitry Andric ? YamlSec.NumberOfRelocations 461349cc55cSDimitry Andric : DerivedSec.NumberOfRelocations); 462349cc55cSDimitry Andric W.write<uint32_t>(YamlSec.NumberOfLineNumbers); 463349cc55cSDimitry Andric W.write<int32_t>(YamlSec.Flags); 464349cc55cSDimitry Andric W.OS.write_zeros(4); 465349cc55cSDimitry Andric } else { 466fe6060f1SDimitry Andric W.write<uint32_t>(SectionAddress); // Physical address 467fe6060f1SDimitry Andric W.write<uint32_t>(SectionAddress); // Virtual address 468fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); 469fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData 470fe6060f1SDimitry Andric : DerivedSec.FileOffsetToData); 471fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.FileOffsetToRelocations 472fe6060f1SDimitry Andric ? YamlSec.FileOffsetToRelocations 473fe6060f1SDimitry Andric : DerivedSec.FileOffsetToRelocations); 474fe6060f1SDimitry Andric W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers); 475fe6060f1SDimitry Andric W.write<uint16_t>(YamlSec.NumberOfRelocations 476fe6060f1SDimitry Andric ? YamlSec.NumberOfRelocations 477fe6060f1SDimitry Andric : DerivedSec.NumberOfRelocations); 478fe6060f1SDimitry Andric W.write<uint16_t>(YamlSec.NumberOfLineNumbers); 479fe6060f1SDimitry Andric W.write<int32_t>(YamlSec.Flags); 480fe6060f1SDimitry Andric } 481fe6060f1SDimitry Andric } 482349cc55cSDimitry Andric } 483fe6060f1SDimitry Andric 484fe6060f1SDimitry Andric bool XCOFFWriter::writeSectionData() { 485fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 486fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 487fe6060f1SDimitry Andric if (YamlSec.SectionData.binary_size()) { 488fe6060f1SDimitry Andric // Fill the padding size with zeros. 489fe6060f1SDimitry Andric int64_t PaddingSize = 490fe6060f1SDimitry Andric InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset); 491fe6060f1SDimitry Andric if (PaddingSize < 0) { 492fe6060f1SDimitry Andric ErrHandler("redundant data was written before section data"); 493fe6060f1SDimitry Andric return false; 494fe6060f1SDimitry Andric } 495fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 496fe6060f1SDimitry Andric YamlSec.SectionData.writeAsBinary(W.OS); 497fe6060f1SDimitry Andric } 498fe6060f1SDimitry Andric } 499fe6060f1SDimitry Andric return true; 500fe6060f1SDimitry Andric } 501fe6060f1SDimitry Andric 502fe6060f1SDimitry Andric bool XCOFFWriter::writeRelocations() { 503fe6060f1SDimitry Andric for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { 504fe6060f1SDimitry Andric XCOFFYAML::Section YamlSec = Obj.Sections[I]; 505fe6060f1SDimitry Andric if (!YamlSec.Relocations.empty()) { 506fe6060f1SDimitry Andric int64_t PaddingSize = 507fe6060f1SDimitry Andric InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset); 508fe6060f1SDimitry Andric if (PaddingSize < 0) { 509fe6060f1SDimitry Andric ErrHandler("redundant data was written before relocations"); 510fe6060f1SDimitry Andric return false; 511fe6060f1SDimitry Andric } 512fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 513fe6060f1SDimitry Andric for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { 514349cc55cSDimitry Andric if (Is64Bit) 515349cc55cSDimitry Andric W.write<uint64_t>(YamlRel.VirtualAddress); 516349cc55cSDimitry Andric else 517fe6060f1SDimitry Andric W.write<uint32_t>(YamlRel.VirtualAddress); 518fe6060f1SDimitry Andric W.write<uint32_t>(YamlRel.SymbolIndex); 519fe6060f1SDimitry Andric W.write<uint8_t>(YamlRel.Info); 520fe6060f1SDimitry Andric W.write<uint8_t>(YamlRel.Type); 521fe6060f1SDimitry Andric } 522fe6060f1SDimitry Andric } 523fe6060f1SDimitry Andric } 524fe6060f1SDimitry Andric return true; 525fe6060f1SDimitry Andric } 526fe6060f1SDimitry Andric 52704eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) { 52804eeddc0SDimitry Andric if (Is64Bit) { 52981ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0)); 53081ad6265SDimitry Andric W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); 53181ad6265SDimitry Andric W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); 53281ad6265SDimitry Andric W.write<uint8_t>(AuxSym.SymbolAlignmentAndType.value_or(0)); 53381ad6265SDimitry Andric W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); 53481ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0)); 53504eeddc0SDimitry Andric W.write<uint8_t>(0); 53604eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_CSECT); 53704eeddc0SDimitry Andric } else { 53881ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0)); 53981ad6265SDimitry Andric W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0)); 54081ad6265SDimitry Andric W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0)); 54181ad6265SDimitry Andric W.write<uint8_t>(AuxSym.SymbolAlignmentAndType.value_or(0)); 54281ad6265SDimitry Andric W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR)); 54381ad6265SDimitry Andric W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0)); 54481ad6265SDimitry Andric W.write<uint16_t>(AuxSym.StabSectNum.value_or(0)); 54504eeddc0SDimitry Andric } 54604eeddc0SDimitry Andric } 54704eeddc0SDimitry Andric 54804eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) { 54904eeddc0SDimitry Andric assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32"); 55081ad6265SDimitry Andric W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); 55181ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 55281ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 55304eeddc0SDimitry Andric W.write<uint8_t>(0); 55404eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_EXCEPT); 55504eeddc0SDimitry Andric } 55604eeddc0SDimitry Andric 55704eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) { 55804eeddc0SDimitry Andric if (Is64Bit) { 55981ad6265SDimitry Andric W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0)); 56081ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 56181ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 56204eeddc0SDimitry Andric W.write<uint8_t>(0); 56304eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_FCN); 56404eeddc0SDimitry Andric } else { 56581ad6265SDimitry Andric W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0)); 56681ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0)); 56781ad6265SDimitry Andric W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0)); 56881ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0)); 56904eeddc0SDimitry Andric W.OS.write_zeros(2); 57004eeddc0SDimitry Andric } 57104eeddc0SDimitry Andric } 57204eeddc0SDimitry Andric 57304eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) { 57481ad6265SDimitry Andric StringRef FileName = AuxSym.FileNameOrString.value_or(""); 57504eeddc0SDimitry Andric if (nameShouldBeInStringTable(FileName)) { 57604eeddc0SDimitry Andric W.write<int32_t>(0); 57704eeddc0SDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(FileName)); 57804eeddc0SDimitry Andric } else { 57904eeddc0SDimitry Andric writeName(FileName, W); 58004eeddc0SDimitry Andric } 58104eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::FileNamePadSize); 58281ad6265SDimitry Andric W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN)); 58304eeddc0SDimitry Andric if (Is64Bit) { 58404eeddc0SDimitry Andric W.OS.write_zeros(2); 58504eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_FILE); 58604eeddc0SDimitry Andric } else { 58704eeddc0SDimitry Andric W.OS.write_zeros(3); 58804eeddc0SDimitry Andric } 58904eeddc0SDimitry Andric } 59004eeddc0SDimitry Andric 59104eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) { 59204eeddc0SDimitry Andric if (Is64Bit) { 59381ad6265SDimitry Andric W.write<uint32_t>(AuxSym.LineNum.value_or(0)); 59404eeddc0SDimitry Andric W.OS.write_zeros(13); 59504eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_SYM); 59604eeddc0SDimitry Andric } else { 59704eeddc0SDimitry Andric W.OS.write_zeros(2); 59881ad6265SDimitry Andric W.write<uint16_t>(AuxSym.LineNumHi.value_or(0)); 59981ad6265SDimitry Andric W.write<uint16_t>(AuxSym.LineNumLo.value_or(0)); 60004eeddc0SDimitry Andric W.OS.write_zeros(12); 60104eeddc0SDimitry Andric } 60204eeddc0SDimitry Andric } 60304eeddc0SDimitry Andric 60404eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) { 60504eeddc0SDimitry Andric if (Is64Bit) { 60681ad6265SDimitry Andric W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0)); 60781ad6265SDimitry Andric W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 60804eeddc0SDimitry Andric W.write<uint8_t>(0); 60904eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_SECT); 61004eeddc0SDimitry Andric } else { 61181ad6265SDimitry Andric W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0)); 61204eeddc0SDimitry Andric W.OS.write_zeros(4); 61381ad6265SDimitry Andric W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 61404eeddc0SDimitry Andric W.OS.write_zeros(6); 61504eeddc0SDimitry Andric } 61604eeddc0SDimitry Andric } 61704eeddc0SDimitry Andric 61804eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) { 61904eeddc0SDimitry Andric assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64"); 62081ad6265SDimitry Andric W.write<uint32_t>(AuxSym.SectionLength.value_or(0)); 62181ad6265SDimitry Andric W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0)); 62281ad6265SDimitry Andric W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0)); 62304eeddc0SDimitry Andric W.OS.write_zeros(10); 62404eeddc0SDimitry Andric } 62504eeddc0SDimitry Andric 62604eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol( 62704eeddc0SDimitry Andric const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) { 62804eeddc0SDimitry Andric if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get())) 62904eeddc0SDimitry Andric writeAuxSymbol(*AS); 63004eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get())) 63104eeddc0SDimitry Andric writeAuxSymbol(*AS); 63204eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get())) 63304eeddc0SDimitry Andric writeAuxSymbol(*AS); 63404eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 63504eeddc0SDimitry Andric writeAuxSymbol(*AS); 63604eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get())) 63704eeddc0SDimitry Andric writeAuxSymbol(*AS); 63804eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get())) 63904eeddc0SDimitry Andric writeAuxSymbol(*AS); 64004eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get())) 64104eeddc0SDimitry Andric writeAuxSymbol(*AS); 64204eeddc0SDimitry Andric else 64304eeddc0SDimitry Andric llvm_unreachable("unknown auxiliary symbol type"); 64404eeddc0SDimitry Andric } 64504eeddc0SDimitry Andric 646fe6060f1SDimitry Andric bool XCOFFWriter::writeSymbols() { 647fe6060f1SDimitry Andric int64_t PaddingSize = 648fe6060f1SDimitry Andric (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset); 649fe6060f1SDimitry Andric if (PaddingSize < 0) { 650fe6060f1SDimitry Andric ErrHandler("redundant data was written before symbols"); 651fe6060f1SDimitry Andric return false; 652fe6060f1SDimitry Andric } 653fe6060f1SDimitry Andric W.OS.write_zeros(PaddingSize); 654fe6060f1SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 655349cc55cSDimitry Andric if (Is64Bit) { 656349cc55cSDimitry Andric W.write<uint64_t>(YamlSym.Value); 657349cc55cSDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 658349cc55cSDimitry Andric } else { 659fe6060f1SDimitry Andric if (nameShouldBeInStringTable(YamlSym.SymbolName)) { 660fe6060f1SDimitry Andric // For XCOFF32: A value of 0 indicates that the symbol name is in the 661fe6060f1SDimitry Andric // string table. 662fe6060f1SDimitry Andric W.write<int32_t>(0); 663349cc55cSDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName)); 664fe6060f1SDimitry Andric } else { 665fe6060f1SDimitry Andric writeName(YamlSym.SymbolName, W); 666fe6060f1SDimitry Andric } 667fe6060f1SDimitry Andric W.write<uint32_t>(YamlSym.Value); 668349cc55cSDimitry Andric } 669349cc55cSDimitry Andric if (YamlSym.SectionName) { 670349cc55cSDimitry Andric if (!SectionIndexMap.count(*YamlSym.SectionName)) { 671349cc55cSDimitry Andric ErrHandler("the SectionName " + *YamlSym.SectionName + 672349cc55cSDimitry Andric " specified in the symbol does not exist"); 673349cc55cSDimitry Andric return false; 674349cc55cSDimitry Andric } 675349cc55cSDimitry Andric if (YamlSym.SectionIndex && 676349cc55cSDimitry Andric SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) { 677349cc55cSDimitry Andric ErrHandler("the SectionName " + *YamlSym.SectionName + 678349cc55cSDimitry Andric " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) + 679349cc55cSDimitry Andric ") refer to different sections"); 680349cc55cSDimitry Andric return false; 681349cc55cSDimitry Andric } 682349cc55cSDimitry Andric W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]); 683349cc55cSDimitry Andric } else { 684349cc55cSDimitry Andric W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0); 685349cc55cSDimitry Andric } 686fe6060f1SDimitry Andric W.write<uint16_t>(YamlSym.Type); 687fe6060f1SDimitry Andric W.write<uint8_t>(YamlSym.StorageClass); 688fe6060f1SDimitry Andric 68981ad6265SDimitry Andric uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0); 69004eeddc0SDimitry Andric W.write<uint8_t>(NumOfAuxSym); 69104eeddc0SDimitry Andric 69204eeddc0SDimitry Andric if (!NumOfAuxSym && !YamlSym.AuxEntries.size()) 69304eeddc0SDimitry Andric continue; 69404eeddc0SDimitry Andric 69504eeddc0SDimitry Andric // Now write auxiliary entries. 69604eeddc0SDimitry Andric if (!YamlSym.AuxEntries.size()) { 69704eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym); 69804eeddc0SDimitry Andric } else { 69904eeddc0SDimitry Andric for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 70004eeddc0SDimitry Andric YamlSym.AuxEntries) { 70104eeddc0SDimitry Andric writeAuxSymbol(AuxSym); 70204eeddc0SDimitry Andric } 70304eeddc0SDimitry Andric // Pad with zeros. 70404eeddc0SDimitry Andric if (NumOfAuxSym > YamlSym.AuxEntries.size()) 70504eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::SymbolTableEntrySize * 70604eeddc0SDimitry Andric (NumOfAuxSym - YamlSym.AuxEntries.size())); 707fe6060f1SDimitry Andric } 708fe6060f1SDimitry Andric } 709fe6060f1SDimitry Andric return true; 710fe6060f1SDimitry Andric } 711fe6060f1SDimitry Andric 712349cc55cSDimitry Andric void XCOFFWriter::writeStringTable() { 713349cc55cSDimitry Andric if (Obj.StrTbl.RawContent) { 714349cc55cSDimitry Andric Obj.StrTbl.RawContent->writeAsBinary(W.OS); 715349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize) { 716349cc55cSDimitry Andric assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() && 717349cc55cSDimitry Andric "Specified ContentSize is less than the RawContent size."); 718349cc55cSDimitry Andric W.OS.write_zeros(*Obj.StrTbl.ContentSize - 719349cc55cSDimitry Andric Obj.StrTbl.RawContent->binary_size()); 720fe6060f1SDimitry Andric } 721349cc55cSDimitry Andric return; 722349cc55cSDimitry Andric } 723349cc55cSDimitry Andric 724349cc55cSDimitry Andric size_t StrTblBuilderSize = StrTblBuilder.getSize(); 725349cc55cSDimitry Andric // If neither Length nor ContentSize is specified, write the StrTblBuilder 726349cc55cSDimitry Andric // directly, which contains the auto-generated Length value. 727349cc55cSDimitry Andric if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) { 728349cc55cSDimitry Andric if (StrTblBuilderSize <= 4) 729349cc55cSDimitry Andric return; 730349cc55cSDimitry Andric StrTblBuilder.write(W.OS); 731349cc55cSDimitry Andric return; 732349cc55cSDimitry Andric } 733349cc55cSDimitry Andric 734349cc55cSDimitry Andric // Serialize the string table's content to a temporary buffer. 735349cc55cSDimitry Andric std::unique_ptr<WritableMemoryBuffer> Buf = 736349cc55cSDimitry Andric WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize); 737349cc55cSDimitry Andric uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); 738349cc55cSDimitry Andric StrTblBuilder.write(Ptr); 739349cc55cSDimitry Andric // Replace the first 4 bytes, which contain the auto-generated Length value, 740349cc55cSDimitry Andric // with the specified value. 741349cc55cSDimitry Andric memset(Ptr, 0, 4); 742349cc55cSDimitry Andric support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length 743349cc55cSDimitry Andric : *Obj.StrTbl.ContentSize); 744349cc55cSDimitry Andric // Copy the buffer content to the actual output stream. 745349cc55cSDimitry Andric W.OS.write(Buf->getBufferStart(), Buf->getBufferSize()); 746349cc55cSDimitry Andric // Add zeros as padding after strings. 747349cc55cSDimitry Andric if (Obj.StrTbl.ContentSize) { 748349cc55cSDimitry Andric assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize && 749349cc55cSDimitry Andric "Specified ContentSize is less than the StringTableBuilder size."); 750349cc55cSDimitry Andric W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); 751349cc55cSDimitry Andric } 752349cc55cSDimitry Andric } 753349cc55cSDimitry Andric 754349cc55cSDimitry Andric bool XCOFFWriter::writeXCOFF() { 755fe6060f1SDimitry Andric if (!assignAddressesAndIndices()) 756fe6060f1SDimitry Andric return false; 757fe6060f1SDimitry Andric StartOffset = W.OS.tell(); 758fe6060f1SDimitry Andric writeFileHeader(); 759349cc55cSDimitry Andric if (Obj.AuxHeader) 760349cc55cSDimitry Andric writeAuxFileHeader(); 761fe6060f1SDimitry Andric if (!Obj.Sections.empty()) { 762fe6060f1SDimitry Andric writeSectionHeader(); 763fe6060f1SDimitry Andric if (!writeSectionData()) 764fe6060f1SDimitry Andric return false; 765fe6060f1SDimitry Andric if (!writeRelocations()) 766fe6060f1SDimitry Andric return false; 767fe6060f1SDimitry Andric } 768fe6060f1SDimitry Andric if (!Obj.Symbols.empty() && !writeSymbols()) 769fe6060f1SDimitry Andric return false; 770349cc55cSDimitry Andric writeStringTable(); 771fe6060f1SDimitry Andric return true; 772fe6060f1SDimitry Andric } 773fe6060f1SDimitry Andric 774fe6060f1SDimitry Andric } // end anonymous namespace 775fe6060f1SDimitry Andric 776fe6060f1SDimitry Andric namespace llvm { 777fe6060f1SDimitry Andric namespace yaml { 778fe6060f1SDimitry Andric 779fe6060f1SDimitry Andric bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { 780fe6060f1SDimitry Andric XCOFFWriter Writer(Doc, Out, EH); 781fe6060f1SDimitry Andric return Writer.writeXCOFF(); 782fe6060f1SDimitry Andric } 783fe6060f1SDimitry Andric 784fe6060f1SDimitry Andric } // namespace yaml 785fe6060f1SDimitry Andric } // namespace llvm 786