brintos

brintos / llvm-project-archived public Read only

0
0
Text · 34.3 KiB · 5d7d6a1 Raw
901 lines · cpp
1//===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// The xcoff component of yaml2obj.11///12//===----------------------------------------------------------------------===//13 14#include "llvm/ADT/DenseMap.h"15#include "llvm/BinaryFormat/XCOFF.h"16#include "llvm/MC/StringTableBuilder.h"17#include "llvm/Object/XCOFFObjectFile.h"18#include "llvm/ObjectYAML/ObjectYAML.h"19#include "llvm/ObjectYAML/yaml2obj.h"20#include "llvm/Support/EndianStream.h"21#include "llvm/Support/MemoryBuffer.h"22#include "llvm/Support/raw_ostream.h"23 24using namespace llvm;25using namespace llvm::object;26 27namespace {28 29constexpr unsigned DefaultSectionAlign = 4;30constexpr int16_t MaxSectionIndex = INT16_MAX;31constexpr uint32_t MaxRawDataSize = UINT32_MAX;32 33class XCOFFWriter {34public:35  XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)36      : Obj(Obj), W(OS, llvm::endianness::big), ErrHandler(EH),37        StrTblBuilder(StringTableBuilder::XCOFF) {38    Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;39  }40  bool writeXCOFF();41 42private:43  void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset,44                       const Twine &fieldName);45  bool nameShouldBeInStringTable(StringRef SymbolName);46  bool initFileHeader(uint64_t CurrentOffset);47  void initAuxFileHeader();48  bool initSectionHeaders(uint64_t &CurrentOffset);49  bool initRelocations(uint64_t &CurrentOffset);50  bool initStringTable();51  bool assignAddressesAndIndices();52 53  void writeFileHeader();54  void writeAuxFileHeader();55  void writeSectionHeaders();56  bool writeSectionData();57  bool writeRelocations();58  bool writeSymbols();59  void writeStringTable();60 61  bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym);62  bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym);63  bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym);64  bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym);65  bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym);66  bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym);67  bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym);68  bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym);69 70  XCOFFYAML::Object &Obj;71  bool Is64Bit = false;72  support::endian::Writer W;73  yaml::ErrorHandler ErrHandler;74  StringTableBuilder StrTblBuilder;75  uint64_t StartOffset = 0u;76  // Map the section name to its corrresponding section index.77  DenseMap<StringRef, int16_t> SectionIndexMap = {78      {StringRef("N_DEBUG"), XCOFF::N_DEBUG},79      {StringRef("N_ABS"), XCOFF::N_ABS},80      {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};81  XCOFFYAML::FileHeader InitFileHdr = Obj.Header;82  XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;83  std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;84};85 86static void writeName(StringRef StrName, support::endian::Writer W) {87  char Name[XCOFF::NameSize];88  memset(Name, 0, XCOFF::NameSize);89  char SrcName[] = "";90  memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());91  ArrayRef<char> NameRef(Name, XCOFF::NameSize);92  W.write(NameRef);93}94 95void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset,96                                  uint64_t specifiedOffset,97                                  const Twine &fieldName) {98  ErrHandler("current file offset (" + Twine(CurrentOffset) +99             ") is bigger than the specified " + fieldName + " (" +100             Twine(specifiedOffset) + ") ");101}102 103bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {104  // For XCOFF64: The symbol name is always in the string table.105  return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;106}107 108bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {109  for (XCOFFYAML::Section &InitSection : InitSections) {110    if (!InitSection.Relocations.empty()) {111      uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64112                                 : XCOFF::RelocationSerializationSize32;113      uint64_t UsedSize = RelSize * InitSection.Relocations.size();114 115      // If NumberOfRelocations was specified, we use it, even if it's116      // not consistent with the number of provided relocations.117      if (!InitSection.NumberOfRelocations)118        InitSection.NumberOfRelocations = InitSection.Relocations.size();119 120      // If the YAML file specified an offset to relocations, we use it.121      if (InitSection.FileOffsetToRelocations) {122        if (CurrentOffset > InitSection.FileOffsetToRelocations) {123          reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations,124                          "FileOffsetToRelocations for the " +125                              InitSection.SectionName + " section");126          return false;127        }128        CurrentOffset = InitSection.FileOffsetToRelocations;129      } else130        InitSection.FileOffsetToRelocations = CurrentOffset;131      CurrentOffset += UsedSize;132      if (CurrentOffset > MaxRawDataSize) {133        ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +134                   ") exceeded when writing relocation data for section " +135                   Twine(InitSection.SectionName));136        return false;137      }138    }139  }140  return true;141}142 143bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) {144  uint64_t CurrentEndDataAddr = 0;145  uint64_t CurrentEndTDataAddr = 0;146  for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {147    // Assign indices for sections.148    if (InitSections[I].SectionName.size()) {149      int16_t &SectionIndex = SectionIndexMap[InitSections[I].SectionName];150      if (!SectionIndex) {151        // The section index starts from 1.152        SectionIndex = I + 1;153        if ((I + 1) > MaxSectionIndex) {154          ErrHandler("exceeded the maximum permitted section index of " +155                     Twine(MaxSectionIndex));156          return false;157        }158      }159    }160 161    if (!InitSections[I].Size)162      InitSections[I].Size = InitSections[I].SectionData.binary_size();163 164    // Section data addresses (physical/virtual) are related to symbol165    // addresses and alignments. Furthermore, it is possible to specify the166    // same starting addresses for the .text, .data, and .tdata sections.167    // Without examining all the symbols and their addreses and alignments,168    // it is not possible to compute valid section addresses. The only169    // condition required by XCOFF is that the .bss section immediately170    // follows the .data section, and the .tbss section immediately follows171    // the .tdata section. Therefore, we only assign addresses to the .bss172    // and .tbss sections if they do not already have non-zero addresses.173    // (If the YAML file is being used to generate a valid object file, we174    // expect all section addresses to be specified explicitly.)175    switch (InitSections[I].Flags) {176    case XCOFF::STYP_DATA:177      CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size;178      break;179    case XCOFF::STYP_BSS:180      if (!InitSections[I].Address)181        InitSections[I].Address = CurrentEndDataAddr;182      break;183    case XCOFF::STYP_TDATA:184      CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size;185      break;186    case XCOFF::STYP_TBSS:187      if (!InitSections[I].Address)188        InitSections[I].Address = CurrentEndTDataAddr;189      break;190    }191 192    if (InitSections[I].SectionData.binary_size()) {193      if (InitSections[I].FileOffsetToData) {194        // Use the providedFileOffsetToData.195        if (CurrentOffset > InitSections[I].FileOffsetToData) {196          reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData,197                          "FileOffsetToData for the " +198                              InitSections[I].SectionName + " section");199          return false;200        }201        CurrentOffset = InitSections[I].FileOffsetToData;202      } else {203        CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);204        InitSections[I].FileOffsetToData = CurrentOffset;205      }206      CurrentOffset += InitSections[I].SectionData.binary_size();207      if (CurrentOffset > MaxRawDataSize) {208        ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +209                   ") exceeded when writing data for section " + Twine(I + 1) +210                   " (" + Twine(InitSections[I].SectionName) + ")");211        return false;212      }213    }214    if (InitSections[I].SectionSubtype) {215      uint32_t DWARFSubtype =216          static_cast<uint32_t>(*InitSections[I].SectionSubtype);217      if (InitSections[I].Flags != XCOFF::STYP_DWARF) {218        ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section");219        return false;220      }221      unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask222                              : XCOFFSectionHeader32::SectionFlagsTypeMask;223      if (DWARFSubtype & Mask) {224        ErrHandler("the low-order bits of DWARFSectionSubtype must be 0");225        return false;226      }227      InitSections[I].Flags |= DWARFSubtype;228    }229  }230  return initRelocations(CurrentOffset);231}232 233bool XCOFFWriter::initStringTable() {234  if (Obj.StrTbl.RawContent) {235    size_t RawSize = Obj.StrTbl.RawContent->binary_size();236    if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {237      ErrHandler(238          "can't specify Strings or Length when RawContent is specified");239      return false;240    }241    if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {242      ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +243                 ") is less than the RawContent data size (" + Twine(RawSize) +244                 ")");245      return false;246    }247    return true;248  }249  if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {250    ErrHandler("ContentSize shouldn't be less than 4 without RawContent");251    return false;252  }253 254  // Build the string table.255  StrTblBuilder.clear();256 257  if (Obj.StrTbl.Strings) {258    // Add all specified strings to the string table.259    for (StringRef StringEnt : *Obj.StrTbl.Strings)260      StrTblBuilder.add(StringEnt);261 262    size_t StrTblIdx = 0;263    size_t NumOfStrings = Obj.StrTbl.Strings->size();264    for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {265      if (nameShouldBeInStringTable(YamlSym.SymbolName)) {266        if (StrTblIdx < NumOfStrings) {267          // Overwrite the symbol name with the specified string.268          YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];269          ++StrTblIdx;270        } else271          // Names that are not overwritten are still stored in the string272          // table.273          StrTblBuilder.add(YamlSym.SymbolName);274      }275    }276  } else {277    for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {278      if (nameShouldBeInStringTable(YamlSym.SymbolName))279        StrTblBuilder.add(YamlSym.SymbolName);280    }281  }282 283  // Check if the file name in the File Auxiliary Entry should be added to the284  // string table.285  for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {286    for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :287         YamlSym.AuxEntries) {288      if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))289        if (nameShouldBeInStringTable(AS->FileNameOrString.value_or("")))290          StrTblBuilder.add(AS->FileNameOrString.value_or(""));291    }292  }293 294  StrTblBuilder.finalize();295 296  size_t StrTblSize = StrTblBuilder.getSize();297  if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {298    ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +299               ") is less than the size of the data that would otherwise be "300               "written (" +301               Twine(StrTblSize) + ")");302    return false;303  }304 305  return true;306}307 308bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {309  // The default format of the object file is XCOFF32.310  InitFileHdr.Magic = XCOFF::XCOFF32;311  InitFileHdr.NumberOfSections = Obj.Sections.size();312  InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();313 314  for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {315    uint32_t AuxCount = YamlSym.AuxEntries.size();316    if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) {317      ErrHandler("specified NumberOfAuxEntries " +318                 Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) +319                 " is less than the actual number "320                 "of auxiliary entries " +321                 Twine(AuxCount));322      return false;323    }324    YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount);325    // Add the number of auxiliary symbols to the total number.326    InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries;327  }328 329  // Calculate SymbolTableOffset for the file header.330  if (InitFileHdr.NumberOfSymTableEntries) {331    if (Obj.Header.SymbolTableOffset) {332      if (CurrentOffset > Obj.Header.SymbolTableOffset) {333        reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset,334                        "SymbolTableOffset");335        return false;336      }337      CurrentOffset = Obj.Header.SymbolTableOffset;338    }339    InitFileHdr.SymbolTableOffset = CurrentOffset;340    CurrentOffset +=341        InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;342    if (CurrentOffset > MaxRawDataSize) {343      ErrHandler("maximum object size of " + Twine(MaxRawDataSize) +344                 " exceeded when writing symbols");345      return false;346    }347  }348  // TODO: Calculate FileOffsetToLineNumbers when line number supported.349  return true;350}351 352void XCOFFWriter::initAuxFileHeader() {353  if (Obj.AuxHeader)354    InitAuxFileHdr = *Obj.AuxHeader;355  // In general, an object file might contain multiple sections of a given type,356  // but in a loadable module, there must be exactly one .text, .data, .bss, and357  // .loader section. A loadable object might also have one .tdata section and358  // one .tbss section.359  // Set these section-related values if not set explicitly. We assume that the360  // input YAML matches the format of the loadable object, but if multiple input361  // sections still have the same type, the first section with that type362  // prevails.363  for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {364    switch (InitSections[I].Flags) {365    case XCOFF::STYP_TEXT:366      if (!InitAuxFileHdr.TextSize)367        InitAuxFileHdr.TextSize = InitSections[I].Size;368      if (!InitAuxFileHdr.TextStartAddr)369        InitAuxFileHdr.TextStartAddr = InitSections[I].Address;370      if (!InitAuxFileHdr.SecNumOfText)371        InitAuxFileHdr.SecNumOfText = I + 1;372      break;373    case XCOFF::STYP_DATA:374      if (!InitAuxFileHdr.InitDataSize)375        InitAuxFileHdr.InitDataSize = InitSections[I].Size;376      if (!InitAuxFileHdr.DataStartAddr)377        InitAuxFileHdr.DataStartAddr = InitSections[I].Address;378      if (!InitAuxFileHdr.SecNumOfData)379        InitAuxFileHdr.SecNumOfData = I + 1;380      break;381    case XCOFF::STYP_BSS:382      if (!InitAuxFileHdr.BssDataSize)383        InitAuxFileHdr.BssDataSize = InitSections[I].Size;384      if (!InitAuxFileHdr.SecNumOfBSS)385        InitAuxFileHdr.SecNumOfBSS = I + 1;386      break;387    case XCOFF::STYP_TDATA:388      if (!InitAuxFileHdr.SecNumOfTData)389        InitAuxFileHdr.SecNumOfTData = I + 1;390      break;391    case XCOFF::STYP_TBSS:392      if (!InitAuxFileHdr.SecNumOfTBSS)393        InitAuxFileHdr.SecNumOfTBSS = I + 1;394      break;395    case XCOFF::STYP_LOADER:396      if (!InitAuxFileHdr.SecNumOfLoader)397        InitAuxFileHdr.SecNumOfLoader = I + 1;398      break;399    default:400      break;401    }402  }403}404 405bool XCOFFWriter::assignAddressesAndIndices() {406  uint64_t FileHdrSize =407      Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;408 409  // If AuxHeaderSize is specified in the YAML file, we construct410  // an auxiliary header.411  uint64_t AuxFileHdrSize = 0;412 413  if (Obj.Header.AuxHeaderSize)414    AuxFileHdrSize = Obj.Header.AuxHeaderSize;415  else if (Obj.AuxHeader)416    AuxFileHdrSize =417        (Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32);418  uint64_t SecHdrSize =419      Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;420  uint64_t CurrentOffset =421      FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;422 423  // Calculate section header info.424  if (!initSectionHeaders(CurrentOffset))425    return false;426 427  // Calculate file header info.428  if (!initFileHeader(CurrentOffset))429    return false;430  InitFileHdr.AuxHeaderSize = AuxFileHdrSize;431 432  // Initialize the auxiliary file header.433  if (AuxFileHdrSize)434    initAuxFileHeader();435 436  // Initialize the string table.437  return initStringTable();438}439 440void XCOFFWriter::writeFileHeader() {441  W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);442  W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections443                                                : InitFileHdr.NumberOfSections);444  W.write<int32_t>(Obj.Header.TimeStamp);445  if (Is64Bit) {446    W.write<uint64_t>(InitFileHdr.SymbolTableOffset);447    W.write<uint16_t>(InitFileHdr.AuxHeaderSize);448    W.write<uint16_t>(Obj.Header.Flags);449    W.write<int32_t>(Obj.Header.NumberOfSymTableEntries450                         ? Obj.Header.NumberOfSymTableEntries451                         : InitFileHdr.NumberOfSymTableEntries);452  } else {453    W.write<uint32_t>(InitFileHdr.SymbolTableOffset);454    W.write<int32_t>(Obj.Header.NumberOfSymTableEntries455                         ? Obj.Header.NumberOfSymTableEntries456                         : InitFileHdr.NumberOfSymTableEntries);457    W.write<uint16_t>(InitFileHdr.AuxHeaderSize);458    W.write<uint16_t>(Obj.Header.Flags);459  }460}461 462void XCOFFWriter::writeAuxFileHeader() {463  W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1)));464  W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1)));465  if (Is64Bit) {466    W.OS.write_zeros(4); // Reserved for debugger.467    W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));468    W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));469    W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));470  } else {471    W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));472    W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));473    W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));474    W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));475    W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));476    W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));477    // A short 32-bit auxiliary header ends here.478    if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort)479      return;480    W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));481  }482  W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0));483  W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0));484  W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0));485  W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0));486  W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0));487  W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0));488  W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0)));489  W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0)));490  W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0)));491  W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0)));492  W.write<uint8_t>(0); // Reserved for CPU type.493  if (Is64Bit) {494    W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));495    W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));496    W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));497    W.write<uint8_t>(498        InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80)));499    W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));500    W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));501    W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));502    W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));503    W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));504    W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));505  } else {506    W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));507    W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));508    W.OS.write_zeros(4); // Reserved for debugger.509    W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));510    W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));511    W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));512    W.write<uint8_t>(513        InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0)));514  }515  W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0));516  W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0));517  if (Is64Bit) {518    W.write<uint16_t>(519        InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB)));520    if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)521      W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);522  } else {523    if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32)524      W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);525  }526}527 528void XCOFFWriter::writeSectionHeaders() {529  for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {530    XCOFFYAML::Section DerivedSec = InitSections[I];531    writeName(DerivedSec.SectionName, W);532    if (Is64Bit) {533      // Virtual address is the same as physical address.534      W.write<uint64_t>(DerivedSec.Address); // Physical address535      W.write<uint64_t>(DerivedSec.Address); // Virtual address536      W.write<uint64_t>(DerivedSec.Size);537      W.write<uint64_t>(DerivedSec.FileOffsetToData);538      W.write<uint64_t>(DerivedSec.FileOffsetToRelocations);539      W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers);540      W.write<uint32_t>(DerivedSec.NumberOfRelocations);541      W.write<uint32_t>(DerivedSec.NumberOfLineNumbers);542      W.write<int32_t>(DerivedSec.Flags);543      W.OS.write_zeros(4);544    } else {545      // Virtual address is the same as physical address.546      W.write<uint32_t>(DerivedSec.Address); // Physical address547      W.write<uint32_t>(DerivedSec.Address); // Virtual address548      W.write<uint32_t>(DerivedSec.Size);549      W.write<uint32_t>(DerivedSec.FileOffsetToData);550      W.write<uint32_t>(DerivedSec.FileOffsetToRelocations);551      W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers);552      W.write<uint16_t>(DerivedSec.NumberOfRelocations);553      W.write<uint16_t>(DerivedSec.NumberOfLineNumbers);554      W.write<int32_t>(DerivedSec.Flags);555    }556  }557}558 559bool XCOFFWriter::writeSectionData() {560  for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {561    XCOFFYAML::Section YamlSec = Obj.Sections[I];562    if (YamlSec.SectionData.binary_size()) {563      // Fill the padding size with zeros.564      int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData -565                            (W.OS.tell() - StartOffset);566      if (PaddingSize < 0) {567        ErrHandler("redundant data was written before section data");568        return false;569      }570      W.OS.write_zeros(PaddingSize);571      YamlSec.SectionData.writeAsBinary(W.OS);572    }573  }574  return true;575}576 577bool XCOFFWriter::writeRelocations() {578  for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {579    XCOFFYAML::Section YamlSec = Obj.Sections[I];580    if (!YamlSec.Relocations.empty()) {581      int64_t PaddingSize =582          InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);583      if (PaddingSize < 0) {584        ErrHandler("redundant data was written before relocations");585        return false;586      }587      W.OS.write_zeros(PaddingSize);588      for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {589        if (Is64Bit)590          W.write<uint64_t>(YamlRel.VirtualAddress);591        else592          W.write<uint32_t>(YamlRel.VirtualAddress);593        W.write<uint32_t>(YamlRel.SymbolIndex);594        W.write<uint8_t>(YamlRel.Info);595        W.write<uint8_t>(YamlRel.Type);596      }597    }598  }599  return true;600}601 602bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) {603  uint8_t SymAlignAndType = 0;604  if (AuxSym.SymbolAlignmentAndType) {605    if (AuxSym.SymbolType || AuxSym.SymbolAlignment) {606      ErrHandler("cannot specify SymbolType or SymbolAlignment if "607                 "SymbolAlignmentAndType is specified");608      return false;609    }610    SymAlignAndType = *AuxSym.SymbolAlignmentAndType;611  } else {612    if (AuxSym.SymbolType) {613      uint8_t SymbolType = *AuxSym.SymbolType;614      if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) {615        ErrHandler("symbol type must be less than " +616                   Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask));617        return false;618      }619      SymAlignAndType = SymbolType;620    }621    if (AuxSym.SymbolAlignment) {622      const uint8_t ShiftedSymbolAlignmentMask =623          XCOFFCsectAuxRef::SymbolAlignmentMask >>624          XCOFFCsectAuxRef::SymbolAlignmentBitOffset;625 626      if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) {627        ErrHandler("symbol alignment must be less than " +628                   Twine(1 + ShiftedSymbolAlignmentMask));629        return false;630      }631      SymAlignAndType |= (*AuxSym.SymbolAlignment632                          << XCOFFCsectAuxRef::SymbolAlignmentBitOffset);633    }634  }635  if (Is64Bit) {636    W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0));637    W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));638    W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));639    W.write<uint8_t>(SymAlignAndType);640    W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));641    W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0));642    W.write<uint8_t>(0);643    W.write<uint8_t>(XCOFF::AUX_CSECT);644  } else {645    W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0));646    W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));647    W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));648    W.write<uint8_t>(SymAlignAndType);649    W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));650    W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0));651    W.write<uint16_t>(AuxSym.StabSectNum.value_or(0));652  }653  return true;654}655 656bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) {657  assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32");658  W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0));659  W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));660  W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));661  W.write<uint8_t>(0);662  W.write<uint8_t>(XCOFF::AUX_EXCEPT);663  return true;664}665 666bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) {667  if (Is64Bit) {668    W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0));669    W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));670    W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));671    W.write<uint8_t>(0);672    W.write<uint8_t>(XCOFF::AUX_FCN);673  } else {674    W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0));675    W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));676    W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0));677    W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));678    W.OS.write_zeros(2);679  }680  return true;681}682 683bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) {684  StringRef FileName = AuxSym.FileNameOrString.value_or("");685  if (nameShouldBeInStringTable(FileName)) {686    W.write<int32_t>(0);687    W.write<uint32_t>(StrTblBuilder.getOffset(FileName));688  } else {689    writeName(FileName, W);690  }691  W.OS.write_zeros(XCOFF::FileNamePadSize);692  W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN));693  if (Is64Bit) {694    W.OS.write_zeros(2);695    W.write<uint8_t>(XCOFF::AUX_FILE);696  } else {697    W.OS.write_zeros(3);698  }699  return true;700}701 702bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) {703  if (Is64Bit) {704    W.write<uint32_t>(AuxSym.LineNum.value_or(0));705    W.OS.write_zeros(13);706    W.write<uint8_t>(XCOFF::AUX_SYM);707  } else {708    W.OS.write_zeros(2);709    W.write<uint16_t>(AuxSym.LineNumHi.value_or(0));710    W.write<uint16_t>(AuxSym.LineNumLo.value_or(0));711    W.OS.write_zeros(12);712  }713  return true;714}715 716bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) {717  if (Is64Bit) {718    W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0));719    W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0));720    W.write<uint8_t>(0);721    W.write<uint8_t>(XCOFF::AUX_SECT);722  } else {723    W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0));724    W.OS.write_zeros(4);725    W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0));726    W.OS.write_zeros(6);727  }728  return true;729}730 731bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) {732  assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64");733  W.write<uint32_t>(AuxSym.SectionLength.value_or(0));734  W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0));735  W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0));736  W.OS.write_zeros(10);737  return true;738}739 740bool XCOFFWriter::writeAuxSymbol(741    const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) {742  if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get()))743    return writeAuxSymbol(*AS);744  else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get()))745    return writeAuxSymbol(*AS);746  else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get()))747    return writeAuxSymbol(*AS);748  else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))749    return writeAuxSymbol(*AS);750  else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get()))751    return writeAuxSymbol(*AS);752  else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get()))753    return writeAuxSymbol(*AS);754  else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get()))755    return writeAuxSymbol(*AS);756  llvm_unreachable("unknown auxiliary symbol type");757  return false;758}759 760bool XCOFFWriter::writeSymbols() {761  int64_t PaddingSize =762      InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);763  if (PaddingSize < 0) {764    ErrHandler("redundant data was written before symbols");765    return false;766  }767  W.OS.write_zeros(PaddingSize);768  for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {769    if (Is64Bit) {770      W.write<uint64_t>(YamlSym.Value);771      W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));772    } else {773      if (nameShouldBeInStringTable(YamlSym.SymbolName)) {774        // For XCOFF32: A value of 0 indicates that the symbol name is in the775        // string table.776        W.write<int32_t>(0);777        W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));778      } else {779        writeName(YamlSym.SymbolName, W);780      }781      W.write<uint32_t>(YamlSym.Value);782    }783    if (YamlSym.SectionName) {784      auto It = SectionIndexMap.find(*YamlSym.SectionName);785      if (It == SectionIndexMap.end()) {786        ErrHandler("the SectionName " + *YamlSym.SectionName +787                   " specified in the symbol does not exist");788        return false;789      }790      if (YamlSym.SectionIndex && It->second != *YamlSym.SectionIndex) {791        ErrHandler("the SectionName " + *YamlSym.SectionName +792                   " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +793                   ") refer to different sections");794        return false;795      }796      W.write<int16_t>(It->second);797    } else {798      W.write<int16_t>(YamlSym.SectionIndex.value_or(0));799    }800    W.write<uint16_t>(YamlSym.Type);801    W.write<uint8_t>(YamlSym.StorageClass);802 803    uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0);804    W.write<uint8_t>(NumOfAuxSym);805 806    if (!NumOfAuxSym && !YamlSym.AuxEntries.size())807      continue;808 809    // Now write auxiliary entries.810    if (!YamlSym.AuxEntries.size()) {811      W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym);812    } else {813      for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :814           YamlSym.AuxEntries) {815        if (!writeAuxSymbol(AuxSym))816          return false;817      }818      // Pad with zeros.819      if (NumOfAuxSym > YamlSym.AuxEntries.size())820        W.OS.write_zeros(XCOFF::SymbolTableEntrySize *821                         (NumOfAuxSym - YamlSym.AuxEntries.size()));822    }823  }824  return true;825}826 827void XCOFFWriter::writeStringTable() {828  if (Obj.StrTbl.RawContent) {829    Obj.StrTbl.RawContent->writeAsBinary(W.OS);830    if (Obj.StrTbl.ContentSize) {831      assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&832             "Specified ContentSize is less than the RawContent size.");833      W.OS.write_zeros(*Obj.StrTbl.ContentSize -834                       Obj.StrTbl.RawContent->binary_size());835    }836    return;837  }838 839  size_t StrTblBuilderSize = StrTblBuilder.getSize();840  // If neither Length nor ContentSize is specified, write the StrTblBuilder841  // directly, which contains the auto-generated Length value.842  if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {843    if (StrTblBuilderSize <= 4)844      return;845    StrTblBuilder.write(W.OS);846    return;847  }848 849  // Serialize the string table's content to a temporary buffer.850  std::unique_ptr<WritableMemoryBuffer> Buf =851      WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);852  uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());853  StrTblBuilder.write(Ptr);854  // Replace the first 4 bytes, which contain the auto-generated Length value,855  // with the specified value.856  memset(Ptr, 0, 4);857  support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length858                                                    : *Obj.StrTbl.ContentSize);859  // Copy the buffer content to the actual output stream.860  W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());861  // Add zeros as padding after strings.862  if (Obj.StrTbl.ContentSize) {863    assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&864           "Specified ContentSize is less than the StringTableBuilder size.");865    W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);866  }867}868 869bool XCOFFWriter::writeXCOFF() {870  if (!assignAddressesAndIndices())871    return false;872  StartOffset = W.OS.tell();873  writeFileHeader();874  if (InitFileHdr.AuxHeaderSize)875    writeAuxFileHeader();876  if (!Obj.Sections.empty()) {877    writeSectionHeaders();878    if (!writeSectionData())879      return false;880    if (!writeRelocations())881      return false;882  }883  if (!Obj.Symbols.empty() && !writeSymbols())884    return false;885  writeStringTable();886  return true;887}888 889} // end anonymous namespace890 891namespace llvm {892namespace yaml {893 894bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {895  XCOFFWriter Writer(Doc, Out, EH);896  return Writer.writeXCOFF();897}898 899} // namespace yaml900} // namespace llvm901