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