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