xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjectYAML/XCOFFEmitter.cpp (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
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();
50fe6060f1SDimitry Andric   void writeFileHeader();
51349cc55cSDimitry Andric   void writeAuxFileHeader();
52fe6060f1SDimitry Andric   void writeSectionHeader();
53fe6060f1SDimitry Andric   bool writeSectionData();
54fe6060f1SDimitry Andric   bool writeRelocations();
55fe6060f1SDimitry Andric   bool writeSymbols();
56349cc55cSDimitry Andric   void writeStringTable();
57fe6060f1SDimitry Andric 
58fe6060f1SDimitry Andric   XCOFFYAML::Object &Obj;
59fe6060f1SDimitry Andric   bool Is64Bit = false;
60fe6060f1SDimitry Andric   support::endian::Writer W;
61fe6060f1SDimitry Andric   yaml::ErrorHandler ErrHandler;
62349cc55cSDimitry Andric   StringTableBuilder StrTblBuilder;
63fe6060f1SDimitry Andric   uint64_t StartOffset;
64fe6060f1SDimitry Andric   // Map the section name to its corrresponding section index.
65fe6060f1SDimitry Andric   DenseMap<StringRef, int16_t> SectionIndexMap = {
66fe6060f1SDimitry Andric       {StringRef("N_DEBUG"), XCOFF::N_DEBUG},
67fe6060f1SDimitry Andric       {StringRef("N_ABS"), XCOFF::N_ABS},
68fe6060f1SDimitry Andric       {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};
69fe6060f1SDimitry Andric   XCOFFYAML::FileHeader InitFileHdr = Obj.Header;
70349cc55cSDimitry Andric   XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;
71fe6060f1SDimitry Andric   std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;
72fe6060f1SDimitry Andric };
73fe6060f1SDimitry Andric 
74fe6060f1SDimitry Andric static void writeName(StringRef StrName, support::endian::Writer W) {
75fe6060f1SDimitry Andric   char Name[XCOFF::NameSize];
76fe6060f1SDimitry Andric   memset(Name, 0, XCOFF::NameSize);
77fe6060f1SDimitry Andric   char SrcName[] = "";
78fe6060f1SDimitry Andric   memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());
79fe6060f1SDimitry Andric   ArrayRef<char> NameRef(Name, XCOFF::NameSize);
80fe6060f1SDimitry Andric   W.write(NameRef);
81fe6060f1SDimitry Andric }
82fe6060f1SDimitry Andric 
83fe6060f1SDimitry Andric bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
84349cc55cSDimitry Andric   // For XCOFF64: The symbol name is always in the string table.
85349cc55cSDimitry Andric   return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
86fe6060f1SDimitry Andric }
87fe6060f1SDimitry Andric 
88fe6060f1SDimitry Andric bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
89*0eae32dcSDimitry Andric   for (XCOFFYAML::Section &InitSection : InitSections) {
90*0eae32dcSDimitry Andric     if (!InitSection.Relocations.empty()) {
91*0eae32dcSDimitry Andric       InitSection.NumberOfRelocations = InitSection.Relocations.size();
92*0eae32dcSDimitry Andric       InitSection.FileOffsetToRelocations = CurrentOffset;
93349cc55cSDimitry Andric       uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64
94349cc55cSDimitry Andric                                  : XCOFF::RelocationSerializationSize32;
95*0eae32dcSDimitry Andric       CurrentOffset += InitSection.NumberOfRelocations * RelSize;
96fe6060f1SDimitry Andric       if (CurrentOffset > MaxRawDataSize) {
97fe6060f1SDimitry Andric         ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
98fe6060f1SDimitry Andric                    "exceeded when writing relocation data");
99fe6060f1SDimitry Andric         return false;
100fe6060f1SDimitry Andric       }
101fe6060f1SDimitry Andric     }
102fe6060f1SDimitry Andric   }
103fe6060f1SDimitry Andric   return true;
104fe6060f1SDimitry Andric }
105fe6060f1SDimitry Andric 
106fe6060f1SDimitry Andric bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) {
107fe6060f1SDimitry Andric   uint64_t CurrentSecAddr = 0;
108fe6060f1SDimitry Andric   for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
109fe6060f1SDimitry Andric     if (CurrentOffset > MaxRawDataSize) {
110fe6060f1SDimitry Andric       ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
111fe6060f1SDimitry Andric                  "exceeded when writing section data");
112fe6060f1SDimitry Andric       return false;
113fe6060f1SDimitry Andric     }
114fe6060f1SDimitry Andric 
115fe6060f1SDimitry Andric     // Assign indices for sections.
116fe6060f1SDimitry Andric     if (InitSections[I].SectionName.size() &&
117fe6060f1SDimitry Andric         !SectionIndexMap[InitSections[I].SectionName]) {
118fe6060f1SDimitry Andric       // The section index starts from 1.
119fe6060f1SDimitry Andric       SectionIndexMap[InitSections[I].SectionName] = I + 1;
120fe6060f1SDimitry Andric       if ((I + 1) > MaxSectionIndex) {
121fe6060f1SDimitry Andric         ErrHandler("exceeded the maximum permitted section index of " +
122fe6060f1SDimitry Andric                    Twine(MaxSectionIndex));
123fe6060f1SDimitry Andric         return false;
124fe6060f1SDimitry Andric       }
125fe6060f1SDimitry Andric     }
126fe6060f1SDimitry Andric 
127fe6060f1SDimitry Andric     // Calculate the physical/virtual address. This field should contain 0 for
128fe6060f1SDimitry Andric     // all sections except the text, data and bss sections.
129fe6060f1SDimitry Andric     if (InitSections[I].Flags != XCOFF::STYP_TEXT &&
130fe6060f1SDimitry Andric         InitSections[I].Flags != XCOFF::STYP_DATA &&
131fe6060f1SDimitry Andric         InitSections[I].Flags != XCOFF::STYP_BSS)
132fe6060f1SDimitry Andric       InitSections[I].Address = 0;
133fe6060f1SDimitry Andric     else
134fe6060f1SDimitry Andric       InitSections[I].Address = CurrentSecAddr;
135fe6060f1SDimitry Andric 
136fe6060f1SDimitry Andric     // Calculate the FileOffsetToData and data size for sections.
137fe6060f1SDimitry Andric     if (InitSections[I].SectionData.binary_size()) {
138fe6060f1SDimitry Andric       InitSections[I].FileOffsetToData = CurrentOffset;
139fe6060f1SDimitry Andric       CurrentOffset += InitSections[I].SectionData.binary_size();
140fe6060f1SDimitry Andric       // Ensure the offset is aligned to DefaultSectionAlign.
141fe6060f1SDimitry Andric       CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);
142fe6060f1SDimitry Andric       InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData;
143fe6060f1SDimitry Andric       CurrentSecAddr += InitSections[I].Size;
144fe6060f1SDimitry Andric     }
145fe6060f1SDimitry Andric   }
146fe6060f1SDimitry Andric   return initRelocations(CurrentOffset);
147fe6060f1SDimitry Andric }
148fe6060f1SDimitry Andric 
149349cc55cSDimitry Andric bool XCOFFWriter::initStringTable() {
150349cc55cSDimitry Andric   if (Obj.StrTbl.RawContent) {
151349cc55cSDimitry Andric     size_t RawSize = Obj.StrTbl.RawContent->binary_size();
152349cc55cSDimitry Andric     if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {
153349cc55cSDimitry Andric       ErrHandler(
154349cc55cSDimitry Andric           "can't specify Strings or Length when RawContent is specified");
155349cc55cSDimitry Andric       return false;
156349cc55cSDimitry Andric     }
157349cc55cSDimitry Andric     if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {
158349cc55cSDimitry Andric       ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
159349cc55cSDimitry Andric                  ") is less than the RawContent data size (" + Twine(RawSize) +
160349cc55cSDimitry Andric                  ")");
161349cc55cSDimitry Andric       return false;
162349cc55cSDimitry Andric     }
163349cc55cSDimitry Andric     return true;
164349cc55cSDimitry Andric   }
165349cc55cSDimitry Andric   if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {
166349cc55cSDimitry Andric     ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
167349cc55cSDimitry Andric     return false;
168349cc55cSDimitry Andric   }
169349cc55cSDimitry Andric 
170349cc55cSDimitry Andric   // Build the string table.
171349cc55cSDimitry Andric   StrTblBuilder.clear();
172349cc55cSDimitry Andric 
173349cc55cSDimitry Andric   if (Obj.StrTbl.Strings) {
174349cc55cSDimitry Andric     // All specified strings should be added to the string table.
175349cc55cSDimitry Andric     for (StringRef StringEnt : *Obj.StrTbl.Strings)
176349cc55cSDimitry Andric       StrTblBuilder.add(StringEnt);
177349cc55cSDimitry Andric 
178349cc55cSDimitry Andric     size_t StrTblIdx = 0;
179349cc55cSDimitry Andric     size_t NumOfStrings = Obj.StrTbl.Strings->size();
180349cc55cSDimitry Andric     for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
181349cc55cSDimitry Andric       if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
182349cc55cSDimitry Andric         if (StrTblIdx < NumOfStrings) {
183349cc55cSDimitry Andric           // Overwrite the symbol name with the specified string.
184349cc55cSDimitry Andric           YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];
185349cc55cSDimitry Andric           ++StrTblIdx;
186349cc55cSDimitry Andric         } else
187349cc55cSDimitry Andric           // Names that are not overwritten are still stored in the string
188349cc55cSDimitry Andric           // table.
189349cc55cSDimitry Andric           StrTblBuilder.add(YamlSym.SymbolName);
190349cc55cSDimitry Andric       }
191349cc55cSDimitry Andric     }
192349cc55cSDimitry Andric   } else {
193349cc55cSDimitry Andric     for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
194349cc55cSDimitry Andric       if (nameShouldBeInStringTable(YamlSym.SymbolName))
195349cc55cSDimitry Andric         StrTblBuilder.add(YamlSym.SymbolName);
196349cc55cSDimitry Andric     }
197349cc55cSDimitry Andric   }
198349cc55cSDimitry Andric 
199349cc55cSDimitry Andric   StrTblBuilder.finalize();
200349cc55cSDimitry Andric 
201349cc55cSDimitry Andric   size_t StrTblSize = StrTblBuilder.getSize();
202349cc55cSDimitry Andric   if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {
203349cc55cSDimitry Andric     ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
204349cc55cSDimitry Andric                ") is less than the size of the data that would otherwise be "
205349cc55cSDimitry Andric                "written (" +
206349cc55cSDimitry Andric                Twine(StrTblSize) + ")");
207349cc55cSDimitry Andric     return false;
208349cc55cSDimitry Andric   }
209349cc55cSDimitry Andric 
210349cc55cSDimitry Andric   return true;
211349cc55cSDimitry Andric }
212349cc55cSDimitry Andric 
213fe6060f1SDimitry Andric bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {
214fe6060f1SDimitry Andric   // The default format of the object file is XCOFF32.
215fe6060f1SDimitry Andric   InitFileHdr.Magic = XCOFF::XCOFF32;
216fe6060f1SDimitry Andric   InitFileHdr.NumberOfSections = Obj.Sections.size();
217fe6060f1SDimitry Andric   InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();
218fe6060f1SDimitry Andric 
219349cc55cSDimitry Andric   for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols)
220fe6060f1SDimitry Andric     // Add the number of auxiliary symbols to the total number.
221fe6060f1SDimitry Andric     InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries;
222fe6060f1SDimitry Andric 
223fe6060f1SDimitry Andric   // Calculate SymbolTableOffset for the file header.
224fe6060f1SDimitry Andric   if (InitFileHdr.NumberOfSymTableEntries) {
225fe6060f1SDimitry Andric     InitFileHdr.SymbolTableOffset = CurrentOffset;
226fe6060f1SDimitry Andric     CurrentOffset +=
227fe6060f1SDimitry Andric         InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
228fe6060f1SDimitry Andric     if (CurrentOffset > MaxRawDataSize) {
229fe6060f1SDimitry Andric       ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
230fe6060f1SDimitry Andric                  "exceeded when writing symbols");
231fe6060f1SDimitry Andric       return false;
232fe6060f1SDimitry Andric     }
233fe6060f1SDimitry Andric   }
234fe6060f1SDimitry Andric   // TODO: Calculate FileOffsetToLineNumbers when line number supported.
235fe6060f1SDimitry Andric   return true;
236fe6060f1SDimitry Andric }
237fe6060f1SDimitry Andric 
238349cc55cSDimitry Andric void XCOFFWriter::initAuxFileHeader() {
239349cc55cSDimitry Andric   InitAuxFileHdr = *Obj.AuxHeader;
240349cc55cSDimitry Andric   // In general, an object file might contain multiple sections of a given type,
241349cc55cSDimitry Andric   // but in a loadable module, there must be exactly one .text, .data, .bss, and
242349cc55cSDimitry Andric   // .loader section. A loadable object might also have one .tdata section and
243349cc55cSDimitry Andric   // one .tbss section.
244349cc55cSDimitry Andric   // Set these section-related values if not set explicitly. We assume that the
245349cc55cSDimitry Andric   // input YAML matches the format of the loadable object, but if multiple input
246349cc55cSDimitry Andric   // sections still have the same type, the first section with that type
247349cc55cSDimitry Andric   // prevails.
248349cc55cSDimitry Andric   for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
249349cc55cSDimitry Andric     switch (InitSections[I].Flags) {
250349cc55cSDimitry Andric     case XCOFF::STYP_TEXT:
251349cc55cSDimitry Andric       if (!InitAuxFileHdr.TextSize)
252349cc55cSDimitry Andric         InitAuxFileHdr.TextSize = InitSections[I].Size;
253349cc55cSDimitry Andric       if (!InitAuxFileHdr.TextStartAddr)
254349cc55cSDimitry Andric         InitAuxFileHdr.TextStartAddr = InitSections[I].Address;
255349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfText)
256349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfText = I + 1;
257349cc55cSDimitry Andric       break;
258349cc55cSDimitry Andric     case XCOFF::STYP_DATA:
259349cc55cSDimitry Andric       if (!InitAuxFileHdr.InitDataSize)
260349cc55cSDimitry Andric         InitAuxFileHdr.InitDataSize = InitSections[I].Size;
261349cc55cSDimitry Andric       if (!InitAuxFileHdr.DataStartAddr)
262349cc55cSDimitry Andric         InitAuxFileHdr.DataStartAddr = InitSections[I].Address;
263349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfData)
264349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfData = I + 1;
265349cc55cSDimitry Andric       break;
266349cc55cSDimitry Andric     case XCOFF::STYP_BSS:
267349cc55cSDimitry Andric       if (!InitAuxFileHdr.BssDataSize)
268349cc55cSDimitry Andric         InitAuxFileHdr.BssDataSize = InitSections[I].Size;
269349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfBSS)
270349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfBSS = I + 1;
271349cc55cSDimitry Andric       break;
272349cc55cSDimitry Andric     case XCOFF::STYP_TDATA:
273349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfTData)
274349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfTData = I + 1;
275349cc55cSDimitry Andric       break;
276349cc55cSDimitry Andric     case XCOFF::STYP_TBSS:
277349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfTBSS)
278349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfTBSS = I + 1;
279349cc55cSDimitry Andric       break;
280349cc55cSDimitry Andric     case XCOFF::STYP_LOADER:
281349cc55cSDimitry Andric       if (!InitAuxFileHdr.SecNumOfLoader)
282349cc55cSDimitry Andric         InitAuxFileHdr.SecNumOfLoader = I + 1;
283349cc55cSDimitry Andric       break;
284349cc55cSDimitry Andric     default:
285349cc55cSDimitry Andric       break;
286349cc55cSDimitry Andric     }
287349cc55cSDimitry Andric   }
288349cc55cSDimitry Andric }
289349cc55cSDimitry Andric 
290fe6060f1SDimitry Andric bool XCOFFWriter::assignAddressesAndIndices() {
291349cc55cSDimitry Andric   uint64_t FileHdrSize =
292349cc55cSDimitry Andric       Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;
293349cc55cSDimitry Andric   uint64_t AuxFileHdrSize = 0;
294349cc55cSDimitry Andric   if (Obj.AuxHeader)
295349cc55cSDimitry Andric     AuxFileHdrSize = Obj.Header.AuxHeaderSize
296349cc55cSDimitry Andric                          ? Obj.Header.AuxHeaderSize
297349cc55cSDimitry Andric                          : (Is64Bit ? XCOFF::AuxFileHeaderSize64
298349cc55cSDimitry Andric                                     : XCOFF::AuxFileHeaderSize32);
299349cc55cSDimitry Andric   uint64_t SecHdrSize =
300349cc55cSDimitry Andric       Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;
301fe6060f1SDimitry Andric   uint64_t CurrentOffset =
302349cc55cSDimitry Andric       FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;
303fe6060f1SDimitry Andric 
304fe6060f1SDimitry Andric   // Calculate section header info.
305fe6060f1SDimitry Andric   if (!initSectionHeader(CurrentOffset))
306fe6060f1SDimitry Andric     return false;
307349cc55cSDimitry Andric   InitFileHdr.AuxHeaderSize = AuxFileHdrSize;
308349cc55cSDimitry Andric 
309fe6060f1SDimitry Andric   // Calculate file header info.
310349cc55cSDimitry Andric   if (!initFileHeader(CurrentOffset))
311349cc55cSDimitry Andric     return false;
312349cc55cSDimitry Andric 
313349cc55cSDimitry Andric   // Initialize the auxiliary file header.
314349cc55cSDimitry Andric   if (Obj.AuxHeader)
315349cc55cSDimitry Andric     initAuxFileHeader();
316349cc55cSDimitry Andric 
317349cc55cSDimitry Andric   // Initialize the string table.
318349cc55cSDimitry Andric   return initStringTable();
319fe6060f1SDimitry Andric }
320fe6060f1SDimitry Andric 
321fe6060f1SDimitry Andric void XCOFFWriter::writeFileHeader() {
322fe6060f1SDimitry Andric   W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);
323fe6060f1SDimitry Andric   W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
324fe6060f1SDimitry Andric                                                 : InitFileHdr.NumberOfSections);
325fe6060f1SDimitry Andric   W.write<int32_t>(Obj.Header.TimeStamp);
326349cc55cSDimitry Andric   if (Is64Bit) {
327349cc55cSDimitry Andric     W.write<uint64_t>(Obj.Header.SymbolTableOffset
328349cc55cSDimitry Andric                           ? Obj.Header.SymbolTableOffset
329349cc55cSDimitry Andric                           : InitFileHdr.SymbolTableOffset);
330349cc55cSDimitry Andric     W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
331349cc55cSDimitry Andric     W.write<uint16_t>(Obj.Header.Flags);
332349cc55cSDimitry Andric     W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
333349cc55cSDimitry Andric                          ? Obj.Header.NumberOfSymTableEntries
334349cc55cSDimitry Andric                          : InitFileHdr.NumberOfSymTableEntries);
335349cc55cSDimitry Andric   } else {
336fe6060f1SDimitry Andric     W.write<uint32_t>(Obj.Header.SymbolTableOffset
337fe6060f1SDimitry Andric                           ? Obj.Header.SymbolTableOffset
338fe6060f1SDimitry Andric                           : InitFileHdr.SymbolTableOffset);
339fe6060f1SDimitry Andric     W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
340fe6060f1SDimitry Andric                          ? Obj.Header.NumberOfSymTableEntries
341fe6060f1SDimitry Andric                          : InitFileHdr.NumberOfSymTableEntries);
342349cc55cSDimitry Andric     W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
343fe6060f1SDimitry Andric     W.write<uint16_t>(Obj.Header.Flags);
344fe6060f1SDimitry Andric   }
345349cc55cSDimitry Andric }
346349cc55cSDimitry Andric 
347349cc55cSDimitry Andric void XCOFFWriter::writeAuxFileHeader() {
348349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.Magic.getValueOr(yaml::Hex16(1)));
349349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.Version.getValueOr(yaml::Hex16(1)));
350349cc55cSDimitry Andric   if (Is64Bit) {
351349cc55cSDimitry Andric     W.OS.write_zeros(4); // Reserved for debugger.
352349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0)));
353349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0)));
354349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0)));
355349cc55cSDimitry Andric   } else {
356349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0)));
357349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0)));
358349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0)));
359349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0)));
360349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0)));
361349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0)));
362349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0)));
363349cc55cSDimitry Andric   }
364349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.getValueOr(0));
365349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.getValueOr(0));
366349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.getValueOr(0));
367349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.getValueOr(0));
368349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.getValueOr(0));
369349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.getValueOr(0));
370349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.getValueOr(yaml::Hex16(0)));
371349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.getValueOr(yaml::Hex16(0)));
372349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.ModuleType.getValueOr(yaml::Hex16(0)));
373349cc55cSDimitry Andric   W.write<uint8_t>(InitAuxFileHdr.CpuFlag.getValueOr(yaml::Hex8(0)));
374349cc55cSDimitry Andric   W.write<uint8_t>(0); // Reserved for CPU type.
375349cc55cSDimitry Andric   if (Is64Bit) {
376349cc55cSDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0)));
377349cc55cSDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0)));
378349cc55cSDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0)));
379349cc55cSDimitry Andric     W.write<uint8_t>(
380349cc55cSDimitry Andric         InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0x80)));
381349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0)));
382349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0)));
383349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0)));
384349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0)));
385349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0)));
386349cc55cSDimitry Andric     W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0)));
387349cc55cSDimitry Andric   } else {
388349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0)));
389349cc55cSDimitry Andric     W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0)));
390349cc55cSDimitry Andric     W.OS.write_zeros(4); // Reserved for debugger.
391349cc55cSDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0)));
392349cc55cSDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0)));
393349cc55cSDimitry Andric     W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0)));
394349cc55cSDimitry Andric     W.write<uint8_t>(
395349cc55cSDimitry Andric         InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0)));
396349cc55cSDimitry Andric   }
397349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.getValueOr(0));
398349cc55cSDimitry Andric   W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.getValueOr(0));
399349cc55cSDimitry Andric   if (Is64Bit) {
400349cc55cSDimitry Andric     W.write<uint16_t>(InitAuxFileHdr.Flag.getValueOr(yaml::Hex16(XCOFF::SHR_SYMTAB)));
401349cc55cSDimitry Andric     if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)
402349cc55cSDimitry Andric       W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);
403349cc55cSDimitry Andric   } else if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) {
404349cc55cSDimitry Andric     W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);
405349cc55cSDimitry Andric   }
406349cc55cSDimitry Andric }
407fe6060f1SDimitry Andric 
408fe6060f1SDimitry Andric void XCOFFWriter::writeSectionHeader() {
409fe6060f1SDimitry Andric   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
410fe6060f1SDimitry Andric     XCOFFYAML::Section YamlSec = Obj.Sections[I];
411fe6060f1SDimitry Andric     XCOFFYAML::Section DerivedSec = InitSections[I];
412fe6060f1SDimitry Andric     writeName(YamlSec.SectionName, W);
413fe6060f1SDimitry Andric     // Virtual address is the same as physical address.
414349cc55cSDimitry Andric     uint64_t SectionAddress =
415fe6060f1SDimitry Andric         YamlSec.Address ? YamlSec.Address : DerivedSec.Address;
416349cc55cSDimitry Andric     if (Is64Bit) {
417349cc55cSDimitry Andric       W.write<uint64_t>(SectionAddress); // Physical address
418349cc55cSDimitry Andric       W.write<uint64_t>(SectionAddress); // Virtual address
419349cc55cSDimitry Andric       W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
420349cc55cSDimitry Andric       W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
421349cc55cSDimitry Andric                                                  : DerivedSec.FileOffsetToData);
422349cc55cSDimitry Andric       W.write<uint64_t>(YamlSec.FileOffsetToRelocations
423349cc55cSDimitry Andric                             ? YamlSec.FileOffsetToRelocations
424349cc55cSDimitry Andric                             : DerivedSec.FileOffsetToRelocations);
425349cc55cSDimitry Andric       W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers);
426349cc55cSDimitry Andric       W.write<uint32_t>(YamlSec.NumberOfRelocations
427349cc55cSDimitry Andric                             ? YamlSec.NumberOfRelocations
428349cc55cSDimitry Andric                             : DerivedSec.NumberOfRelocations);
429349cc55cSDimitry Andric       W.write<uint32_t>(YamlSec.NumberOfLineNumbers);
430349cc55cSDimitry Andric       W.write<int32_t>(YamlSec.Flags);
431349cc55cSDimitry Andric       W.OS.write_zeros(4);
432349cc55cSDimitry Andric     } else {
433fe6060f1SDimitry Andric       W.write<uint32_t>(SectionAddress); // Physical address
434fe6060f1SDimitry Andric       W.write<uint32_t>(SectionAddress); // Virtual address
435fe6060f1SDimitry Andric       W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
436fe6060f1SDimitry Andric       W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
437fe6060f1SDimitry Andric                                                  : DerivedSec.FileOffsetToData);
438fe6060f1SDimitry Andric       W.write<uint32_t>(YamlSec.FileOffsetToRelocations
439fe6060f1SDimitry Andric                             ? YamlSec.FileOffsetToRelocations
440fe6060f1SDimitry Andric                             : DerivedSec.FileOffsetToRelocations);
441fe6060f1SDimitry Andric       W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers);
442fe6060f1SDimitry Andric       W.write<uint16_t>(YamlSec.NumberOfRelocations
443fe6060f1SDimitry Andric                             ? YamlSec.NumberOfRelocations
444fe6060f1SDimitry Andric                             : DerivedSec.NumberOfRelocations);
445fe6060f1SDimitry Andric       W.write<uint16_t>(YamlSec.NumberOfLineNumbers);
446fe6060f1SDimitry Andric       W.write<int32_t>(YamlSec.Flags);
447fe6060f1SDimitry Andric     }
448fe6060f1SDimitry Andric   }
449349cc55cSDimitry Andric }
450fe6060f1SDimitry Andric 
451fe6060f1SDimitry Andric bool XCOFFWriter::writeSectionData() {
452fe6060f1SDimitry Andric   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
453fe6060f1SDimitry Andric     XCOFFYAML::Section YamlSec = Obj.Sections[I];
454fe6060f1SDimitry Andric     if (YamlSec.SectionData.binary_size()) {
455fe6060f1SDimitry Andric       // Fill the padding size with zeros.
456fe6060f1SDimitry Andric       int64_t PaddingSize =
457fe6060f1SDimitry Andric           InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset);
458fe6060f1SDimitry Andric       if (PaddingSize < 0) {
459fe6060f1SDimitry Andric         ErrHandler("redundant data was written before section data");
460fe6060f1SDimitry Andric         return false;
461fe6060f1SDimitry Andric       }
462fe6060f1SDimitry Andric       W.OS.write_zeros(PaddingSize);
463fe6060f1SDimitry Andric       YamlSec.SectionData.writeAsBinary(W.OS);
464fe6060f1SDimitry Andric     }
465fe6060f1SDimitry Andric   }
466fe6060f1SDimitry Andric   return true;
467fe6060f1SDimitry Andric }
468fe6060f1SDimitry Andric 
469fe6060f1SDimitry Andric bool XCOFFWriter::writeRelocations() {
470fe6060f1SDimitry Andric   for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
471fe6060f1SDimitry Andric     XCOFFYAML::Section YamlSec = Obj.Sections[I];
472fe6060f1SDimitry Andric     if (!YamlSec.Relocations.empty()) {
473fe6060f1SDimitry Andric       int64_t PaddingSize =
474fe6060f1SDimitry Andric           InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);
475fe6060f1SDimitry Andric       if (PaddingSize < 0) {
476fe6060f1SDimitry Andric         ErrHandler("redundant data was written before relocations");
477fe6060f1SDimitry Andric         return false;
478fe6060f1SDimitry Andric       }
479fe6060f1SDimitry Andric       W.OS.write_zeros(PaddingSize);
480fe6060f1SDimitry Andric       for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
481349cc55cSDimitry Andric         if (Is64Bit)
482349cc55cSDimitry Andric           W.write<uint64_t>(YamlRel.VirtualAddress);
483349cc55cSDimitry Andric         else
484fe6060f1SDimitry Andric           W.write<uint32_t>(YamlRel.VirtualAddress);
485fe6060f1SDimitry Andric         W.write<uint32_t>(YamlRel.SymbolIndex);
486fe6060f1SDimitry Andric         W.write<uint8_t>(YamlRel.Info);
487fe6060f1SDimitry Andric         W.write<uint8_t>(YamlRel.Type);
488fe6060f1SDimitry Andric       }
489fe6060f1SDimitry Andric     }
490fe6060f1SDimitry Andric   }
491fe6060f1SDimitry Andric   return true;
492fe6060f1SDimitry Andric }
493fe6060f1SDimitry Andric 
494fe6060f1SDimitry Andric bool XCOFFWriter::writeSymbols() {
495fe6060f1SDimitry Andric   int64_t PaddingSize =
496fe6060f1SDimitry Andric       (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);
497fe6060f1SDimitry Andric   if (PaddingSize < 0) {
498fe6060f1SDimitry Andric     ErrHandler("redundant data was written before symbols");
499fe6060f1SDimitry Andric     return false;
500fe6060f1SDimitry Andric   }
501fe6060f1SDimitry Andric   W.OS.write_zeros(PaddingSize);
502fe6060f1SDimitry Andric   for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
503349cc55cSDimitry Andric     if (Is64Bit) {
504349cc55cSDimitry Andric       W.write<uint64_t>(YamlSym.Value);
505349cc55cSDimitry Andric       W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
506349cc55cSDimitry Andric     } else {
507fe6060f1SDimitry Andric       if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
508fe6060f1SDimitry Andric         // For XCOFF32: A value of 0 indicates that the symbol name is in the
509fe6060f1SDimitry Andric         // string table.
510fe6060f1SDimitry Andric         W.write<int32_t>(0);
511349cc55cSDimitry Andric         W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
512fe6060f1SDimitry Andric       } else {
513fe6060f1SDimitry Andric         writeName(YamlSym.SymbolName, W);
514fe6060f1SDimitry Andric       }
515fe6060f1SDimitry Andric       W.write<uint32_t>(YamlSym.Value);
516349cc55cSDimitry Andric     }
517349cc55cSDimitry Andric     if (YamlSym.SectionName) {
518349cc55cSDimitry Andric       if (!SectionIndexMap.count(*YamlSym.SectionName)) {
519349cc55cSDimitry Andric         ErrHandler("the SectionName " + *YamlSym.SectionName +
520349cc55cSDimitry Andric                    " specified in the symbol does not exist");
521349cc55cSDimitry Andric         return false;
522349cc55cSDimitry Andric       }
523349cc55cSDimitry Andric       if (YamlSym.SectionIndex &&
524349cc55cSDimitry Andric           SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) {
525349cc55cSDimitry Andric         ErrHandler("the SectionName " + *YamlSym.SectionName +
526349cc55cSDimitry Andric                    " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +
527349cc55cSDimitry Andric                    ") refer to different sections");
528349cc55cSDimitry Andric         return false;
529349cc55cSDimitry Andric       }
530349cc55cSDimitry Andric       W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]);
531349cc55cSDimitry Andric     } else {
532349cc55cSDimitry Andric       W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0);
533349cc55cSDimitry Andric     }
534fe6060f1SDimitry Andric     W.write<uint16_t>(YamlSym.Type);
535fe6060f1SDimitry Andric     W.write<uint8_t>(YamlSym.StorageClass);
536fe6060f1SDimitry Andric     W.write<uint8_t>(YamlSym.NumberOfAuxEntries);
537fe6060f1SDimitry Andric 
538fe6060f1SDimitry Andric     // Now output the auxiliary entry.
539fe6060f1SDimitry Andric     for (uint8_t I = 0, E = YamlSym.NumberOfAuxEntries; I < E; ++I) {
540fe6060f1SDimitry Andric       // TODO: Auxiliary entry is not supported yet.
541fe6060f1SDimitry Andric       // The auxiliary entries for a symbol follow its symbol table entry. The
542fe6060f1SDimitry Andric       // length of each auxiliary entry is the same as a symbol table entry (18
543fe6060f1SDimitry Andric       // bytes). The format and quantity of auxiliary entries depend on the
544fe6060f1SDimitry Andric       // storage class (n_sclass) and type (n_type) of the symbol table entry.
545349cc55cSDimitry Andric       W.OS.write_zeros(XCOFF::SymbolTableEntrySize);
546fe6060f1SDimitry Andric     }
547fe6060f1SDimitry Andric   }
548fe6060f1SDimitry Andric   return true;
549fe6060f1SDimitry Andric }
550fe6060f1SDimitry Andric 
551349cc55cSDimitry Andric void XCOFFWriter::writeStringTable() {
552349cc55cSDimitry Andric   if (Obj.StrTbl.RawContent) {
553349cc55cSDimitry Andric     Obj.StrTbl.RawContent->writeAsBinary(W.OS);
554349cc55cSDimitry Andric     if (Obj.StrTbl.ContentSize) {
555349cc55cSDimitry Andric       assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&
556349cc55cSDimitry Andric              "Specified ContentSize is less than the RawContent size.");
557349cc55cSDimitry Andric       W.OS.write_zeros(*Obj.StrTbl.ContentSize -
558349cc55cSDimitry Andric                        Obj.StrTbl.RawContent->binary_size());
559fe6060f1SDimitry Andric     }
560349cc55cSDimitry Andric     return;
561349cc55cSDimitry Andric   }
562349cc55cSDimitry Andric 
563349cc55cSDimitry Andric   size_t StrTblBuilderSize = StrTblBuilder.getSize();
564349cc55cSDimitry Andric   // If neither Length nor ContentSize is specified, write the StrTblBuilder
565349cc55cSDimitry Andric   // directly, which contains the auto-generated Length value.
566349cc55cSDimitry Andric   if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {
567349cc55cSDimitry Andric     if (StrTblBuilderSize <= 4)
568349cc55cSDimitry Andric       return;
569349cc55cSDimitry Andric     StrTblBuilder.write(W.OS);
570349cc55cSDimitry Andric     return;
571349cc55cSDimitry Andric   }
572349cc55cSDimitry Andric 
573349cc55cSDimitry Andric   // Serialize the string table's content to a temporary buffer.
574349cc55cSDimitry Andric   std::unique_ptr<WritableMemoryBuffer> Buf =
575349cc55cSDimitry Andric       WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);
576349cc55cSDimitry Andric   uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
577349cc55cSDimitry Andric   StrTblBuilder.write(Ptr);
578349cc55cSDimitry Andric   // Replace the first 4 bytes, which contain the auto-generated Length value,
579349cc55cSDimitry Andric   // with the specified value.
580349cc55cSDimitry Andric   memset(Ptr, 0, 4);
581349cc55cSDimitry Andric   support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length
582349cc55cSDimitry Andric                                                     : *Obj.StrTbl.ContentSize);
583349cc55cSDimitry Andric   // Copy the buffer content to the actual output stream.
584349cc55cSDimitry Andric   W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());
585349cc55cSDimitry Andric   // Add zeros as padding after strings.
586349cc55cSDimitry Andric   if (Obj.StrTbl.ContentSize) {
587349cc55cSDimitry Andric     assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&
588349cc55cSDimitry Andric            "Specified ContentSize is less than the StringTableBuilder size.");
589349cc55cSDimitry Andric     W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);
590349cc55cSDimitry Andric   }
591349cc55cSDimitry Andric }
592349cc55cSDimitry Andric 
593349cc55cSDimitry Andric bool XCOFFWriter::writeXCOFF() {
594fe6060f1SDimitry Andric   if (!assignAddressesAndIndices())
595fe6060f1SDimitry Andric     return false;
596fe6060f1SDimitry Andric   StartOffset = W.OS.tell();
597fe6060f1SDimitry Andric   writeFileHeader();
598349cc55cSDimitry Andric   if (Obj.AuxHeader)
599349cc55cSDimitry Andric     writeAuxFileHeader();
600fe6060f1SDimitry Andric   if (!Obj.Sections.empty()) {
601fe6060f1SDimitry Andric     writeSectionHeader();
602fe6060f1SDimitry Andric     if (!writeSectionData())
603fe6060f1SDimitry Andric       return false;
604fe6060f1SDimitry Andric     if (!writeRelocations())
605fe6060f1SDimitry Andric       return false;
606fe6060f1SDimitry Andric   }
607fe6060f1SDimitry Andric   if (!Obj.Symbols.empty() && !writeSymbols())
608fe6060f1SDimitry Andric     return false;
609349cc55cSDimitry Andric   writeStringTable();
610fe6060f1SDimitry Andric   return true;
611fe6060f1SDimitry Andric }
612fe6060f1SDimitry Andric 
613fe6060f1SDimitry Andric } // end anonymous namespace
614fe6060f1SDimitry Andric 
615fe6060f1SDimitry Andric namespace llvm {
616fe6060f1SDimitry Andric namespace yaml {
617fe6060f1SDimitry Andric 
618fe6060f1SDimitry Andric bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {
619fe6060f1SDimitry Andric   XCOFFWriter Writer(Doc, Out, EH);
620fe6060f1SDimitry Andric   return Writer.writeXCOFF();
621fe6060f1SDimitry Andric }
622fe6060f1SDimitry Andric 
623fe6060f1SDimitry Andric } // namespace yaml
624fe6060f1SDimitry Andric } // namespace llvm
625