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(); 50*04eeddc0SDimitry 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 59*04eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym); 60*04eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym); 61*04eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym); 62*04eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym); 63*04eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym); 64*04eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym); 65*04eeddc0SDimitry Andric void writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym); 66*04eeddc0SDimitry Andric void writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym); 67*04eeddc0SDimitry 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; 73fe6060f1SDimitry Andric uint64_t StartOffset; 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 { 203*04eeddc0SDimitry 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 209*04eeddc0SDimitry Andric // Check if the file name in the File Auxiliary Entry should be added to the 210*04eeddc0SDimitry Andric // string table. 211*04eeddc0SDimitry Andric for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 212*04eeddc0SDimitry Andric for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 213*04eeddc0SDimitry Andric YamlSym.AuxEntries) { 214*04eeddc0SDimitry Andric if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 215*04eeddc0SDimitry Andric if (nameShouldBeInStringTable(AS->FileNameOrString.getValueOr(""))) 216*04eeddc0SDimitry Andric StrTblBuilder.add(AS->FileNameOrString.getValueOr("")); 217*04eeddc0SDimitry Andric } 218*04eeddc0SDimitry Andric } 219*04eeddc0SDimitry 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 240*04eeddc0SDimitry Andric for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { 241*04eeddc0SDimitry Andric uint32_t AuxCount = YamlSym.AuxEntries.size(); 242*04eeddc0SDimitry Andric if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) { 243*04eeddc0SDimitry Andric ErrHandler("specified NumberOfAuxEntries " + 244*04eeddc0SDimitry Andric Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) + 245*04eeddc0SDimitry Andric " is less than the actual number " 246*04eeddc0SDimitry Andric "of auxiliary entries " + 247*04eeddc0SDimitry Andric Twine(AuxCount)); 248*04eeddc0SDimitry Andric return false; 249*04eeddc0SDimitry Andric } 250*04eeddc0SDimitry Andric YamlSym.NumberOfAuxEntries = 251*04eeddc0SDimitry Andric YamlSym.NumberOfAuxEntries.getValueOr(AuxCount); 252fe6060f1SDimitry Andric // Add the number of auxiliary symbols to the total number. 253*04eeddc0SDimitry Andric InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries; 254*04eeddc0SDimitry Andric } 255fe6060f1SDimitry Andric 256fe6060f1SDimitry Andric // Calculate SymbolTableOffset for the file header. 257fe6060f1SDimitry Andric if (InitFileHdr.NumberOfSymTableEntries) { 258fe6060f1SDimitry Andric InitFileHdr.SymbolTableOffset = CurrentOffset; 259fe6060f1SDimitry Andric CurrentOffset += 260fe6060f1SDimitry Andric InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; 261fe6060f1SDimitry Andric if (CurrentOffset > MaxRawDataSize) { 262fe6060f1SDimitry Andric ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + 263fe6060f1SDimitry Andric "exceeded when writing symbols"); 264fe6060f1SDimitry Andric return false; 265fe6060f1SDimitry Andric } 266fe6060f1SDimitry Andric } 267fe6060f1SDimitry Andric // TODO: Calculate FileOffsetToLineNumbers when line number supported. 268fe6060f1SDimitry Andric return true; 269fe6060f1SDimitry Andric } 270fe6060f1SDimitry Andric 271349cc55cSDimitry Andric void XCOFFWriter::initAuxFileHeader() { 272349cc55cSDimitry Andric InitAuxFileHdr = *Obj.AuxHeader; 273349cc55cSDimitry Andric // In general, an object file might contain multiple sections of a given type, 274349cc55cSDimitry Andric // but in a loadable module, there must be exactly one .text, .data, .bss, and 275349cc55cSDimitry Andric // .loader section. A loadable object might also have one .tdata section and 276349cc55cSDimitry Andric // one .tbss section. 277349cc55cSDimitry Andric // Set these section-related values if not set explicitly. We assume that the 278349cc55cSDimitry Andric // input YAML matches the format of the loadable object, but if multiple input 279349cc55cSDimitry Andric // sections still have the same type, the first section with that type 280349cc55cSDimitry Andric // prevails. 281349cc55cSDimitry Andric for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { 282349cc55cSDimitry Andric switch (InitSections[I].Flags) { 283349cc55cSDimitry Andric case XCOFF::STYP_TEXT: 284349cc55cSDimitry Andric if (!InitAuxFileHdr.TextSize) 285349cc55cSDimitry Andric InitAuxFileHdr.TextSize = InitSections[I].Size; 286349cc55cSDimitry Andric if (!InitAuxFileHdr.TextStartAddr) 287349cc55cSDimitry Andric InitAuxFileHdr.TextStartAddr = InitSections[I].Address; 288349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfText) 289349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfText = I + 1; 290349cc55cSDimitry Andric break; 291349cc55cSDimitry Andric case XCOFF::STYP_DATA: 292349cc55cSDimitry Andric if (!InitAuxFileHdr.InitDataSize) 293349cc55cSDimitry Andric InitAuxFileHdr.InitDataSize = InitSections[I].Size; 294349cc55cSDimitry Andric if (!InitAuxFileHdr.DataStartAddr) 295349cc55cSDimitry Andric InitAuxFileHdr.DataStartAddr = InitSections[I].Address; 296349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfData) 297349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfData = I + 1; 298349cc55cSDimitry Andric break; 299349cc55cSDimitry Andric case XCOFF::STYP_BSS: 300349cc55cSDimitry Andric if (!InitAuxFileHdr.BssDataSize) 301349cc55cSDimitry Andric InitAuxFileHdr.BssDataSize = InitSections[I].Size; 302349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfBSS) 303349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfBSS = I + 1; 304349cc55cSDimitry Andric break; 305349cc55cSDimitry Andric case XCOFF::STYP_TDATA: 306349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTData) 307349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTData = I + 1; 308349cc55cSDimitry Andric break; 309349cc55cSDimitry Andric case XCOFF::STYP_TBSS: 310349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfTBSS) 311349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfTBSS = I + 1; 312349cc55cSDimitry Andric break; 313349cc55cSDimitry Andric case XCOFF::STYP_LOADER: 314349cc55cSDimitry Andric if (!InitAuxFileHdr.SecNumOfLoader) 315349cc55cSDimitry Andric InitAuxFileHdr.SecNumOfLoader = I + 1; 316349cc55cSDimitry Andric break; 317349cc55cSDimitry Andric default: 318349cc55cSDimitry Andric break; 319349cc55cSDimitry Andric } 320349cc55cSDimitry Andric } 321349cc55cSDimitry Andric } 322349cc55cSDimitry Andric 323fe6060f1SDimitry Andric bool XCOFFWriter::assignAddressesAndIndices() { 324349cc55cSDimitry Andric uint64_t FileHdrSize = 325349cc55cSDimitry Andric Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; 326349cc55cSDimitry Andric uint64_t AuxFileHdrSize = 0; 327349cc55cSDimitry Andric if (Obj.AuxHeader) 328349cc55cSDimitry Andric AuxFileHdrSize = Obj.Header.AuxHeaderSize 329349cc55cSDimitry Andric ? Obj.Header.AuxHeaderSize 330349cc55cSDimitry Andric : (Is64Bit ? XCOFF::AuxFileHeaderSize64 331349cc55cSDimitry Andric : XCOFF::AuxFileHeaderSize32); 332349cc55cSDimitry Andric uint64_t SecHdrSize = 333349cc55cSDimitry Andric Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; 334fe6060f1SDimitry Andric uint64_t CurrentOffset = 335349cc55cSDimitry Andric FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize; 336fe6060f1SDimitry Andric 337fe6060f1SDimitry Andric // Calculate section header info. 338fe6060f1SDimitry Andric if (!initSectionHeader(CurrentOffset)) 339fe6060f1SDimitry Andric return false; 340349cc55cSDimitry Andric InitFileHdr.AuxHeaderSize = AuxFileHdrSize; 341349cc55cSDimitry Andric 342fe6060f1SDimitry Andric // Calculate file header info. 343349cc55cSDimitry Andric if (!initFileHeader(CurrentOffset)) 344349cc55cSDimitry Andric return false; 345349cc55cSDimitry Andric 346349cc55cSDimitry Andric // Initialize the auxiliary file header. 347349cc55cSDimitry Andric if (Obj.AuxHeader) 348349cc55cSDimitry Andric initAuxFileHeader(); 349349cc55cSDimitry Andric 350349cc55cSDimitry Andric // Initialize the string table. 351349cc55cSDimitry Andric return initStringTable(); 352fe6060f1SDimitry Andric } 353fe6060f1SDimitry Andric 354fe6060f1SDimitry Andric void XCOFFWriter::writeFileHeader() { 355fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); 356fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections 357fe6060f1SDimitry Andric : InitFileHdr.NumberOfSections); 358fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.TimeStamp); 359349cc55cSDimitry Andric if (Is64Bit) { 360349cc55cSDimitry Andric W.write<uint64_t>(Obj.Header.SymbolTableOffset 361349cc55cSDimitry Andric ? Obj.Header.SymbolTableOffset 362349cc55cSDimitry Andric : InitFileHdr.SymbolTableOffset); 363349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 364349cc55cSDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 365349cc55cSDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 366349cc55cSDimitry Andric ? Obj.Header.NumberOfSymTableEntries 367349cc55cSDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 368349cc55cSDimitry Andric } else { 369fe6060f1SDimitry Andric W.write<uint32_t>(Obj.Header.SymbolTableOffset 370fe6060f1SDimitry Andric ? Obj.Header.SymbolTableOffset 371fe6060f1SDimitry Andric : InitFileHdr.SymbolTableOffset); 372fe6060f1SDimitry Andric W.write<int32_t>(Obj.Header.NumberOfSymTableEntries 373fe6060f1SDimitry Andric ? Obj.Header.NumberOfSymTableEntries 374fe6060f1SDimitry Andric : InitFileHdr.NumberOfSymTableEntries); 375349cc55cSDimitry Andric W.write<uint16_t>(InitFileHdr.AuxHeaderSize); 376fe6060f1SDimitry Andric W.write<uint16_t>(Obj.Header.Flags); 377fe6060f1SDimitry Andric } 378349cc55cSDimitry Andric } 379349cc55cSDimitry Andric 380349cc55cSDimitry Andric void XCOFFWriter::writeAuxFileHeader() { 381349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Magic.getValueOr(yaml::Hex16(1))); 382349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Version.getValueOr(yaml::Hex16(1))); 383349cc55cSDimitry Andric if (Is64Bit) { 384349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 385349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0))); 386349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0))); 387349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0))); 388349cc55cSDimitry Andric } else { 389349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0))); 390349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0))); 391349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0))); 392349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0))); 393349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0))); 394349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0))); 395349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0))); 396349cc55cSDimitry Andric } 397349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.getValueOr(0)); 398349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.getValueOr(0)); 399349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.getValueOr(0)); 400349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.getValueOr(0)); 401349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.getValueOr(0)); 402349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.getValueOr(0)); 403349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.getValueOr(yaml::Hex16(0))); 404349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.getValueOr(yaml::Hex16(0))); 405349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.ModuleType.getValueOr(yaml::Hex16(0))); 406349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.CpuFlag.getValueOr(yaml::Hex8(0))); 407349cc55cSDimitry Andric W.write<uint8_t>(0); // Reserved for CPU type. 408349cc55cSDimitry Andric if (Is64Bit) { 409349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0))); 410349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0))); 411349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0))); 412349cc55cSDimitry Andric W.write<uint8_t>( 413349cc55cSDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0x80))); 414349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0))); 415349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0))); 416349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0))); 417349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0))); 418349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0))); 419349cc55cSDimitry Andric W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0))); 420349cc55cSDimitry Andric } else { 421349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0))); 422349cc55cSDimitry Andric W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0))); 423349cc55cSDimitry Andric W.OS.write_zeros(4); // Reserved for debugger. 424349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0))); 425349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0))); 426349cc55cSDimitry Andric W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0))); 427349cc55cSDimitry Andric W.write<uint8_t>( 428349cc55cSDimitry Andric InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0))); 429349cc55cSDimitry Andric } 430349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.getValueOr(0)); 431349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.getValueOr(0)); 432349cc55cSDimitry Andric if (Is64Bit) { 433349cc55cSDimitry Andric W.write<uint16_t>(InitAuxFileHdr.Flag.getValueOr(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 527*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) { 528*04eeddc0SDimitry Andric if (Is64Bit) { 529*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLengthLo.getValueOr(0)); 530*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.ParameterHashIndex.getValueOr(0)); 531*04eeddc0SDimitry Andric W.write<uint16_t>(AuxSym.TypeChkSectNum.getValueOr(0)); 532*04eeddc0SDimitry Andric W.write<uint8_t>(AuxSym.SymbolAlignmentAndType.getValueOr(0)); 533*04eeddc0SDimitry Andric W.write<uint8_t>(AuxSym.StorageMappingClass.getValueOr(XCOFF::XMC_PR)); 534*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLengthHi.getValueOr(0)); 535*04eeddc0SDimitry Andric W.write<uint8_t>(0); 536*04eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_CSECT); 537*04eeddc0SDimitry Andric } else { 538*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SectionOrLength.getValueOr(0)); 539*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.ParameterHashIndex.getValueOr(0)); 540*04eeddc0SDimitry Andric W.write<uint16_t>(AuxSym.TypeChkSectNum.getValueOr(0)); 541*04eeddc0SDimitry Andric W.write<uint8_t>(AuxSym.SymbolAlignmentAndType.getValueOr(0)); 542*04eeddc0SDimitry Andric W.write<uint8_t>(AuxSym.StorageMappingClass.getValueOr(XCOFF::XMC_PR)); 543*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.StabInfoIndex.getValueOr(0)); 544*04eeddc0SDimitry Andric W.write<uint16_t>(AuxSym.StabSectNum.getValueOr(0)); 545*04eeddc0SDimitry Andric } 546*04eeddc0SDimitry Andric } 547*04eeddc0SDimitry Andric 548*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) { 549*04eeddc0SDimitry Andric assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32"); 550*04eeddc0SDimitry Andric W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.getValueOr(0)); 551*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.getValueOr(0)); 552*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.getValueOr(0)); 553*04eeddc0SDimitry Andric W.write<uint8_t>(0); 554*04eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_EXCEPT); 555*04eeddc0SDimitry Andric } 556*04eeddc0SDimitry Andric 557*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) { 558*04eeddc0SDimitry Andric if (Is64Bit) { 559*04eeddc0SDimitry Andric W.write<uint64_t>(AuxSym.PtrToLineNum.getValueOr(0)); 560*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.getValueOr(0)); 561*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.getValueOr(0)); 562*04eeddc0SDimitry Andric W.write<uint8_t>(0); 563*04eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_FCN); 564*04eeddc0SDimitry Andric } else { 565*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.getValueOr(0)); 566*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SizeOfFunction.getValueOr(0)); 567*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.PtrToLineNum.getValueOr(0)); 568*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.getValueOr(0)); 569*04eeddc0SDimitry Andric W.OS.write_zeros(2); 570*04eeddc0SDimitry Andric } 571*04eeddc0SDimitry Andric } 572*04eeddc0SDimitry Andric 573*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) { 574*04eeddc0SDimitry Andric StringRef FileName = AuxSym.FileNameOrString.getValueOr(""); 575*04eeddc0SDimitry Andric if (nameShouldBeInStringTable(FileName)) { 576*04eeddc0SDimitry Andric W.write<int32_t>(0); 577*04eeddc0SDimitry Andric W.write<uint32_t>(StrTblBuilder.getOffset(FileName)); 578*04eeddc0SDimitry Andric } else { 579*04eeddc0SDimitry Andric writeName(FileName, W); 580*04eeddc0SDimitry Andric } 581*04eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::FileNamePadSize); 582*04eeddc0SDimitry Andric W.write<uint8_t>(AuxSym.FileStringType.getValueOr(XCOFF::XFT_FN)); 583*04eeddc0SDimitry Andric if (Is64Bit) { 584*04eeddc0SDimitry Andric W.OS.write_zeros(2); 585*04eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_FILE); 586*04eeddc0SDimitry Andric } else { 587*04eeddc0SDimitry Andric W.OS.write_zeros(3); 588*04eeddc0SDimitry Andric } 589*04eeddc0SDimitry Andric } 590*04eeddc0SDimitry Andric 591*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) { 592*04eeddc0SDimitry Andric if (Is64Bit) { 593*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.LineNum.getValueOr(0)); 594*04eeddc0SDimitry Andric W.OS.write_zeros(13); 595*04eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_SYM); 596*04eeddc0SDimitry Andric } else { 597*04eeddc0SDimitry Andric W.OS.write_zeros(2); 598*04eeddc0SDimitry Andric W.write<uint16_t>(AuxSym.LineNumHi.getValueOr(0)); 599*04eeddc0SDimitry Andric W.write<uint16_t>(AuxSym.LineNumLo.getValueOr(0)); 600*04eeddc0SDimitry Andric W.OS.write_zeros(12); 601*04eeddc0SDimitry Andric } 602*04eeddc0SDimitry Andric } 603*04eeddc0SDimitry Andric 604*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) { 605*04eeddc0SDimitry Andric if (Is64Bit) { 606*04eeddc0SDimitry Andric W.write<uint64_t>(AuxSym.LengthOfSectionPortion.getValueOr(0)); 607*04eeddc0SDimitry Andric W.write<uint64_t>(AuxSym.NumberOfRelocEnt.getValueOr(0)); 608*04eeddc0SDimitry Andric W.write<uint8_t>(0); 609*04eeddc0SDimitry Andric W.write<uint8_t>(XCOFF::AUX_SECT); 610*04eeddc0SDimitry Andric } else { 611*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.LengthOfSectionPortion.getValueOr(0)); 612*04eeddc0SDimitry Andric W.OS.write_zeros(4); 613*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.NumberOfRelocEnt.getValueOr(0)); 614*04eeddc0SDimitry Andric W.OS.write_zeros(6); 615*04eeddc0SDimitry Andric } 616*04eeddc0SDimitry Andric } 617*04eeddc0SDimitry Andric 618*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) { 619*04eeddc0SDimitry Andric assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64"); 620*04eeddc0SDimitry Andric W.write<uint32_t>(AuxSym.SectionLength.getValueOr(0)); 621*04eeddc0SDimitry Andric W.write<uint16_t>(AuxSym.NumberOfRelocEnt.getValueOr(0)); 622*04eeddc0SDimitry Andric W.write<uint16_t>(AuxSym.NumberOfLineNum.getValueOr(0)); 623*04eeddc0SDimitry Andric W.OS.write_zeros(10); 624*04eeddc0SDimitry Andric } 625*04eeddc0SDimitry Andric 626*04eeddc0SDimitry Andric void XCOFFWriter::writeAuxSymbol( 627*04eeddc0SDimitry Andric const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) { 628*04eeddc0SDimitry Andric if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get())) 629*04eeddc0SDimitry Andric writeAuxSymbol(*AS); 630*04eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get())) 631*04eeddc0SDimitry Andric writeAuxSymbol(*AS); 632*04eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get())) 633*04eeddc0SDimitry Andric writeAuxSymbol(*AS); 634*04eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get())) 635*04eeddc0SDimitry Andric writeAuxSymbol(*AS); 636*04eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get())) 637*04eeddc0SDimitry Andric writeAuxSymbol(*AS); 638*04eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get())) 639*04eeddc0SDimitry Andric writeAuxSymbol(*AS); 640*04eeddc0SDimitry Andric else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get())) 641*04eeddc0SDimitry Andric writeAuxSymbol(*AS); 642*04eeddc0SDimitry Andric else 643*04eeddc0SDimitry Andric llvm_unreachable("unknown auxiliary symbol type"); 644*04eeddc0SDimitry Andric } 645*04eeddc0SDimitry 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 689*04eeddc0SDimitry Andric uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.getValueOr(0); 690*04eeddc0SDimitry Andric W.write<uint8_t>(NumOfAuxSym); 691*04eeddc0SDimitry Andric 692*04eeddc0SDimitry Andric if (!NumOfAuxSym && !YamlSym.AuxEntries.size()) 693*04eeddc0SDimitry Andric continue; 694*04eeddc0SDimitry Andric 695*04eeddc0SDimitry Andric // Now write auxiliary entries. 696*04eeddc0SDimitry Andric if (!YamlSym.AuxEntries.size()) { 697*04eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym); 698*04eeddc0SDimitry Andric } else { 699*04eeddc0SDimitry Andric for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym : 700*04eeddc0SDimitry Andric YamlSym.AuxEntries) { 701*04eeddc0SDimitry Andric writeAuxSymbol(AuxSym); 702*04eeddc0SDimitry Andric } 703*04eeddc0SDimitry Andric // Pad with zeros. 704*04eeddc0SDimitry Andric if (NumOfAuxSym > YamlSym.AuxEntries.size()) 705*04eeddc0SDimitry Andric W.OS.write_zeros(XCOFF::SymbolTableEntrySize * 706*04eeddc0SDimitry 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