xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjectYAML/XCOFFEmitter.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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