1 //===-- lib/MC/XCOFFObjectWriter.cpp - XCOFF file writer ------------------===//
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 // This file implements XCOFF object file writer information.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/BinaryFormat/XCOFF.h"
14 #include "llvm/MC/MCAsmLayout.h"
15 #include "llvm/MC/MCAssembler.h"
16 #include "llvm/MC/MCObjectWriter.h"
17 #include "llvm/MC/MCSectionXCOFF.h"
18 #include "llvm/MC/MCSymbolXCOFF.h"
19 #include "llvm/MC/MCValue.h"
20 #include "llvm/MC/MCXCOFFObjectWriter.h"
21 #include "llvm/MC/StringTableBuilder.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/MathExtras.h"
24 
25 #include <deque>
26 
27 using namespace llvm;
28 
29 // An XCOFF object file has a limited set of predefined sections. The most
30 // important ones for us (right now) are:
31 // .text --> contains program code and read-only data.
32 // .data --> contains initialized data, function descriptors, and the TOC.
33 // .bss  --> contains uninitialized data.
34 // Each of these sections is composed of 'Control Sections'. A Control Section
35 // is more commonly referred to as a csect. A csect is an indivisible unit of
36 // code or data, and acts as a container for symbols. A csect is mapped
37 // into a section based on its storage-mapping class, with the exception of
38 // XMC_RW which gets mapped to either .data or .bss based on whether it's
39 // explicitly initialized or not.
40 //
41 // We don't represent the sections in the MC layer as there is nothing
42 // interesting about them at at that level: they carry information that is
43 // only relevant to the ObjectWriter, so we materialize them in this class.
44 namespace {
45 
46 constexpr unsigned DefaultSectionAlign = 4;
47 constexpr int16_t MaxSectionIndex = INT16_MAX;
48 
49 // Packs the csect's alignment and type into a byte.
50 uint8_t getEncodedType(const MCSectionXCOFF *);
51 
52 // Wrapper around an MCSymbolXCOFF.
53 struct Symbol {
54   const MCSymbolXCOFF *const MCSym;
55   uint32_t SymbolTableIndex;
56 
57   XCOFF::StorageClass getStorageClass() const {
58     return MCSym->getStorageClass();
59   }
60   StringRef getName() const { return MCSym->getName(); }
61   Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {}
62 };
63 
64 // Wrapper for an MCSectionXCOFF.
65 struct ControlSection {
66   const MCSectionXCOFF *const MCCsect;
67   uint32_t SymbolTableIndex;
68   uint32_t Address;
69   uint32_t Size;
70 
71   SmallVector<Symbol, 1> Syms;
72   StringRef getName() const { return MCCsect->getSectionName(); }
73   ControlSection(const MCSectionXCOFF *MCSec)
74       : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {}
75 };
76 
77 // Type to be used for a container representing a set of csects with
78 // (approximately) the same storage mapping class. For example all the csects
79 // with a storage mapping class of `xmc_pr` will get placed into the same
80 // container.
81 struct CsectGroup {
82   enum LabelDefinitionSupport : bool {
83     LabelDefSupported = true,
84     LabelDefUnsupported = false
85   };
86 
87   const LabelDefinitionSupport SupportLabelDef;
88   std::deque<ControlSection> Csects;
89 };
90 
91 using CsectGroups = std::deque<CsectGroup *>;
92 
93 // Represents the data related to a section excluding the csects that make up
94 // the raw data of the section. The csects are stored separately as not all
95 // sections contain csects, and some sections contain csects which are better
96 // stored separately, e.g. the .data section containing read-write, descriptor,
97 // TOCBase and TOC-entry csects.
98 struct Section {
99   char Name[XCOFF::NameSize];
100   // The physical/virtual address of the section. For an object file
101   // these values are equivalent.
102   uint32_t Address;
103   uint32_t Size;
104   uint32_t FileOffsetToData;
105   uint32_t FileOffsetToRelocations;
106   uint32_t RelocationCount;
107   int32_t Flags;
108 
109   int16_t Index;
110 
111   // Virtual sections do not need storage allocated in the object file.
112   const bool IsVirtual;
113 
114   // XCOFF has special section numbers for symbols:
115   // -2 Specifies N_DEBUG, a special symbolic debugging symbol.
116   // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not
117   // relocatable.
118   //  0 Specifies N_UNDEF, an undefined external symbol.
119   // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that
120   // hasn't been initialized.
121   static constexpr int16_t UninitializedIndex =
122       XCOFF::ReservedSectionNum::N_DEBUG - 1;
123 
124   CsectGroups Groups;
125 
126   void reset() {
127     Address = 0;
128     Size = 0;
129     FileOffsetToData = 0;
130     FileOffsetToRelocations = 0;
131     RelocationCount = 0;
132     Index = UninitializedIndex;
133     // Clear any csects we have stored.
134     for (auto *Group : Groups)
135       Group->Csects.clear();
136   }
137 
138   Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual,
139           CsectGroups Groups)
140       : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0),
141         RelocationCount(0), Flags(Flags), Index(UninitializedIndex),
142         IsVirtual(IsVirtual), Groups(Groups) {
143     strncpy(Name, N, XCOFF::NameSize);
144   }
145 };
146 
147 class XCOFFObjectWriter : public MCObjectWriter {
148 
149   uint32_t SymbolTableEntryCount = 0;
150   uint32_t SymbolTableOffset = 0;
151   uint16_t SectionCount = 0;
152 
153   support::endian::Writer W;
154   std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
155   StringTableBuilder Strings;
156 
157   // CsectGroups. These store the csects which make up different parts of
158   // the sections. Should have one for each set of csects that get mapped into
159   // the same section and get handled in a 'similar' way.
160   CsectGroup ProgramCodeCsects{CsectGroup::LabelDefSupported, {}};
161   CsectGroup DataCsects{CsectGroup::LabelDefSupported, {}};
162   CsectGroup BSSCsects{CsectGroup::LabelDefUnsupported, {}};
163 
164   // The Predefined sections.
165   Section Text;
166   Section Data;
167   Section BSS;
168 
169   // All the XCOFF sections, in the order they will appear in the section header
170   // table.
171   std::array<Section *const, 3> Sections{{&Text, &Data, &BSS}};
172 
173   CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec);
174 
175   virtual void reset() override;
176 
177   void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
178 
179   void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *,
180                         const MCFixup &, MCValue, uint64_t &) override;
181 
182   uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
183 
184   static bool nameShouldBeInStringTable(const StringRef &);
185   void writeSymbolName(const StringRef &);
186   void writeSymbolTableEntryForCsectMemberLabel(const Symbol &,
187                                                 const ControlSection &, int16_t,
188                                                 uint64_t);
189   void writeSymbolTableEntryForControlSection(const ControlSection &, int16_t,
190                                               XCOFF::StorageClass);
191   void writeFileHeader();
192   void writeSectionHeaderTable();
193   void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout);
194   void writeSymbolTable(const MCAsmLayout &Layout);
195 
196   // Called after all the csects and symbols have been processed by
197   // `executePostLayoutBinding`, this function handles building up the majority
198   // of the structures in the object file representation. Namely:
199   // *) Calculates physical/virtual addresses, raw-pointer offsets, and section
200   //    sizes.
201   // *) Assigns symbol table indices.
202   // *) Builds up the section header table by adding any non-empty sections to
203   //    `Sections`.
204   void assignAddressesAndIndices(const MCAsmLayout &);
205 
206   bool
207   needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */
208     return false;
209   }
210 
211   // Returns the size of the auxiliary header to be written to the object file.
212   size_t auxiliaryHeaderSize() const {
213     assert(!needsAuxiliaryHeader() &&
214            "Auxiliary header support not implemented.");
215     return 0;
216   }
217 
218 public:
219   XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
220                     raw_pwrite_stream &OS);
221 };
222 
223 XCOFFObjectWriter::XCOFFObjectWriter(
224     std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
225     : W(OS, support::big), TargetObjectWriter(std::move(MOTW)),
226       Strings(StringTableBuilder::XCOFF),
227       Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false,
228            CsectGroups{&ProgramCodeCsects}),
229       Data(".data", XCOFF::STYP_DATA, /* IsVirtual */ false,
230            CsectGroups{&DataCsects}),
231       BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true,
232           CsectGroups{&BSSCsects}) {}
233 
234 void XCOFFObjectWriter::reset() {
235   // Reset any sections we have written to, and empty the section header table.
236   for (auto *Sec : Sections)
237     Sec->reset();
238 
239   // Reset the symbol table and string table.
240   SymbolTableEntryCount = 0;
241   SymbolTableOffset = 0;
242   SectionCount = 0;
243   Strings.clear();
244 
245   MCObjectWriter::reset();
246 }
247 
248 CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) {
249   switch (MCSec->getMappingClass()) {
250   case XCOFF::XMC_PR:
251     assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
252            "Only an initialized csect can contain program code.");
253     return ProgramCodeCsects;
254   case XCOFF::XMC_RW:
255     if (XCOFF::XTY_CM == MCSec->getCSectType())
256       return BSSCsects;
257 
258     if (XCOFF::XTY_SD == MCSec->getCSectType())
259       return DataCsects;
260 
261     report_fatal_error("Unhandled mapping of read-write csect to section.");
262   case XCOFF::XMC_BS:
263     assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
264            "Mapping invalid csect. CSECT with bss storage class must be "
265            "common type.");
266     return BSSCsects;
267   default:
268     report_fatal_error("Unhandled mapping of csect to section.");
269   }
270 }
271 
272 void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
273                                                  const MCAsmLayout &Layout) {
274   if (TargetObjectWriter->is64Bit())
275     report_fatal_error("64-bit XCOFF object files are not supported yet.");
276 
277   // Maps the MC Section representation to its corresponding ControlSection
278   // wrapper. Needed for finding the ControlSection to insert an MCSymbol into
279   // from its containing MCSectionXCOFF.
280   DenseMap<const MCSectionXCOFF *, ControlSection *> WrapperMap;
281 
282   for (const auto &S : Asm) {
283     const auto *MCSec = cast<const MCSectionXCOFF>(&S);
284     assert(WrapperMap.find(MCSec) == WrapperMap.end() &&
285            "Cannot add a csect twice.");
286 
287     // If the name does not fit in the storage provided in the symbol table
288     // entry, add it to the string table.
289     if (nameShouldBeInStringTable(MCSec->getSectionName()))
290       Strings.add(MCSec->getSectionName());
291 
292     // TODO FIXME Handle emiting the TOC base.
293     if (MCSec->getMappingClass() == XCOFF::XMC_TC0)
294       continue;
295 
296     CsectGroup &Group = getCsectGroup(MCSec);
297     Group.Csects.emplace_back(MCSec);
298     WrapperMap[MCSec] = &Group.Csects.back();
299   }
300 
301   for (const MCSymbol &S : Asm.symbols()) {
302     // Nothing to do for temporary symbols.
303     if (S.isTemporary())
304       continue;
305     const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S);
306 
307     // Map the symbol into its containing csect.
308     const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect();
309     assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() &&
310            "Expected containing csect to exist in map");
311 
312     // Lookup the containing csect and add the symbol to it.
313     WrapperMap[ContainingCsect]->Syms.emplace_back(XSym);
314 
315     // If the name does not fit in the storage provided in the symbol table
316     // entry, add it to the string table.
317     if (nameShouldBeInStringTable(XSym->getName()))
318       Strings.add(XSym->getName());
319     }
320 
321   Strings.finalize();
322   assignAddressesAndIndices(Layout);
323 }
324 
325 void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &,
326                                          const MCFragment *, const MCFixup &,
327                                          MCValue, uint64_t &) {
328   report_fatal_error("XCOFF relocations not supported.");
329 }
330 
331 void XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
332                                       const MCAsmLayout &Layout) {
333   uint32_t CurrentAddressLocation = 0;
334   for (const auto *Section : Sections) {
335     // Nothing to write for this Section.
336     if (Section->Index == Section::UninitializedIndex || Section->IsVirtual)
337       continue;
338 
339     assert(CurrentAddressLocation == Section->Address &&
340            "We should have no padding between sections.");
341     for (const auto *Group : Section->Groups) {
342       for (const auto &Csect : Group->Csects) {
343         if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation)
344           W.OS.write_zeros(PaddingSize);
345         Asm.writeSectionData(W.OS, Csect.MCCsect, Layout);
346         CurrentAddressLocation = Csect.Address + Csect.Size;
347       }
348     }
349 
350     // The size of the tail padding in a section is the end virtual address of
351     // the current section minus the the end virtual address of the last csect
352     // in that section.
353     if (uint32_t PaddingSize =
354             Section->Address + Section->Size - CurrentAddressLocation)
355       W.OS.write_zeros(PaddingSize);
356   }
357 }
358 
359 uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm,
360                                         const MCAsmLayout &Layout) {
361   // We always emit a timestamp of 0 for reproducibility, so ensure incremental
362   // linking is not enabled, in case, like with Windows COFF, such a timestamp
363   // is incompatible with incremental linking of XCOFF.
364   if (Asm.isIncrementalLinkerCompatible())
365     report_fatal_error("Incremental linking not supported for XCOFF.");
366 
367   if (TargetObjectWriter->is64Bit())
368     report_fatal_error("64-bit XCOFF object files are not supported yet.");
369 
370   uint64_t StartOffset = W.OS.tell();
371 
372   writeFileHeader();
373   writeSectionHeaderTable();
374   writeSections(Asm, Layout);
375   // TODO writeRelocations();
376 
377   writeSymbolTable(Layout);
378   // Write the string table.
379   Strings.write(W.OS);
380 
381   return W.OS.tell() - StartOffset;
382 }
383 
384 bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) {
385   return SymbolName.size() > XCOFF::NameSize;
386 }
387 
388 void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) {
389   if (nameShouldBeInStringTable(SymbolName)) {
390     W.write<int32_t>(0);
391     W.write<uint32_t>(Strings.getOffset(SymbolName));
392   } else {
393     char Name[XCOFF::NameSize];
394     std::strncpy(Name, SymbolName.data(), XCOFF::NameSize);
395     ArrayRef<char> NameRef(Name, XCOFF::NameSize);
396     W.write(NameRef);
397   }
398 }
399 
400 void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel(
401     const Symbol &SymbolRef, const ControlSection &CSectionRef,
402     int16_t SectionIndex, uint64_t SymbolOffset) {
403   // Name or Zeros and string table offset
404   writeSymbolName(SymbolRef.getName());
405   assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address &&
406          "Symbol address overflows.");
407   W.write<uint32_t>(CSectionRef.Address + SymbolOffset);
408   W.write<int16_t>(SectionIndex);
409   // Basic/Derived type. See the description of the n_type field for symbol
410   // table entries for a detailed description. Since we don't yet support
411   // visibility, and all other bits are either optionally set or reserved, this
412   // is always zero.
413   // TODO FIXME How to assert a symbol's visibilty is default?
414   // TODO Set the function indicator (bit 10, 0x0020) for functions
415   // when debugging is enabled.
416   W.write<uint16_t>(0);
417   W.write<uint8_t>(SymbolRef.getStorageClass());
418   // Always 1 aux entry for now.
419   W.write<uint8_t>(1);
420 
421   // Now output the auxiliary entry.
422   W.write<uint32_t>(CSectionRef.SymbolTableIndex);
423   // Parameter typecheck hash. Not supported.
424   W.write<uint32_t>(0);
425   // Typecheck section number. Not supported.
426   W.write<uint16_t>(0);
427   // Symbol type: Label
428   W.write<uint8_t>(XCOFF::XTY_LD);
429   // Storage mapping class.
430   W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
431   // Reserved (x_stab).
432   W.write<uint32_t>(0);
433   // Reserved (x_snstab).
434   W.write<uint16_t>(0);
435 }
436 
437 void XCOFFObjectWriter::writeSymbolTableEntryForControlSection(
438     const ControlSection &CSectionRef, int16_t SectionIndex,
439     XCOFF::StorageClass StorageClass) {
440   // n_name, n_zeros, n_offset
441   writeSymbolName(CSectionRef.getName());
442   // n_value
443   W.write<uint32_t>(CSectionRef.Address);
444   // n_scnum
445   W.write<int16_t>(SectionIndex);
446   // Basic/Derived type. See the description of the n_type field for symbol
447   // table entries for a detailed description. Since we don't yet support
448   // visibility, and all other bits are either optionally set or reserved, this
449   // is always zero.
450   // TODO FIXME How to assert a symbol's visibilty is default?
451   // TODO Set the function indicator (bit 10, 0x0020) for functions
452   // when debugging is enabled.
453   W.write<uint16_t>(0);
454   // n_sclass
455   W.write<uint8_t>(StorageClass);
456   // Always 1 aux entry for now.
457   W.write<uint8_t>(1);
458 
459   // Now output the auxiliary entry.
460   W.write<uint32_t>(CSectionRef.Size);
461   // Parameter typecheck hash. Not supported.
462   W.write<uint32_t>(0);
463   // Typecheck section number. Not supported.
464   W.write<uint16_t>(0);
465   // Symbol type.
466   W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect));
467   // Storage mapping class.
468   W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
469   // Reserved (x_stab).
470   W.write<uint32_t>(0);
471   // Reserved (x_snstab).
472   W.write<uint16_t>(0);
473 }
474 
475 void XCOFFObjectWriter::writeFileHeader() {
476   // Magic.
477   W.write<uint16_t>(0x01df);
478   // Number of sections.
479   W.write<uint16_t>(SectionCount);
480   // Timestamp field. For reproducible output we write a 0, which represents no
481   // timestamp.
482   W.write<int32_t>(0);
483   // Byte Offset to the start of the symbol table.
484   W.write<uint32_t>(SymbolTableOffset);
485   // Number of entries in the symbol table.
486   W.write<int32_t>(SymbolTableEntryCount);
487   // Size of the optional header.
488   W.write<uint16_t>(0);
489   // Flags.
490   W.write<uint16_t>(0);
491 }
492 
493 void XCOFFObjectWriter::writeSectionHeaderTable() {
494   for (const auto *Sec : Sections) {
495     // Nothing to write for this Section.
496     if (Sec->Index == Section::UninitializedIndex)
497       continue;
498 
499     // Write Name.
500     ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
501     W.write(NameRef);
502 
503     // Write the Physical Address and Virtual Address. In an object file these
504     // are the same.
505     W.write<uint32_t>(Sec->Address);
506     W.write<uint32_t>(Sec->Address);
507 
508     W.write<uint32_t>(Sec->Size);
509     W.write<uint32_t>(Sec->FileOffsetToData);
510 
511     // Relocation pointer and Lineno pointer. Not supported yet.
512     W.write<uint32_t>(0);
513     W.write<uint32_t>(0);
514 
515     // Relocation and line-number counts. Not supported yet.
516     W.write<uint16_t>(0);
517     W.write<uint16_t>(0);
518 
519     W.write<int32_t>(Sec->Flags);
520   }
521 }
522 
523 void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
524   for (const auto *Section : Sections) {
525     // Nothing to write for this Section.
526     if (Section->Index == Section::UninitializedIndex)
527       continue;
528 
529     for (const auto *Group : Section->Groups) {
530       if (Group->Csects.empty())
531         continue;
532 
533       const bool SupportLabelDef = Group->SupportLabelDef;
534       const int16_t SectionIndex = Section->Index;
535       for (const auto &Csect : Group->Csects) {
536         // Write out the control section first and then each symbol in it.
537         writeSymbolTableEntryForControlSection(
538             Csect, SectionIndex, Csect.MCCsect->getStorageClass());
539         if (!SupportLabelDef) {
540           assert(Csect.Syms.size() == 1 && "Csect should only contain 1 symbol "
541                                            "which is its label definition.");
542           continue;
543         }
544 
545         for (const auto Sym : Csect.Syms)
546           writeSymbolTableEntryForCsectMemberLabel(
547               Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym)));
548       }
549     }
550   }
551 }
552 
553 void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
554   // The address corrresponds to the address of sections and symbols in the
555   // object file. We place the shared address 0 immediately after the
556   // section header table.
557   uint32_t Address = 0;
558   // Section indices are 1-based in XCOFF.
559   int32_t SectionIndex = 1;
560   // The first symbol table entry is for the file name. We are not emitting it
561   // yet, so start at index 0.
562   uint32_t SymbolTableIndex = 0;
563 
564   for (auto *Section : Sections) {
565     const bool IsEmpty =
566         llvm::all_of(Section->Groups, [](const CsectGroup *Group) {
567           return Group->Csects.empty();
568         });
569     if (IsEmpty)
570       continue;
571 
572     if (SectionIndex > MaxSectionIndex)
573       report_fatal_error("Section index overflow!");
574     Section->Index = SectionIndex++;
575     SectionCount++;
576 
577     bool SectionAddressSet = false;
578     for (auto *Group : Section->Groups) {
579       if (Group->Csects.empty())
580         continue;
581 
582       const bool SupportLabelDef = Group->SupportLabelDef;
583       for (auto &Csect : Group->Csects) {
584         const MCSectionXCOFF *MCSec = Csect.MCCsect;
585         Csect.Address = alignTo(Address, MCSec->getAlignment());
586         Csect.Size = Layout.getSectionAddressSize(MCSec);
587         Address = Csect.Address + Csect.Size;
588         Csect.SymbolTableIndex = SymbolTableIndex;
589         // 1 main and 1 auxiliary symbol table entry for the csect.
590         SymbolTableIndex += 2;
591 
592         if (!SupportLabelDef)
593           continue;
594 
595         for (auto &Sym : Csect.Syms) {
596           Sym.SymbolTableIndex = SymbolTableIndex;
597           // 1 main and 1 auxiliary symbol table entry for each contained
598           // symbol.
599           SymbolTableIndex += 2;
600         }
601       }
602 
603       if (!SectionAddressSet) {
604         Section->Address = Group->Csects.front().Address;
605         SectionAddressSet = true;
606       }
607     }
608 
609     // Make sure the address of the next section aligned to
610     // DefaultSectionAlign.
611     Address = alignTo(Address, DefaultSectionAlign);
612     Section->Size = Address - Section->Address;
613   }
614 
615   SymbolTableEntryCount = SymbolTableIndex;
616 
617   // Calculate the RawPointer value for each section.
618   uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
619                         SectionCount * sizeof(XCOFF::SectionHeader32);
620   for (auto *Sec : Sections) {
621     if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual)
622       continue;
623 
624     Sec->FileOffsetToData = RawPointer;
625     RawPointer += Sec->Size;
626   }
627 
628   // TODO Add in Relocation storage to the RawPointer Calculation.
629   // TODO What to align the SymbolTable to?
630   // TODO Error check that the number of symbol table entries fits in 32-bits
631   // signed ...
632   if (SymbolTableEntryCount)
633     SymbolTableOffset = RawPointer;
634 }
635 
636 // Takes the log base 2 of the alignment and shifts the result into the 5 most
637 // significant bits of a byte, then or's in the csect type into the least
638 // significant 3 bits.
639 uint8_t getEncodedType(const MCSectionXCOFF *Sec) {
640   unsigned Align = Sec->getAlignment();
641   assert(isPowerOf2_32(Align) && "Alignment must be a power of 2.");
642   unsigned Log2Align = Log2_32(Align);
643   // Result is a number in the range [0, 31] which fits in the 5 least
644   // significant bits. Shift this value into the 5 most significant bits, and
645   // bitwise-or in the csect type.
646   uint8_t EncodedAlign = Log2Align << 3;
647   return EncodedAlign | Sec->getCSectType();
648 }
649 
650 } // end anonymous namespace
651 
652 std::unique_ptr<MCObjectWriter>
653 llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
654                               raw_pwrite_stream &OS) {
655   return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
656 }
657