xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjectYAML/XCOFFEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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;
26*0fca6ea1SDimitry Andric using namespace llvm::object;
27fe6060f1SDimitry Andric 
28fe6060f1SDimitry Andric namespace {
29fe6060f1SDimitry Andric 
30fe6060f1SDimitry Andric constexpr unsigned DefaultSectionAlign = 4;
31fe6060f1SDimitry Andric constexpr int16_t MaxSectionIndex = INT16_MAX;
32fe6060f1SDimitry Andric constexpr uint32_t MaxRawDataSize = UINT32_MAX;
33fe6060f1SDimitry Andric 
34fe6060f1SDimitry Andric class XCOFFWriter {
35fe6060f1SDimitry Andric public:
36fe6060f1SDimitry Andric   XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)
375f757f3fSDimitry Andric       : Obj(Obj), W(OS, llvm::endianness::big), ErrHandler(EH),
38349cc55cSDimitry Andric         StrTblBuilder(StringTableBuilder::XCOFF) {
39fe6060f1SDimitry Andric     Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;
40fe6060f1SDimitry Andric   }
41fe6060f1SDimitry Andric   bool writeXCOFF();
42fe6060f1SDimitry Andric 
43fe6060f1SDimitry Andric private:
44*0fca6ea1SDimitry Andric   void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset,
45*0fca6ea1SDimitry Andric                        const Twine &fieldName);
46fe6060f1SDimitry Andric   bool nameShouldBeInStringTable(StringRef SymbolName);
47fe6060f1SDimitry Andric   bool initFileHeader(uint64_t CurrentOffset);
48349cc55cSDimitry Andric   void initAuxFileHeader();
49*0fca6ea1SDimitry Andric   bool initSectionHeaders(uint64_t &CurrentOffset);
50fe6060f1SDimitry Andric   bool initRelocations(uint64_t &CurrentOffset);
51349cc55cSDimitry Andric   bool initStringTable();
52fe6060f1SDimitry Andric   bool assignAddressesAndIndices();
5304eeddc0SDimitry Andric 
54fe6060f1SDimitry Andric   void writeFileHeader();
55349cc55cSDimitry Andric   void writeAuxFileHeader();
56*0fca6ea1SDimitry Andric   void writeSectionHeaders();
57fe6060f1SDimitry Andric   bool writeSectionData();
58fe6060f1SDimitry Andric   bool writeRelocations();
59fe6060f1SDimitry Andric   bool writeSymbols();
60349cc55cSDimitry Andric   void writeStringTable();
61fe6060f1SDimitry Andric 
62*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym);
63*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym);
64*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym);
65*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym);
66*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym);
67*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym);
68*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym);
69*0fca6ea1SDimitry Andric   bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym);
7004eeddc0SDimitry Andric 
71fe6060f1SDimitry Andric   XCOFFYAML::Object &Obj;
72fe6060f1SDimitry Andric   bool Is64Bit = false;
73fe6060f1SDimitry Andric   support::endian::Writer W;
74fe6060f1SDimitry Andric   yaml::ErrorHandler ErrHandler;
75349cc55cSDimitry Andric   StringTableBuilder StrTblBuilder;
7606c3fb27SDimitry Andric   uint64_t StartOffset = 0u;
77fe6060f1SDimitry Andric   // Map the section name to its corrresponding section index.
78fe6060f1SDimitry Andric   DenseMap<StringRef, int16_t> SectionIndexMap = {
79fe6060f1SDimitry Andric       {StringRef("N_DEBUG"), XCOFF::N_DEBUG},
80fe6060f1SDimitry Andric       {StringRef("N_ABS"), XCOFF::N_ABS},
81fe6060f1SDimitry Andric       {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};
82fe6060f1SDimitry Andric   XCOFFYAML::FileHeader InitFileHdr = Obj.Header;
83349cc55cSDimitry Andric   XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;
84fe6060f1SDimitry Andric   std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;
85fe6060f1SDimitry Andric };
86fe6060f1SDimitry Andric 
87fe6060f1SDimitry Andric static void writeName(StringRef StrName, support::endian::Writer W) {
88fe6060f1SDimitry Andric   char Name[XCOFF::NameSize];
89fe6060f1SDimitry Andric   memset(Name, 0, XCOFF::NameSize);
90fe6060f1SDimitry Andric   char SrcName[] = "";
91fe6060f1SDimitry Andric   memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());
92fe6060f1SDimitry Andric   ArrayRef<char> NameRef(Name, XCOFF::NameSize);
93fe6060f1SDimitry Andric   W.write(NameRef);
94fe6060f1SDimitry Andric }
95fe6060f1SDimitry Andric 
96*0fca6ea1SDimitry Andric void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset,
97*0fca6ea1SDimitry Andric                                   uint64_t specifiedOffset,
98*0fca6ea1SDimitry Andric                                   const Twine &fieldName) {
99*0fca6ea1SDimitry Andric   ErrHandler("current file offset (" + Twine(CurrentOffset) +
100*0fca6ea1SDimitry Andric              ") is bigger than the specified " + fieldName + " (" +
101*0fca6ea1SDimitry Andric              Twine(specifiedOffset) + ") ");
102*0fca6ea1SDimitry Andric }
103*0fca6ea1SDimitry Andric 
104fe6060f1SDimitry Andric bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
105349cc55cSDimitry Andric   // For XCOFF64: The symbol name is always in the string table.
106349cc55cSDimitry Andric   return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
107fe6060f1SDimitry Andric }
108fe6060f1SDimitry Andric 
109fe6060f1SDimitry Andric bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
1100eae32dcSDimitry Andric   for (XCOFFYAML::Section &InitSection : InitSections) {
1110eae32dcSDimitry Andric     if (!InitSection.Relocations.empty()) {
112349cc55cSDimitry Andric       uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64
113349cc55cSDimitry Andric                                  : XCOFF::RelocationSerializationSize32;
114*0fca6ea1SDimitry Andric       uint64_t UsedSize = RelSize * InitSection.Relocations.size();
115*0fca6ea1SDimitry Andric 
116*0fca6ea1SDimitry Andric       // If NumberOfRelocations was specified, we use it, even if it's
117*0fca6ea1SDimitry Andric       // not consistent with the number of provided relocations.
118*0fca6ea1SDimitry Andric       if (!InitSection.NumberOfRelocations)
119*0fca6ea1SDimitry Andric         InitSection.NumberOfRelocations = InitSection.Relocations.size();
120*0fca6ea1SDimitry Andric 
121*0fca6ea1SDimitry Andric       // If the YAML file specified an offset to relocations, we use it.
122*0fca6ea1SDimitry Andric       if (InitSection.FileOffsetToRelocations) {
123*0fca6ea1SDimitry Andric         if (CurrentOffset > InitSection.FileOffsetToRelocations) {
124*0fca6ea1SDimitry Andric           reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations,
125*0fca6ea1SDimitry Andric                           "FileOffsetToRelocations for the " +
126*0fca6ea1SDimitry Andric                               InitSection.SectionName + " section");
127*0fca6ea1SDimitry Andric           return false;
128*0fca6ea1SDimitry Andric         }
129*0fca6ea1SDimitry Andric         CurrentOffset = InitSection.FileOffsetToRelocations;
130*0fca6ea1SDimitry Andric       } else
131*0fca6ea1SDimitry Andric         InitSection.FileOffsetToRelocations = CurrentOffset;
132*0fca6ea1SDimitry Andric       CurrentOffset += UsedSize;
133fe6060f1SDimitry Andric       if (CurrentOffset > MaxRawDataSize) {
134*0fca6ea1SDimitry Andric         ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +
135*0fca6ea1SDimitry Andric                    ") exceeded when writing relocation data for section " +
136*0fca6ea1SDimitry Andric                    Twine(InitSection.SectionName));
137fe6060f1SDimitry Andric         return false;
138fe6060f1SDimitry Andric       }
139fe6060f1SDimitry Andric     }
140fe6060f1SDimitry Andric   }
141fe6060f1SDimitry Andric   return true;
142fe6060f1SDimitry Andric }
143fe6060f1SDimitry Andric 
144*0fca6ea1SDimitry Andric bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) {
145*0fca6ea1SDimitry Andric   uint64_t CurrentEndDataAddr = 0;
146*0fca6ea1SDimitry Andric   uint64_t CurrentEndTDataAddr = 0;
147fe6060f1SDimitry Andric   for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
148fe6060f1SDimitry Andric     // Assign indices for sections.
149fe6060f1SDimitry Andric     if (InitSections[I].SectionName.size() &&
150fe6060f1SDimitry Andric         !SectionIndexMap[InitSections[I].SectionName]) {
151fe6060f1SDimitry Andric       // The section index starts from 1.
152fe6060f1SDimitry Andric       SectionIndexMap[InitSections[I].SectionName] = I + 1;
153fe6060f1SDimitry Andric       if ((I + 1) > MaxSectionIndex) {
154fe6060f1SDimitry Andric         ErrHandler("exceeded the maximum permitted section index of " +
155fe6060f1SDimitry Andric                    Twine(MaxSectionIndex));
156fe6060f1SDimitry Andric         return false;
157fe6060f1SDimitry Andric       }
158fe6060f1SDimitry Andric     }
159fe6060f1SDimitry Andric 
160*0fca6ea1SDimitry Andric     if (!InitSections[I].Size)
161*0fca6ea1SDimitry Andric       InitSections[I].Size = InitSections[I].SectionData.binary_size();
162fe6060f1SDimitry Andric 
163*0fca6ea1SDimitry Andric     // Section data addresses (physical/virtual) are related to symbol
164*0fca6ea1SDimitry Andric     // addresses and alignments. Furthermore, it is possible to specify the
165*0fca6ea1SDimitry Andric     // same starting addresses for the .text, .data, and .tdata sections.
166*0fca6ea1SDimitry Andric     // Without examining all the symbols and their addreses and alignments,
167*0fca6ea1SDimitry Andric     // it is not possible to compute valid section addresses. The only
168*0fca6ea1SDimitry Andric     // condition required by XCOFF is that the .bss section immediately
169*0fca6ea1SDimitry Andric     // follows the .data section, and the .tbss section immediately follows
170*0fca6ea1SDimitry Andric     // the .tdata section. Therefore, we only assign addresses to the .bss
171*0fca6ea1SDimitry Andric     // and .tbss sections if they do not already have non-zero addresses.
172*0fca6ea1SDimitry Andric     // (If the YAML file is being used to generate a valid object file, we
173*0fca6ea1SDimitry Andric     // expect all section addresses to be specified explicitly.)
174*0fca6ea1SDimitry Andric     switch (InitSections[I].Flags) {
175*0fca6ea1SDimitry Andric     case XCOFF::STYP_DATA:
176*0fca6ea1SDimitry Andric       CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size;
177*0fca6ea1SDimitry Andric       break;
178*0fca6ea1SDimitry Andric     case XCOFF::STYP_BSS:
179*0fca6ea1SDimitry Andric       if (!InitSections[I].Address)
180*0fca6ea1SDimitry Andric         InitSections[I].Address = CurrentEndDataAddr;
181*0fca6ea1SDimitry Andric       break;
182*0fca6ea1SDimitry Andric     case XCOFF::STYP_TDATA:
183*0fca6ea1SDimitry Andric       CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size;
184*0fca6ea1SDimitry Andric       break;
185*0fca6ea1SDimitry Andric     case XCOFF::STYP_TBSS:
186*0fca6ea1SDimitry Andric       if (!InitSections[I].Address)
187*0fca6ea1SDimitry Andric         InitSections[I].Address = CurrentEndTDataAddr;
188*0fca6ea1SDimitry Andric       break;
189*0fca6ea1SDimitry Andric     }
190*0fca6ea1SDimitry Andric 
191fe6060f1SDimitry Andric     if (InitSections[I].SectionData.binary_size()) {
192*0fca6ea1SDimitry Andric       if (InitSections[I].FileOffsetToData) {
193*0fca6ea1SDimitry Andric         // Use the providedFileOffsetToData.
194*0fca6ea1SDimitry Andric         if (CurrentOffset > InitSections[I].FileOffsetToData) {
195*0fca6ea1SDimitry Andric           reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData,
196*0fca6ea1SDimitry Andric                           "FileOffsetToData for the " +
197*0fca6ea1SDimitry Andric                               InitSections[I].SectionName + " section");
198*0fca6ea1SDimitry Andric           return false;
199*0fca6ea1SDimitry Andric         }
200*0fca6ea1SDimitry Andric         CurrentOffset = InitSections[I].FileOffsetToData;
201*0fca6ea1SDimitry Andric       } else {
202fe6060f1SDimitry Andric         CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);
203*0fca6ea1SDimitry Andric         InitSections[I].FileOffsetToData = CurrentOffset;
204*0fca6ea1SDimitry Andric       }
205*0fca6ea1SDimitry Andric       CurrentOffset += InitSections[I].SectionData.binary_size();
206*0fca6ea1SDimitry Andric       if (CurrentOffset > MaxRawDataSize) {
207*0fca6ea1SDimitry Andric         ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +
208*0fca6ea1SDimitry Andric                    ") exceeded when writing data for section " + Twine(I + 1) +
209*0fca6ea1SDimitry Andric                    " (" + Twine(InitSections[I].SectionName) + ")");
210*0fca6ea1SDimitry Andric         return false;
211*0fca6ea1SDimitry Andric       }
212*0fca6ea1SDimitry Andric     }
213*0fca6ea1SDimitry Andric     if (InitSections[I].SectionSubtype) {
214*0fca6ea1SDimitry Andric       uint32_t DWARFSubtype =
215*0fca6ea1SDimitry Andric           static_cast<uint32_t>(*InitSections[I].SectionSubtype);
216*0fca6ea1SDimitry Andric       if (InitSections[I].Flags != XCOFF::STYP_DWARF) {
217*0fca6ea1SDimitry Andric         ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section");
218*0fca6ea1SDimitry Andric         return false;
219*0fca6ea1SDimitry Andric       }
220*0fca6ea1SDimitry Andric       unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask
221*0fca6ea1SDimitry Andric                               : XCOFFSectionHeader32::SectionFlagsTypeMask;
222*0fca6ea1SDimitry Andric       if (DWARFSubtype & Mask) {
223*0fca6ea1SDimitry Andric         ErrHandler("the low-order bits of DWARFSectionSubtype must be 0");
224*0fca6ea1SDimitry Andric         return false;
225*0fca6ea1SDimitry Andric       }
226*0fca6ea1SDimitry Andric       InitSections[I].Flags |= DWARFSubtype;
227fe6060f1SDimitry Andric     }
228fe6060f1SDimitry Andric   }
229fe6060f1SDimitry Andric   return initRelocations(CurrentOffset);
230fe6060f1SDimitry Andric }
231fe6060f1SDimitry Andric 
232349cc55cSDimitry Andric bool XCOFFWriter::initStringTable() {
233349cc55cSDimitry Andric   if (Obj.StrTbl.RawContent) {
234349cc55cSDimitry Andric     size_t RawSize = Obj.StrTbl.RawContent->binary_size();
235349cc55cSDimitry Andric     if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {
236349cc55cSDimitry Andric       ErrHandler(
237349cc55cSDimitry Andric           "can't specify Strings or Length when RawContent is specified");
238349cc55cSDimitry Andric       return false;
239349cc55cSDimitry Andric     }
240349cc55cSDimitry Andric     if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {
241349cc55cSDimitry Andric       ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
242349cc55cSDimitry Andric                  ") is less than the RawContent data size (" + Twine(RawSize) +
243349cc55cSDimitry Andric                  ")");
244349cc55cSDimitry Andric       return false;
245349cc55cSDimitry Andric     }
246349cc55cSDimitry Andric     return true;
247349cc55cSDimitry Andric   }
248349cc55cSDimitry Andric   if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {
249349cc55cSDimitry Andric     ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
250349cc55cSDimitry Andric     return false;
251349cc55cSDimitry Andric   }
252349cc55cSDimitry Andric 
253349cc55cSDimitry Andric   // Build the string table.
254349cc55cSDimitry Andric   StrTblBuilder.clear();
255349cc55cSDimitry Andric 
256349cc55cSDimitry Andric   if (Obj.StrTbl.Strings) {
257*0fca6ea1SDimitry Andric     // Add all specified strings to the string table.
258349cc55cSDimitry Andric     for (StringRef StringEnt : *Obj.StrTbl.Strings)
259349cc55cSDimitry Andric       StrTblBuilder.add(StringEnt);
260349cc55cSDimitry Andric 
261349cc55cSDimitry Andric     size_t StrTblIdx = 0;
262349cc55cSDimitry Andric     size_t NumOfStrings = Obj.StrTbl.Strings->size();
263349cc55cSDimitry Andric     for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
264349cc55cSDimitry Andric       if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
265349cc55cSDimitry Andric         if (StrTblIdx < NumOfStrings) {
266349cc55cSDimitry Andric           // Overwrite the symbol name with the specified string.
267349cc55cSDimitry Andric           YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];
268349cc55cSDimitry Andric           ++StrTblIdx;
269349cc55cSDimitry Andric         } else
270349cc55cSDimitry Andric           // Names that are not overwritten are still stored in the string
271349cc55cSDimitry Andric           // table.
272349cc55cSDimitry Andric           StrTblBuilder.add(YamlSym.SymbolName);
273349cc55cSDimitry Andric       }
274349cc55cSDimitry Andric     }
275349cc55cSDimitry Andric   } else {
27604eeddc0SDimitry Andric     for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
277349cc55cSDimitry Andric       if (nameShouldBeInStringTable(YamlSym.SymbolName))
278349cc55cSDimitry Andric         StrTblBuilder.add(YamlSym.SymbolName);
279349cc55cSDimitry Andric     }
280349cc55cSDimitry Andric   }
281349cc55cSDimitry Andric 
28204eeddc0SDimitry Andric   // Check if the file name in the File Auxiliary Entry should be added to the
28304eeddc0SDimitry Andric   // string table.
28404eeddc0SDimitry Andric   for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
28504eeddc0SDimitry Andric     for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :
28604eeddc0SDimitry Andric          YamlSym.AuxEntries) {
28704eeddc0SDimitry Andric       if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))
28881ad6265SDimitry Andric         if (nameShouldBeInStringTable(AS->FileNameOrString.value_or("")))
28981ad6265SDimitry Andric           StrTblBuilder.add(AS->FileNameOrString.value_or(""));
29004eeddc0SDimitry Andric     }
29104eeddc0SDimitry Andric   }
29204eeddc0SDimitry Andric 
293349cc55cSDimitry Andric   StrTblBuilder.finalize();
294349cc55cSDimitry Andric 
295349cc55cSDimitry Andric   size_t StrTblSize = StrTblBuilder.getSize();
296349cc55cSDimitry Andric   if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {
297349cc55cSDimitry Andric     ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
298349cc55cSDimitry Andric                ") is less than the size of the data that would otherwise be "
299349cc55cSDimitry Andric                "written (" +
300349cc55cSDimitry Andric                Twine(StrTblSize) + ")");
301349cc55cSDimitry Andric     return false;
302349cc55cSDimitry Andric   }
303349cc55cSDimitry Andric 
304349cc55cSDimitry Andric   return true;
305349cc55cSDimitry Andric }
306349cc55cSDimitry Andric 
307fe6060f1SDimitry Andric bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {
308fe6060f1SDimitry Andric   // The default format of the object file is XCOFF32.
309fe6060f1SDimitry Andric   InitFileHdr.Magic = XCOFF::XCOFF32;
310fe6060f1SDimitry Andric   InitFileHdr.NumberOfSections = Obj.Sections.size();
311fe6060f1SDimitry Andric   InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();
312fe6060f1SDimitry Andric 
31304eeddc0SDimitry Andric   for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
31404eeddc0SDimitry Andric     uint32_t AuxCount = YamlSym.AuxEntries.size();
31504eeddc0SDimitry Andric     if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) {
31604eeddc0SDimitry Andric       ErrHandler("specified NumberOfAuxEntries " +
31704eeddc0SDimitry Andric                  Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) +
31804eeddc0SDimitry Andric                  " is less than the actual number "
31904eeddc0SDimitry Andric                  "of auxiliary entries " +
32004eeddc0SDimitry Andric                  Twine(AuxCount));
32104eeddc0SDimitry Andric       return false;
32204eeddc0SDimitry Andric     }
32381ad6265SDimitry Andric     YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount);
324fe6060f1SDimitry Andric     // Add the number of auxiliary symbols to the total number.
32504eeddc0SDimitry Andric     InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries;
32604eeddc0SDimitry Andric   }
327fe6060f1SDimitry Andric 
328fe6060f1SDimitry Andric   // Calculate SymbolTableOffset for the file header.
329fe6060f1SDimitry Andric   if (InitFileHdr.NumberOfSymTableEntries) {
330*0fca6ea1SDimitry Andric     if (Obj.Header.SymbolTableOffset) {
331*0fca6ea1SDimitry Andric       if (CurrentOffset > Obj.Header.SymbolTableOffset) {
332*0fca6ea1SDimitry Andric         reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset,
333*0fca6ea1SDimitry Andric                         "SymbolTableOffset");
334*0fca6ea1SDimitry Andric         return false;
335*0fca6ea1SDimitry Andric       }
336*0fca6ea1SDimitry Andric       CurrentOffset = Obj.Header.SymbolTableOffset;
337*0fca6ea1SDimitry Andric     }
338fe6060f1SDimitry Andric     InitFileHdr.SymbolTableOffset = CurrentOffset;
339fe6060f1SDimitry Andric     CurrentOffset +=
340fe6060f1SDimitry Andric         InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
341fe6060f1SDimitry Andric     if (CurrentOffset > MaxRawDataSize) {
342fe6060f1SDimitry Andric       ErrHandler("maximum object size of " + Twine(MaxRawDataSize) +
343fe6060f1SDimitry Andric                  " exceeded when writing symbols");
344fe6060f1SDimitry Andric       return false;
345fe6060f1SDimitry Andric     }
346fe6060f1SDimitry Andric   }
347fe6060f1SDimitry Andric   // TODO: Calculate FileOffsetToLineNumbers when line number supported.
348fe6060f1SDimitry Andric   return true;
349fe6060f1SDimitry Andric }
350fe6060f1SDimitry Andric 
351349cc55cSDimitry Andric void XCOFFWriter::initAuxFileHeader() {
352*0fca6ea1SDimitry Andric   if (Obj.AuxHeader)
353349cc55cSDimitry Andric     InitAuxFileHdr = *Obj.AuxHeader;
354349cc55cSDimitry Andric   // In general, an object file might contain multiple sections of a given type,
355349cc55cSDimitry Andric   // but in a loadable module, there must be exactly one .text, .data, .bss, and
356349cc55cSDimitry Andric   // .loader section. A loadable object might also have one .tdata section and
357349cc55cSDimitry Andric   // one .tbss section.
358349cc55cSDimitry Andric   // Set these section-related values if not set explicitly. We assume that the
359349cc55cSDimitry Andric   // input YAML matches the format of the loadable object, but if multiple input
360349cc55cSDimitry Andric   // sections still have the same type, the first section with that type
361349cc55cSDimitry Andric   // prevails.
362349cc55cSDimitry Andric   for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
363349cc55cSDimitry Andric     switch (InitSections[I].Flags) {
364349cc55cSDimitry Andric     case XCOFF::STYP_TEXT:
365349cc55cSDimitry Andric       if (!InitAuxFileHdr.TextSize)
366349cc55cSDimitry Andric         InitAuxFileHdr.TextSize = InitSections[I].Size;
367349cc55cSDimitry Andric       if (!InitAuxFileHdr.TextStartAddr)
368349cc55cSDimitry Andric         InitAuxFileHdr.TextStartAddr = InitSections[I].Address;
369349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfText)
370349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfText = I + 1;
371349cc55cSDimitry Andric       break;
372349cc55cSDimitry Andric     case XCOFF::STYP_DATA:
373349cc55cSDimitry Andric       if (!InitAuxFileHdr.InitDataSize)
374349cc55cSDimitry Andric         InitAuxFileHdr.InitDataSize = InitSections[I].Size;
375349cc55cSDimitry Andric       if (!InitAuxFileHdr.DataStartAddr)
376349cc55cSDimitry Andric         InitAuxFileHdr.DataStartAddr = InitSections[I].Address;
377349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfData)
378349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfData = I + 1;
379349cc55cSDimitry Andric       break;
380349cc55cSDimitry Andric     case XCOFF::STYP_BSS:
381349cc55cSDimitry Andric       if (!InitAuxFileHdr.BssDataSize)
382349cc55cSDimitry Andric         InitAuxFileHdr.BssDataSize = InitSections[I].Size;
383349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfBSS)
384349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfBSS = I + 1;
385349cc55cSDimitry Andric       break;
386349cc55cSDimitry Andric     case XCOFF::STYP_TDATA:
387349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfTData)
388349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfTData = I + 1;
389349cc55cSDimitry Andric       break;
390349cc55cSDimitry Andric     case XCOFF::STYP_TBSS:
391349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfTBSS)
392349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfTBSS = I + 1;
393349cc55cSDimitry Andric       break;
394349cc55cSDimitry Andric     case XCOFF::STYP_LOADER:
395349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfLoader)
396349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfLoader = I + 1;
397349cc55cSDimitry Andric       break;
398349cc55cSDimitry Andric     default:
399349cc55cSDimitry Andric       break;
400349cc55cSDimitry Andric     }
401349cc55cSDimitry Andric   }
402349cc55cSDimitry Andric }
403349cc55cSDimitry Andric 
404fe6060f1SDimitry Andric bool XCOFFWriter::assignAddressesAndIndices() {
405349cc55cSDimitry Andric   uint64_t FileHdrSize =
406349cc55cSDimitry Andric       Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;
407*0fca6ea1SDimitry Andric 
408*0fca6ea1SDimitry Andric   // If AuxHeaderSize is specified in the YAML file, we construct
409*0fca6ea1SDimitry Andric   // an auxiliary header.
410349cc55cSDimitry Andric   uint64_t AuxFileHdrSize = 0;
411*0fca6ea1SDimitry Andric 
412*0fca6ea1SDimitry Andric   if (Obj.Header.AuxHeaderSize)
413*0fca6ea1SDimitry Andric     AuxFileHdrSize = Obj.Header.AuxHeaderSize;
414*0fca6ea1SDimitry Andric   else if (Obj.AuxHeader)
415*0fca6ea1SDimitry Andric     AuxFileHdrSize =
416*0fca6ea1SDimitry Andric         (Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32);
417349cc55cSDimitry Andric   uint64_t SecHdrSize =
418349cc55cSDimitry Andric       Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;
419fe6060f1SDimitry Andric   uint64_t CurrentOffset =
420349cc55cSDimitry Andric       FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;
421fe6060f1SDimitry Andric 
422fe6060f1SDimitry Andric   // Calculate section header info.
423*0fca6ea1SDimitry Andric   if (!initSectionHeaders(CurrentOffset))
424fe6060f1SDimitry Andric     return false;
425349cc55cSDimitry Andric 
426fe6060f1SDimitry Andric   // Calculate file header info.
427349cc55cSDimitry Andric   if (!initFileHeader(CurrentOffset))
428349cc55cSDimitry Andric     return false;
429*0fca6ea1SDimitry Andric   InitFileHdr.AuxHeaderSize = AuxFileHdrSize;
430349cc55cSDimitry Andric 
431349cc55cSDimitry Andric   // Initialize the auxiliary file header.
432*0fca6ea1SDimitry Andric   if (AuxFileHdrSize)
433349cc55cSDimitry Andric     initAuxFileHeader();
434349cc55cSDimitry Andric 
435349cc55cSDimitry Andric   // Initialize the string table.
436349cc55cSDimitry Andric   return initStringTable();
437fe6060f1SDimitry Andric }
438fe6060f1SDimitry Andric 
439fe6060f1SDimitry Andric void XCOFFWriter::writeFileHeader() {
440fe6060f1SDimitry Andric   W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);
441fe6060f1SDimitry Andric   W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
442fe6060f1SDimitry Andric                                                 : InitFileHdr.NumberOfSections);
443fe6060f1SDimitry Andric   W.write<int32_t>(Obj.Header.TimeStamp);
444349cc55cSDimitry Andric   if (Is64Bit) {
445*0fca6ea1SDimitry Andric     W.write<uint64_t>(InitFileHdr.SymbolTableOffset);
446349cc55cSDimitry Andric     W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
447349cc55cSDimitry Andric     W.write<uint16_t>(Obj.Header.Flags);
448349cc55cSDimitry Andric     W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
449349cc55cSDimitry Andric                          ? Obj.Header.NumberOfSymTableEntries
450349cc55cSDimitry Andric                          : InitFileHdr.NumberOfSymTableEntries);
451349cc55cSDimitry Andric   } else {
452*0fca6ea1SDimitry Andric     W.write<uint32_t>(InitFileHdr.SymbolTableOffset);
453fe6060f1SDimitry Andric     W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
454fe6060f1SDimitry Andric                          ? Obj.Header.NumberOfSymTableEntries
455fe6060f1SDimitry Andric                          : InitFileHdr.NumberOfSymTableEntries);
456349cc55cSDimitry Andric     W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
457fe6060f1SDimitry Andric     W.write<uint16_t>(Obj.Header.Flags);
458fe6060f1SDimitry Andric   }
459349cc55cSDimitry Andric }
460349cc55cSDimitry Andric 
461349cc55cSDimitry Andric void XCOFFWriter::writeAuxFileHeader() {
46281ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1)));
46381ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1)));
464349cc55cSDimitry Andric   if (Is64Bit) {
465349cc55cSDimitry Andric     W.OS.write_zeros(4); // Reserved for debugger.
46681ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));
46781ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));
46881ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));
469349cc55cSDimitry Andric   } else {
47081ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));
47181ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));
47281ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));
47381ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));
47481ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));
47581ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));
476*0fca6ea1SDimitry Andric     // A short 32-bit auxiliary header ends here.
477*0fca6ea1SDimitry Andric     if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort)
478*0fca6ea1SDimitry Andric       return;
47981ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));
480349cc55cSDimitry Andric   }
48181ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0));
48281ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0));
48381ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0));
48481ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0));
48581ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0));
48681ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0));
48781ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0)));
48881ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0)));
48981ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0)));
49081ad6265SDimitry Andric   W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0)));
491349cc55cSDimitry Andric   W.write<uint8_t>(0); // Reserved for CPU type.
492349cc55cSDimitry Andric   if (Is64Bit) {
49381ad6265SDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));
49481ad6265SDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));
49581ad6265SDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));
496349cc55cSDimitry Andric     W.write<uint8_t>(
49781ad6265SDimitry Andric         InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80)));
49881ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));
49981ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));
50081ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));
50181ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));
50281ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));
50381ad6265SDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));
504349cc55cSDimitry Andric   } else {
50581ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));
50681ad6265SDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));
507349cc55cSDimitry Andric     W.OS.write_zeros(4); // Reserved for debugger.
50881ad6265SDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));
50981ad6265SDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));
51081ad6265SDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));
511349cc55cSDimitry Andric     W.write<uint8_t>(
51281ad6265SDimitry Andric         InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0)));
513349cc55cSDimitry Andric   }
51481ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0));
51581ad6265SDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0));
516349cc55cSDimitry Andric   if (Is64Bit) {
51781ad6265SDimitry Andric     W.write<uint16_t>(
51881ad6265SDimitry Andric         InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB)));
519349cc55cSDimitry Andric     if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)
520349cc55cSDimitry Andric       W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);
521*0fca6ea1SDimitry Andric   } else {
522*0fca6ea1SDimitry Andric     if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32)
523349cc55cSDimitry Andric       W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);
524349cc55cSDimitry Andric   }
525349cc55cSDimitry Andric }
526fe6060f1SDimitry Andric 
527*0fca6ea1SDimitry Andric void XCOFFWriter::writeSectionHeaders() {
528fe6060f1SDimitry Andric   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
529fe6060f1SDimitry Andric     XCOFFYAML::Section DerivedSec = InitSections[I];
530*0fca6ea1SDimitry Andric     writeName(DerivedSec.SectionName, W);
531349cc55cSDimitry Andric     if (Is64Bit) {
532*0fca6ea1SDimitry Andric       // Virtual address is the same as physical address.
533*0fca6ea1SDimitry Andric       W.write<uint64_t>(DerivedSec.Address); // Physical address
534*0fca6ea1SDimitry Andric       W.write<uint64_t>(DerivedSec.Address); // Virtual address
535*0fca6ea1SDimitry Andric       W.write<uint64_t>(DerivedSec.Size);
536*0fca6ea1SDimitry Andric       W.write<uint64_t>(DerivedSec.FileOffsetToData);
537*0fca6ea1SDimitry Andric       W.write<uint64_t>(DerivedSec.FileOffsetToRelocations);
538*0fca6ea1SDimitry Andric       W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers);
539*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.NumberOfRelocations);
540*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.NumberOfLineNumbers);
541*0fca6ea1SDimitry Andric       W.write<int32_t>(DerivedSec.Flags);
542349cc55cSDimitry Andric       W.OS.write_zeros(4);
543349cc55cSDimitry Andric     } else {
544*0fca6ea1SDimitry Andric       // Virtual address is the same as physical address.
545*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.Address); // Physical address
546*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.Address); // Virtual address
547*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.Size);
548*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.FileOffsetToData);
549*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.FileOffsetToRelocations);
550*0fca6ea1SDimitry Andric       W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers);
551*0fca6ea1SDimitry Andric       W.write<uint16_t>(DerivedSec.NumberOfRelocations);
552*0fca6ea1SDimitry Andric       W.write<uint16_t>(DerivedSec.NumberOfLineNumbers);
553*0fca6ea1SDimitry Andric       W.write<int32_t>(DerivedSec.Flags);
554fe6060f1SDimitry Andric     }
555fe6060f1SDimitry Andric   }
556349cc55cSDimitry Andric }
557fe6060f1SDimitry Andric 
558fe6060f1SDimitry Andric bool XCOFFWriter::writeSectionData() {
559fe6060f1SDimitry Andric   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
560fe6060f1SDimitry Andric     XCOFFYAML::Section YamlSec = Obj.Sections[I];
561fe6060f1SDimitry Andric     if (YamlSec.SectionData.binary_size()) {
562fe6060f1SDimitry Andric       // Fill the padding size with zeros.
563*0fca6ea1SDimitry Andric       int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData -
564*0fca6ea1SDimitry Andric                             (W.OS.tell() - StartOffset);
565fe6060f1SDimitry Andric       if (PaddingSize < 0) {
566fe6060f1SDimitry Andric         ErrHandler("redundant data was written before section data");
567fe6060f1SDimitry Andric         return false;
568fe6060f1SDimitry Andric       }
569fe6060f1SDimitry Andric       W.OS.write_zeros(PaddingSize);
570fe6060f1SDimitry Andric       YamlSec.SectionData.writeAsBinary(W.OS);
571fe6060f1SDimitry Andric     }
572fe6060f1SDimitry Andric   }
573fe6060f1SDimitry Andric   return true;
574fe6060f1SDimitry Andric }
575fe6060f1SDimitry Andric 
576fe6060f1SDimitry Andric bool XCOFFWriter::writeRelocations() {
577fe6060f1SDimitry Andric   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
578fe6060f1SDimitry Andric     XCOFFYAML::Section YamlSec = Obj.Sections[I];
579fe6060f1SDimitry Andric     if (!YamlSec.Relocations.empty()) {
580fe6060f1SDimitry Andric       int64_t PaddingSize =
581fe6060f1SDimitry Andric           InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);
582fe6060f1SDimitry Andric       if (PaddingSize < 0) {
583fe6060f1SDimitry Andric         ErrHandler("redundant data was written before relocations");
584fe6060f1SDimitry Andric         return false;
585fe6060f1SDimitry Andric       }
586fe6060f1SDimitry Andric       W.OS.write_zeros(PaddingSize);
587fe6060f1SDimitry Andric       for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
588349cc55cSDimitry Andric         if (Is64Bit)
589349cc55cSDimitry Andric           W.write<uint64_t>(YamlRel.VirtualAddress);
590349cc55cSDimitry Andric         else
591fe6060f1SDimitry Andric           W.write<uint32_t>(YamlRel.VirtualAddress);
592fe6060f1SDimitry Andric         W.write<uint32_t>(YamlRel.SymbolIndex);
593fe6060f1SDimitry Andric         W.write<uint8_t>(YamlRel.Info);
594fe6060f1SDimitry Andric         W.write<uint8_t>(YamlRel.Type);
595fe6060f1SDimitry Andric       }
596fe6060f1SDimitry Andric     }
597fe6060f1SDimitry Andric   }
598fe6060f1SDimitry Andric   return true;
599fe6060f1SDimitry Andric }
600fe6060f1SDimitry Andric 
601*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) {
602*0fca6ea1SDimitry Andric   uint8_t SymAlignAndType = 0;
603*0fca6ea1SDimitry Andric   if (AuxSym.SymbolAlignmentAndType) {
604*0fca6ea1SDimitry Andric     if (AuxSym.SymbolType || AuxSym.SymbolAlignment) {
605*0fca6ea1SDimitry Andric       ErrHandler("cannot specify SymbolType or SymbolAlignment if "
606*0fca6ea1SDimitry Andric                  "SymbolAlignmentAndType is specified");
607*0fca6ea1SDimitry Andric       return false;
608*0fca6ea1SDimitry Andric     }
609*0fca6ea1SDimitry Andric     SymAlignAndType = *AuxSym.SymbolAlignmentAndType;
610*0fca6ea1SDimitry Andric   } else {
611*0fca6ea1SDimitry Andric     if (AuxSym.SymbolType) {
612*0fca6ea1SDimitry Andric       uint8_t SymbolType = *AuxSym.SymbolType;
613*0fca6ea1SDimitry Andric       if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) {
614*0fca6ea1SDimitry Andric         ErrHandler("symbol type must be less than " +
615*0fca6ea1SDimitry Andric                    Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask));
616*0fca6ea1SDimitry Andric         return false;
617*0fca6ea1SDimitry Andric       }
618*0fca6ea1SDimitry Andric       SymAlignAndType = SymbolType;
619*0fca6ea1SDimitry Andric     }
620*0fca6ea1SDimitry Andric     if (AuxSym.SymbolAlignment) {
621*0fca6ea1SDimitry Andric       const uint8_t ShiftedSymbolAlignmentMask =
622*0fca6ea1SDimitry Andric           XCOFFCsectAuxRef::SymbolAlignmentMask >>
623*0fca6ea1SDimitry Andric           XCOFFCsectAuxRef::SymbolAlignmentBitOffset;
624*0fca6ea1SDimitry Andric 
625*0fca6ea1SDimitry Andric       if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) {
626*0fca6ea1SDimitry Andric         ErrHandler("symbol alignment must be less than " +
627*0fca6ea1SDimitry Andric                    Twine(1 + ShiftedSymbolAlignmentMask));
628*0fca6ea1SDimitry Andric         return false;
629*0fca6ea1SDimitry Andric       }
630*0fca6ea1SDimitry Andric       SymAlignAndType |= (*AuxSym.SymbolAlignment
631*0fca6ea1SDimitry Andric                           << XCOFFCsectAuxRef::SymbolAlignmentBitOffset);
632*0fca6ea1SDimitry Andric     }
633*0fca6ea1SDimitry Andric   }
63404eeddc0SDimitry Andric   if (Is64Bit) {
63581ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0));
63681ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));
63781ad6265SDimitry Andric     W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));
638*0fca6ea1SDimitry Andric     W.write<uint8_t>(SymAlignAndType);
63981ad6265SDimitry Andric     W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));
64081ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0));
64104eeddc0SDimitry Andric     W.write<uint8_t>(0);
64204eeddc0SDimitry Andric     W.write<uint8_t>(XCOFF::AUX_CSECT);
64304eeddc0SDimitry Andric   } else {
64481ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0));
64581ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));
64681ad6265SDimitry Andric     W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));
647*0fca6ea1SDimitry Andric     W.write<uint8_t>(SymAlignAndType);
64881ad6265SDimitry Andric     W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));
64981ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0));
65081ad6265SDimitry Andric     W.write<uint16_t>(AuxSym.StabSectNum.value_or(0));
65104eeddc0SDimitry Andric   }
652*0fca6ea1SDimitry Andric   return true;
65304eeddc0SDimitry Andric }
65404eeddc0SDimitry Andric 
655*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) {
65604eeddc0SDimitry Andric   assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32");
65781ad6265SDimitry Andric   W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0));
65881ad6265SDimitry Andric   W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
65981ad6265SDimitry Andric   W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
66004eeddc0SDimitry Andric   W.write<uint8_t>(0);
66104eeddc0SDimitry Andric   W.write<uint8_t>(XCOFF::AUX_EXCEPT);
662*0fca6ea1SDimitry Andric   return true;
66304eeddc0SDimitry Andric }
66404eeddc0SDimitry Andric 
665*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) {
66604eeddc0SDimitry Andric   if (Is64Bit) {
66781ad6265SDimitry Andric     W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0));
66881ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
66981ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
67004eeddc0SDimitry Andric     W.write<uint8_t>(0);
67104eeddc0SDimitry Andric     W.write<uint8_t>(XCOFF::AUX_FCN);
67204eeddc0SDimitry Andric   } else {
67381ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0));
67481ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
67581ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0));
67681ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
67704eeddc0SDimitry Andric     W.OS.write_zeros(2);
67804eeddc0SDimitry Andric   }
679*0fca6ea1SDimitry Andric   return true;
68004eeddc0SDimitry Andric }
68104eeddc0SDimitry Andric 
682*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) {
68381ad6265SDimitry Andric   StringRef FileName = AuxSym.FileNameOrString.value_or("");
68404eeddc0SDimitry Andric   if (nameShouldBeInStringTable(FileName)) {
68504eeddc0SDimitry Andric     W.write<int32_t>(0);
68604eeddc0SDimitry Andric     W.write<uint32_t>(StrTblBuilder.getOffset(FileName));
68704eeddc0SDimitry Andric   } else {
68804eeddc0SDimitry Andric     writeName(FileName, W);
68904eeddc0SDimitry Andric   }
69004eeddc0SDimitry Andric   W.OS.write_zeros(XCOFF::FileNamePadSize);
69181ad6265SDimitry Andric   W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN));
69204eeddc0SDimitry Andric   if (Is64Bit) {
69304eeddc0SDimitry Andric     W.OS.write_zeros(2);
69404eeddc0SDimitry Andric     W.write<uint8_t>(XCOFF::AUX_FILE);
69504eeddc0SDimitry Andric   } else {
69604eeddc0SDimitry Andric     W.OS.write_zeros(3);
69704eeddc0SDimitry Andric   }
698*0fca6ea1SDimitry Andric   return true;
69904eeddc0SDimitry Andric }
70004eeddc0SDimitry Andric 
701*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) {
70204eeddc0SDimitry Andric   if (Is64Bit) {
70381ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.LineNum.value_or(0));
70404eeddc0SDimitry Andric     W.OS.write_zeros(13);
70504eeddc0SDimitry Andric     W.write<uint8_t>(XCOFF::AUX_SYM);
70604eeddc0SDimitry Andric   } else {
70704eeddc0SDimitry Andric     W.OS.write_zeros(2);
70881ad6265SDimitry Andric     W.write<uint16_t>(AuxSym.LineNumHi.value_or(0));
70981ad6265SDimitry Andric     W.write<uint16_t>(AuxSym.LineNumLo.value_or(0));
71004eeddc0SDimitry Andric     W.OS.write_zeros(12);
71104eeddc0SDimitry Andric   }
712*0fca6ea1SDimitry Andric   return true;
71304eeddc0SDimitry Andric }
71404eeddc0SDimitry Andric 
715*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) {
71604eeddc0SDimitry Andric   if (Is64Bit) {
71781ad6265SDimitry Andric     W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0));
71881ad6265SDimitry Andric     W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0));
71904eeddc0SDimitry Andric     W.write<uint8_t>(0);
72004eeddc0SDimitry Andric     W.write<uint8_t>(XCOFF::AUX_SECT);
72104eeddc0SDimitry Andric   } else {
72281ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0));
72304eeddc0SDimitry Andric     W.OS.write_zeros(4);
72481ad6265SDimitry Andric     W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0));
72504eeddc0SDimitry Andric     W.OS.write_zeros(6);
72604eeddc0SDimitry Andric   }
727*0fca6ea1SDimitry Andric   return true;
72804eeddc0SDimitry Andric }
72904eeddc0SDimitry Andric 
730*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) {
73104eeddc0SDimitry Andric   assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64");
73281ad6265SDimitry Andric   W.write<uint32_t>(AuxSym.SectionLength.value_or(0));
73381ad6265SDimitry Andric   W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0));
73481ad6265SDimitry Andric   W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0));
73504eeddc0SDimitry Andric   W.OS.write_zeros(10);
736*0fca6ea1SDimitry Andric   return true;
73704eeddc0SDimitry Andric }
73804eeddc0SDimitry Andric 
739*0fca6ea1SDimitry Andric bool XCOFFWriter::writeAuxSymbol(
74004eeddc0SDimitry Andric     const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) {
74104eeddc0SDimitry Andric   if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get()))
742*0fca6ea1SDimitry Andric     return writeAuxSymbol(*AS);
74304eeddc0SDimitry Andric   else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get()))
744*0fca6ea1SDimitry Andric     return writeAuxSymbol(*AS);
74504eeddc0SDimitry Andric   else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get()))
746*0fca6ea1SDimitry Andric     return writeAuxSymbol(*AS);
74704eeddc0SDimitry Andric   else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))
748*0fca6ea1SDimitry Andric     return writeAuxSymbol(*AS);
74904eeddc0SDimitry Andric   else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get()))
750*0fca6ea1SDimitry Andric     return writeAuxSymbol(*AS);
75104eeddc0SDimitry Andric   else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get()))
752*0fca6ea1SDimitry Andric     return writeAuxSymbol(*AS);
75304eeddc0SDimitry Andric   else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get()))
754*0fca6ea1SDimitry Andric     return writeAuxSymbol(*AS);
75504eeddc0SDimitry Andric   llvm_unreachable("unknown auxiliary symbol type");
756*0fca6ea1SDimitry Andric   return false;
75704eeddc0SDimitry Andric }
75804eeddc0SDimitry Andric 
759fe6060f1SDimitry Andric bool XCOFFWriter::writeSymbols() {
760fe6060f1SDimitry Andric   int64_t PaddingSize =
761*0fca6ea1SDimitry Andric       InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);
762fe6060f1SDimitry Andric   if (PaddingSize < 0) {
763fe6060f1SDimitry Andric     ErrHandler("redundant data was written before symbols");
764fe6060f1SDimitry Andric     return false;
765fe6060f1SDimitry Andric   }
766fe6060f1SDimitry Andric   W.OS.write_zeros(PaddingSize);
767fe6060f1SDimitry Andric   for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
768349cc55cSDimitry Andric     if (Is64Bit) {
769349cc55cSDimitry Andric       W.write<uint64_t>(YamlSym.Value);
770349cc55cSDimitry Andric       W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
771349cc55cSDimitry Andric     } else {
772fe6060f1SDimitry Andric       if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
773fe6060f1SDimitry Andric         // For XCOFF32: A value of 0 indicates that the symbol name is in the
774fe6060f1SDimitry Andric         // string table.
775fe6060f1SDimitry Andric         W.write<int32_t>(0);
776349cc55cSDimitry Andric         W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
777fe6060f1SDimitry Andric       } else {
778fe6060f1SDimitry Andric         writeName(YamlSym.SymbolName, W);
779fe6060f1SDimitry Andric       }
780fe6060f1SDimitry Andric       W.write<uint32_t>(YamlSym.Value);
781349cc55cSDimitry Andric     }
782349cc55cSDimitry Andric     if (YamlSym.SectionName) {
783349cc55cSDimitry Andric       if (!SectionIndexMap.count(*YamlSym.SectionName)) {
784349cc55cSDimitry Andric         ErrHandler("the SectionName " + *YamlSym.SectionName +
785349cc55cSDimitry Andric                    " specified in the symbol does not exist");
786349cc55cSDimitry Andric         return false;
787349cc55cSDimitry Andric       }
788349cc55cSDimitry Andric       if (YamlSym.SectionIndex &&
789349cc55cSDimitry Andric           SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) {
790349cc55cSDimitry Andric         ErrHandler("the SectionName " + *YamlSym.SectionName +
791349cc55cSDimitry Andric                    " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +
792349cc55cSDimitry Andric                    ") refer to different sections");
793349cc55cSDimitry Andric         return false;
794349cc55cSDimitry Andric       }
795349cc55cSDimitry Andric       W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]);
796349cc55cSDimitry Andric     } else {
797349cc55cSDimitry Andric       W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0);
798349cc55cSDimitry Andric     }
799fe6060f1SDimitry Andric     W.write<uint16_t>(YamlSym.Type);
800fe6060f1SDimitry Andric     W.write<uint8_t>(YamlSym.StorageClass);
801fe6060f1SDimitry Andric 
80281ad6265SDimitry Andric     uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0);
80304eeddc0SDimitry Andric     W.write<uint8_t>(NumOfAuxSym);
80404eeddc0SDimitry Andric 
80504eeddc0SDimitry Andric     if (!NumOfAuxSym && !YamlSym.AuxEntries.size())
80604eeddc0SDimitry Andric       continue;
80704eeddc0SDimitry Andric 
80804eeddc0SDimitry Andric     // Now write auxiliary entries.
80904eeddc0SDimitry Andric     if (!YamlSym.AuxEntries.size()) {
81004eeddc0SDimitry Andric       W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym);
81104eeddc0SDimitry Andric     } else {
81204eeddc0SDimitry Andric       for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :
81304eeddc0SDimitry Andric            YamlSym.AuxEntries) {
814*0fca6ea1SDimitry Andric         if (!writeAuxSymbol(AuxSym))
815*0fca6ea1SDimitry Andric           return false;
81604eeddc0SDimitry Andric       }
81704eeddc0SDimitry Andric       // Pad with zeros.
81804eeddc0SDimitry Andric       if (NumOfAuxSym > YamlSym.AuxEntries.size())
81904eeddc0SDimitry Andric         W.OS.write_zeros(XCOFF::SymbolTableEntrySize *
82004eeddc0SDimitry Andric                          (NumOfAuxSym - YamlSym.AuxEntries.size()));
821fe6060f1SDimitry Andric     }
822fe6060f1SDimitry Andric   }
823fe6060f1SDimitry Andric   return true;
824fe6060f1SDimitry Andric }
825fe6060f1SDimitry Andric 
826349cc55cSDimitry Andric void XCOFFWriter::writeStringTable() {
827349cc55cSDimitry Andric   if (Obj.StrTbl.RawContent) {
828349cc55cSDimitry Andric     Obj.StrTbl.RawContent->writeAsBinary(W.OS);
829349cc55cSDimitry Andric     if (Obj.StrTbl.ContentSize) {
830349cc55cSDimitry Andric       assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&
831349cc55cSDimitry Andric              "Specified ContentSize is less than the RawContent size.");
832349cc55cSDimitry Andric       W.OS.write_zeros(*Obj.StrTbl.ContentSize -
833349cc55cSDimitry Andric                        Obj.StrTbl.RawContent->binary_size());
834fe6060f1SDimitry Andric     }
835349cc55cSDimitry Andric     return;
836349cc55cSDimitry Andric   }
837349cc55cSDimitry Andric 
838349cc55cSDimitry Andric   size_t StrTblBuilderSize = StrTblBuilder.getSize();
839349cc55cSDimitry Andric   // If neither Length nor ContentSize is specified, write the StrTblBuilder
840349cc55cSDimitry Andric   // directly, which contains the auto-generated Length value.
841349cc55cSDimitry Andric   if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {
842349cc55cSDimitry Andric     if (StrTblBuilderSize <= 4)
843349cc55cSDimitry Andric       return;
844349cc55cSDimitry Andric     StrTblBuilder.write(W.OS);
845349cc55cSDimitry Andric     return;
846349cc55cSDimitry Andric   }
847349cc55cSDimitry Andric 
848349cc55cSDimitry Andric   // Serialize the string table's content to a temporary buffer.
849349cc55cSDimitry Andric   std::unique_ptr<WritableMemoryBuffer> Buf =
850349cc55cSDimitry Andric       WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);
851349cc55cSDimitry Andric   uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
852349cc55cSDimitry Andric   StrTblBuilder.write(Ptr);
853349cc55cSDimitry Andric   // Replace the first 4 bytes, which contain the auto-generated Length value,
854349cc55cSDimitry Andric   // with the specified value.
855349cc55cSDimitry Andric   memset(Ptr, 0, 4);
856349cc55cSDimitry Andric   support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length
857349cc55cSDimitry Andric                                                     : *Obj.StrTbl.ContentSize);
858349cc55cSDimitry Andric   // Copy the buffer content to the actual output stream.
859349cc55cSDimitry Andric   W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());
860349cc55cSDimitry Andric   // Add zeros as padding after strings.
861349cc55cSDimitry Andric   if (Obj.StrTbl.ContentSize) {
862349cc55cSDimitry Andric     assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&
863349cc55cSDimitry Andric            "Specified ContentSize is less than the StringTableBuilder size.");
864349cc55cSDimitry Andric     W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);
865349cc55cSDimitry Andric   }
866349cc55cSDimitry Andric }
867349cc55cSDimitry Andric 
868349cc55cSDimitry Andric bool XCOFFWriter::writeXCOFF() {
869fe6060f1SDimitry Andric   if (!assignAddressesAndIndices())
870fe6060f1SDimitry Andric     return false;
871fe6060f1SDimitry Andric   StartOffset = W.OS.tell();
872fe6060f1SDimitry Andric   writeFileHeader();
873*0fca6ea1SDimitry Andric   if (InitFileHdr.AuxHeaderSize)
874349cc55cSDimitry Andric     writeAuxFileHeader();
875fe6060f1SDimitry Andric   if (!Obj.Sections.empty()) {
876*0fca6ea1SDimitry Andric     writeSectionHeaders();
877fe6060f1SDimitry Andric     if (!writeSectionData())
878fe6060f1SDimitry Andric       return false;
879fe6060f1SDimitry Andric     if (!writeRelocations())
880fe6060f1SDimitry Andric       return false;
881fe6060f1SDimitry Andric   }
882fe6060f1SDimitry Andric   if (!Obj.Symbols.empty() && !writeSymbols())
883fe6060f1SDimitry Andric     return false;
884349cc55cSDimitry Andric   writeStringTable();
885fe6060f1SDimitry Andric   return true;
886fe6060f1SDimitry Andric }
887fe6060f1SDimitry Andric 
888fe6060f1SDimitry Andric } // end anonymous namespace
889fe6060f1SDimitry Andric 
890fe6060f1SDimitry Andric namespace llvm {
891fe6060f1SDimitry Andric namespace yaml {
892fe6060f1SDimitry Andric 
893fe6060f1SDimitry Andric bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {
894fe6060f1SDimitry Andric   XCOFFWriter Writer(Doc, Out, EH);
895fe6060f1SDimitry Andric   return Writer.writeXCOFF();
896fe6060f1SDimitry Andric }
897fe6060f1SDimitry Andric 
898fe6060f1SDimitry Andric } // namespace yaml
899fe6060f1SDimitry Andric } // namespace llvm
900