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/MCAsmBackend.h"
15 #include "llvm/MC/MCAsmLayout.h"
16 #include "llvm/MC/MCAssembler.h"
17 #include "llvm/MC/MCFixup.h"
18 #include "llvm/MC/MCFixupKindInfo.h"
19 #include "llvm/MC/MCObjectWriter.h"
20 #include "llvm/MC/MCSectionXCOFF.h"
21 #include "llvm/MC/MCSymbolXCOFF.h"
22 #include "llvm/MC/MCValue.h"
23 #include "llvm/MC/MCXCOFFObjectWriter.h"
24 #include "llvm/MC/StringTableBuilder.h"
25 #include "llvm/Support/EndianStream.h"
26 #include "llvm/Support/Error.h"
27 #include "llvm/Support/MathExtras.h"
28 
29 #include <deque>
30 
31 using namespace llvm;
32 
33 // An XCOFF object file has a limited set of predefined sections. The most
34 // important ones for us (right now) are:
35 // .text --> contains program code and read-only data.
36 // .data --> contains initialized data, function descriptors, and the TOC.
37 // .bss  --> contains uninitialized data.
38 // Each of these sections is composed of 'Control Sections'. A Control Section
39 // is more commonly referred to as a csect. A csect is an indivisible unit of
40 // code or data, and acts as a container for symbols. A csect is mapped
41 // into a section based on its storage-mapping class, with the exception of
42 // XMC_RW which gets mapped to either .data or .bss based on whether it's
43 // explicitly initialized or not.
44 //
45 // We don't represent the sections in the MC layer as there is nothing
46 // interesting about them at at that level: they carry information that is
47 // only relevant to the ObjectWriter, so we materialize them in this class.
48 namespace {
49 
50 constexpr unsigned DefaultSectionAlign = 4;
51 constexpr int16_t MaxSectionIndex = INT16_MAX;
52 
53 // Packs the csect's alignment and type into a byte.
54 uint8_t getEncodedType(const MCSectionXCOFF *);
55 
56 struct XCOFFRelocation {
57   uint32_t SymbolTableIndex;
58   uint32_t FixupOffsetInCsect;
59   uint8_t SignAndSize;
60   uint8_t Type;
61 };
62 
63 // Wrapper around an MCSymbolXCOFF.
64 struct Symbol {
65   const MCSymbolXCOFF *const MCSym;
66   uint32_t SymbolTableIndex;
67 
68   XCOFF::StorageClass getStorageClass() const {
69     return MCSym->getStorageClass();
70   }
71   StringRef getName() const { return MCSym->getName(); }
72   Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {}
73 };
74 
75 // Wrapper for an MCSectionXCOFF.
76 struct ControlSection {
77   const MCSectionXCOFF *const MCCsect;
78   uint32_t SymbolTableIndex;
79   uint32_t Address;
80   uint32_t Size;
81 
82   SmallVector<Symbol, 1> Syms;
83   SmallVector<XCOFFRelocation, 1> Relocations;
84   StringRef getName() const { return MCCsect->getName(); }
85   ControlSection(const MCSectionXCOFF *MCSec)
86       : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {}
87 };
88 
89 // Type to be used for a container representing a set of csects with
90 // (approximately) the same storage mapping class. For example all the csects
91 // with a storage mapping class of `xmc_pr` will get placed into the same
92 // container.
93 using CsectGroup = std::deque<ControlSection>;
94 using CsectGroups = std::deque<CsectGroup *>;
95 
96 // Represents the data related to a section excluding the csects that make up
97 // the raw data of the section. The csects are stored separately as not all
98 // sections contain csects, and some sections contain csects which are better
99 // stored separately, e.g. the .data section containing read-write, descriptor,
100 // TOCBase and TOC-entry csects.
101 struct Section {
102   char Name[XCOFF::NameSize];
103   // The physical/virtual address of the section. For an object file
104   // these values are equivalent.
105   uint32_t Address;
106   uint32_t Size;
107   uint32_t FileOffsetToData;
108   uint32_t FileOffsetToRelocations;
109   uint32_t RelocationCount;
110   int32_t Flags;
111 
112   int16_t Index;
113 
114   // Virtual sections do not need storage allocated in the object file.
115   const bool IsVirtual;
116 
117   // XCOFF has special section numbers for symbols:
118   // -2 Specifies N_DEBUG, a special symbolic debugging symbol.
119   // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not
120   // relocatable.
121   //  0 Specifies N_UNDEF, an undefined external symbol.
122   // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that
123   // hasn't been initialized.
124   static constexpr int16_t UninitializedIndex =
125       XCOFF::ReservedSectionNum::N_DEBUG - 1;
126 
127   CsectGroups Groups;
128 
129   void reset() {
130     Address = 0;
131     Size = 0;
132     FileOffsetToData = 0;
133     FileOffsetToRelocations = 0;
134     RelocationCount = 0;
135     Index = UninitializedIndex;
136     // Clear any csects we have stored.
137     for (auto *Group : Groups)
138       Group->clear();
139   }
140 
141   Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual,
142           CsectGroups Groups)
143       : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0),
144         RelocationCount(0), Flags(Flags), Index(UninitializedIndex),
145         IsVirtual(IsVirtual), Groups(Groups) {
146     strncpy(Name, N, XCOFF::NameSize);
147   }
148 };
149 
150 class XCOFFObjectWriter : public MCObjectWriter {
151 
152   uint32_t SymbolTableEntryCount = 0;
153   uint32_t SymbolTableOffset = 0;
154   uint16_t SectionCount = 0;
155   uint32_t RelocationEntryOffset = 0;
156 
157   support::endian::Writer W;
158   std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
159   StringTableBuilder Strings;
160 
161   // Maps the MCSection representation to its corresponding ControlSection
162   // wrapper. Needed for finding the ControlSection to insert an MCSymbol into
163   // from its containing MCSectionXCOFF.
164   DenseMap<const MCSectionXCOFF *, ControlSection *> SectionMap;
165 
166   // Maps the MCSymbol representation to its corrresponding symbol table index.
167   // Needed for relocation.
168   DenseMap<const MCSymbol *, uint32_t> SymbolIndexMap;
169 
170   // CsectGroups. These store the csects which make up different parts of
171   // the sections. Should have one for each set of csects that get mapped into
172   // the same section and get handled in a 'similar' way.
173   CsectGroup UndefinedCsects;
174   CsectGroup ProgramCodeCsects;
175   CsectGroup ReadOnlyCsects;
176   CsectGroup DataCsects;
177   CsectGroup FuncDSCsects;
178   CsectGroup TOCCsects;
179   CsectGroup BSSCsects;
180 
181   // The Predefined sections.
182   Section Text;
183   Section Data;
184   Section BSS;
185 
186   // All the XCOFF sections, in the order they will appear in the section header
187   // table.
188   std::array<Section *const, 3> Sections{{&Text, &Data, &BSS}};
189 
190   CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec);
191 
192   virtual void reset() override;
193 
194   void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
195 
196   void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *,
197                         const MCFixup &, MCValue, uint64_t &) override;
198 
199   uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
200 
201   static bool nameShouldBeInStringTable(const StringRef &);
202   void writeSymbolName(const StringRef &);
203   void writeSymbolTableEntryForCsectMemberLabel(const Symbol &,
204                                                 const ControlSection &, int16_t,
205                                                 uint64_t);
206   void writeSymbolTableEntryForControlSection(const ControlSection &, int16_t,
207                                               XCOFF::StorageClass);
208   void writeFileHeader();
209   void writeSectionHeaderTable();
210   void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout);
211   void writeSymbolTable(const MCAsmLayout &Layout);
212   void writeRelocations();
213   void writeRelocation(XCOFFRelocation Reloc, const ControlSection &CSection);
214 
215   // Called after all the csects and symbols have been processed by
216   // `executePostLayoutBinding`, this function handles building up the majority
217   // of the structures in the object file representation. Namely:
218   // *) Calculates physical/virtual addresses, raw-pointer offsets, and section
219   //    sizes.
220   // *) Assigns symbol table indices.
221   // *) Builds up the section header table by adding any non-empty sections to
222   //    `Sections`.
223   void assignAddressesAndIndices(const MCAsmLayout &);
224   void finalizeSectionInfo();
225 
226   bool
227   needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */
228     return false;
229   }
230 
231   // Returns the size of the auxiliary header to be written to the object file.
232   size_t auxiliaryHeaderSize() const {
233     assert(!needsAuxiliaryHeader() &&
234            "Auxiliary header support not implemented.");
235     return 0;
236   }
237 
238 public:
239   XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
240                     raw_pwrite_stream &OS);
241 };
242 
243 XCOFFObjectWriter::XCOFFObjectWriter(
244     std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
245     : W(OS, support::big), TargetObjectWriter(std::move(MOTW)),
246       Strings(StringTableBuilder::XCOFF),
247       Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false,
248            CsectGroups{&ProgramCodeCsects, &ReadOnlyCsects}),
249       Data(".data", XCOFF::STYP_DATA, /* IsVirtual */ false,
250            CsectGroups{&DataCsects, &FuncDSCsects, &TOCCsects}),
251       BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true,
252           CsectGroups{&BSSCsects}) {}
253 
254 void XCOFFObjectWriter::reset() {
255   // Clear the mappings we created.
256   SymbolIndexMap.clear();
257   SectionMap.clear();
258 
259   UndefinedCsects.clear();
260   // Reset any sections we have written to, and empty the section header table.
261   for (auto *Sec : Sections)
262     Sec->reset();
263 
264   // Reset states in XCOFFObjectWriter.
265   SymbolTableEntryCount = 0;
266   SymbolTableOffset = 0;
267   SectionCount = 0;
268   RelocationEntryOffset = 0;
269   Strings.clear();
270 
271   MCObjectWriter::reset();
272 }
273 
274 CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) {
275   switch (MCSec->getMappingClass()) {
276   case XCOFF::XMC_PR:
277     assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
278            "Only an initialized csect can contain program code.");
279     return ProgramCodeCsects;
280   case XCOFF::XMC_RO:
281     assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
282            "Only an initialized csect can contain read only data.");
283     return ReadOnlyCsects;
284   case XCOFF::XMC_RW:
285     if (XCOFF::XTY_CM == MCSec->getCSectType())
286       return BSSCsects;
287 
288     if (XCOFF::XTY_SD == MCSec->getCSectType())
289       return DataCsects;
290 
291     report_fatal_error("Unhandled mapping of read-write csect to section.");
292   case XCOFF::XMC_DS:
293     return FuncDSCsects;
294   case XCOFF::XMC_BS:
295     assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
296            "Mapping invalid csect. CSECT with bss storage class must be "
297            "common type.");
298     return BSSCsects;
299   case XCOFF::XMC_TC0:
300     assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
301            "Only an initialized csect can contain TOC-base.");
302     assert(TOCCsects.empty() &&
303            "We should have only one TOC-base, and it should be the first csect "
304            "in this CsectGroup.");
305     return TOCCsects;
306   case XCOFF::XMC_TC:
307     assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
308            "Only an initialized csect can contain TC entry.");
309     assert(!TOCCsects.empty() &&
310            "We should at least have a TOC-base in this CsectGroup.");
311     return TOCCsects;
312   default:
313     report_fatal_error("Unhandled mapping of csect to section.");
314   }
315 }
316 
317 static MCSectionXCOFF *getContainingCsect(const MCSymbolXCOFF *XSym) {
318   if (XSym->isDefined())
319     return cast<MCSectionXCOFF>(XSym->getFragment()->getParent());
320   return XSym->getRepresentedCsect();
321 }
322 
323 void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
324                                                  const MCAsmLayout &Layout) {
325   if (TargetObjectWriter->is64Bit())
326     report_fatal_error("64-bit XCOFF object files are not supported yet.");
327 
328   for (const auto &S : Asm) {
329     const auto *MCSec = cast<const MCSectionXCOFF>(&S);
330     assert(SectionMap.find(MCSec) == SectionMap.end() &&
331            "Cannot add a csect twice.");
332     assert(XCOFF::XTY_ER != MCSec->getCSectType() &&
333            "An undefined csect should not get registered.");
334 
335     // If the name does not fit in the storage provided in the symbol table
336     // entry, add it to the string table.
337     if (nameShouldBeInStringTable(MCSec->getName()))
338       Strings.add(MCSec->getName());
339 
340     CsectGroup &Group = getCsectGroup(MCSec);
341     Group.emplace_back(MCSec);
342     SectionMap[MCSec] = &Group.back();
343   }
344 
345   for (const MCSymbol &S : Asm.symbols()) {
346     // Nothing to do for temporary symbols.
347     if (S.isTemporary())
348       continue;
349 
350     const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S);
351     const MCSectionXCOFF *ContainingCsect = getContainingCsect(XSym);
352 
353     if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) {
354       // Handle undefined symbol.
355       UndefinedCsects.emplace_back(ContainingCsect);
356       SectionMap[ContainingCsect] = &UndefinedCsects.back();
357     } else {
358       // If the symbol is the csect itself, we don't need to put the symbol
359       // into csect's Syms.
360       if (XSym == ContainingCsect->getQualNameSymbol())
361         continue;
362 
363       // Only put a label into the symbol table when it is an external label.
364       if (!XSym->isExternal())
365         continue;
366 
367       assert(SectionMap.find(ContainingCsect) != SectionMap.end() &&
368              "Expected containing csect to exist in map");
369       // Lookup the containing csect and add the symbol to it.
370       SectionMap[ContainingCsect]->Syms.emplace_back(XSym);
371     }
372 
373     // If the name does not fit in the storage provided in the symbol table
374     // entry, add it to the string table.
375     if (nameShouldBeInStringTable(XSym->getName()))
376       Strings.add(XSym->getName());
377   }
378 
379   Strings.finalize();
380   assignAddressesAndIndices(Layout);
381 }
382 
383 void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
384                                          const MCAsmLayout &Layout,
385                                          const MCFragment *Fragment,
386                                          const MCFixup &Fixup, MCValue Target,
387                                          uint64_t &FixedValue) {
388   auto getIndex = [this](const MCSymbol *Sym,
389                          const MCSectionXCOFF *ContainingCsect) {
390     // If we could not find the symbol directly in SymbolIndexMap, this symbol
391     // could either be a temporary symbol or an undefined symbol. In this case,
392     // we would need to have the relocation reference its csect instead.
393     return SymbolIndexMap.find(Sym) != SymbolIndexMap.end()
394                ? SymbolIndexMap[Sym]
395                : SymbolIndexMap[ContainingCsect->getQualNameSymbol()];
396   };
397 
398   auto getVirtualAddress = [this,
399                             &Layout](const MCSymbol *Sym,
400                                      const MCSectionXCOFF *ContainingCsect) {
401     // If Sym is a csect, return csect's address.
402     // If Sym is a label, return csect's address + label's offset from the csect.
403     return SectionMap[ContainingCsect]->Address +
404            (Sym->isDefined() ? Layout.getSymbolOffset(*Sym) : 0);
405   };
406 
407   const MCSymbol *const SymA = &Target.getSymA()->getSymbol();
408 
409   MCAsmBackend &Backend = Asm.getBackend();
410   bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
411                  MCFixupKindInfo::FKF_IsPCRel;
412 
413   uint8_t Type;
414   uint8_t SignAndSize;
415   std::tie(Type, SignAndSize) =
416       TargetObjectWriter->getRelocTypeAndSignSize(Target, Fixup, IsPCRel);
417 
418   const MCSectionXCOFF *SymASec = getContainingCsect(cast<MCSymbolXCOFF>(SymA));
419   assert(SectionMap.find(SymASec) != SectionMap.end() &&
420          "Expected containing csect to exist in map.");
421 
422   const uint32_t Index = getIndex(SymA, SymASec);
423   if (Type == XCOFF::RelocationType::R_POS)
424     // The FixedValue should be symbol's virtual address in this object file
425     // plus any constant value that we might get.
426     FixedValue = getVirtualAddress(SymA, SymASec) + Target.getConstant();
427   else if (Type == XCOFF::RelocationType::R_TOC)
428     // The FixedValue should be the TC entry offset from TOC-base.
429     FixedValue = SectionMap[SymASec]->Address - TOCCsects.front().Address;
430 
431   assert(
432       (TargetObjectWriter->is64Bit() ||
433        Fixup.getOffset() <= UINT32_MAX - Layout.getFragmentOffset(Fragment)) &&
434       "Fragment offset + fixup offset is overflowed in 32-bit mode.");
435   uint32_t FixupOffsetInCsect =
436       Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
437 
438   XCOFFRelocation Reloc = {Index, FixupOffsetInCsect, SignAndSize, Type};
439   MCSectionXCOFF *RelocationSec = cast<MCSectionXCOFF>(Fragment->getParent());
440   assert(SectionMap.find(RelocationSec) != SectionMap.end() &&
441          "Expected containing csect to exist in map.");
442   SectionMap[RelocationSec]->Relocations.push_back(Reloc);
443 
444   if (!Target.getSymB())
445     return;
446 
447   const MCSymbol *const SymB = &Target.getSymB()->getSymbol();
448   if (SymA == SymB)
449     report_fatal_error("relocation for opposite term is not yet supported");
450 
451   const MCSectionXCOFF *SymBSec = getContainingCsect(cast<MCSymbolXCOFF>(SymB));
452   assert(SectionMap.find(SymBSec) != SectionMap.end() &&
453          "Expected containing csect to exist in map.");
454   if (SymASec == SymBSec)
455     report_fatal_error(
456         "relocation for paired relocatable term is not yet supported");
457 
458   assert(Type == XCOFF::RelocationType::R_POS &&
459          "SymA must be R_POS here if it's not opposite term or paired "
460          "relocatable term.");
461   const uint32_t IndexB = getIndex(SymB, SymBSec);
462   // SymB must be R_NEG here, given the general form of Target(MCValue) is
463   // "SymbolA - SymbolB + imm64".
464   const uint8_t TypeB = XCOFF::RelocationType::R_NEG;
465   XCOFFRelocation RelocB = {IndexB, FixupOffsetInCsect, SignAndSize, TypeB};
466   SectionMap[RelocationSec]->Relocations.push_back(RelocB);
467   // We already folded "SymbolA + imm64" above when Type is R_POS for SymbolA,
468   // now we just need to fold "- SymbolB" here.
469   FixedValue -= getVirtualAddress(SymB, SymBSec);
470 }
471 
472 void XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
473                                       const MCAsmLayout &Layout) {
474   uint32_t CurrentAddressLocation = 0;
475   for (const auto *Section : Sections) {
476     // Nothing to write for this Section.
477     if (Section->Index == Section::UninitializedIndex || Section->IsVirtual)
478       continue;
479 
480     // There could be a gap (without corresponding zero padding) between
481     // sections.
482     assert(CurrentAddressLocation <= Section->Address &&
483            "CurrentAddressLocation should be less than or equal to section "
484            "address.");
485 
486     CurrentAddressLocation = Section->Address;
487 
488     for (const auto *Group : Section->Groups) {
489       for (const auto &Csect : *Group) {
490         if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation)
491           W.OS.write_zeros(PaddingSize);
492         if (Csect.Size)
493           Asm.writeSectionData(W.OS, Csect.MCCsect, Layout);
494         CurrentAddressLocation = Csect.Address + Csect.Size;
495       }
496     }
497 
498     // The size of the tail padding in a section is the end virtual address of
499     // the current section minus the the end virtual address of the last csect
500     // in that section.
501     if (uint32_t PaddingSize =
502             Section->Address + Section->Size - CurrentAddressLocation) {
503       W.OS.write_zeros(PaddingSize);
504       CurrentAddressLocation += PaddingSize;
505     }
506   }
507 }
508 
509 uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm,
510                                         const MCAsmLayout &Layout) {
511   // We always emit a timestamp of 0 for reproducibility, so ensure incremental
512   // linking is not enabled, in case, like with Windows COFF, such a timestamp
513   // is incompatible with incremental linking of XCOFF.
514   if (Asm.isIncrementalLinkerCompatible())
515     report_fatal_error("Incremental linking not supported for XCOFF.");
516 
517   if (TargetObjectWriter->is64Bit())
518     report_fatal_error("64-bit XCOFF object files are not supported yet.");
519 
520   finalizeSectionInfo();
521   uint64_t StartOffset = W.OS.tell();
522 
523   writeFileHeader();
524   writeSectionHeaderTable();
525   writeSections(Asm, Layout);
526   writeRelocations();
527 
528   writeSymbolTable(Layout);
529   // Write the string table.
530   Strings.write(W.OS);
531 
532   return W.OS.tell() - StartOffset;
533 }
534 
535 bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) {
536   return SymbolName.size() > XCOFF::NameSize;
537 }
538 
539 void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) {
540   if (nameShouldBeInStringTable(SymbolName)) {
541     W.write<int32_t>(0);
542     W.write<uint32_t>(Strings.getOffset(SymbolName));
543   } else {
544     char Name[XCOFF::NameSize+1];
545     std::strncpy(Name, SymbolName.data(), XCOFF::NameSize);
546     ArrayRef<char> NameRef(Name, XCOFF::NameSize);
547     W.write(NameRef);
548   }
549 }
550 
551 void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel(
552     const Symbol &SymbolRef, const ControlSection &CSectionRef,
553     int16_t SectionIndex, uint64_t SymbolOffset) {
554   // Name or Zeros and string table offset
555   writeSymbolName(SymbolRef.getName());
556   assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address &&
557          "Symbol address overflows.");
558   W.write<uint32_t>(CSectionRef.Address + SymbolOffset);
559   W.write<int16_t>(SectionIndex);
560   // Basic/Derived type. See the description of the n_type field for symbol
561   // table entries for a detailed description. Since we don't yet support
562   // visibility, and all other bits are either optionally set or reserved, this
563   // is always zero.
564   // TODO FIXME How to assert a symbol's visibilty is default?
565   // TODO Set the function indicator (bit 10, 0x0020) for functions
566   // when debugging is enabled.
567   W.write<uint16_t>(0);
568   W.write<uint8_t>(SymbolRef.getStorageClass());
569   // Always 1 aux entry for now.
570   W.write<uint8_t>(1);
571 
572   // Now output the auxiliary entry.
573   W.write<uint32_t>(CSectionRef.SymbolTableIndex);
574   // Parameter typecheck hash. Not supported.
575   W.write<uint32_t>(0);
576   // Typecheck section number. Not supported.
577   W.write<uint16_t>(0);
578   // Symbol type: Label
579   W.write<uint8_t>(XCOFF::XTY_LD);
580   // Storage mapping class.
581   W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
582   // Reserved (x_stab).
583   W.write<uint32_t>(0);
584   // Reserved (x_snstab).
585   W.write<uint16_t>(0);
586 }
587 
588 void XCOFFObjectWriter::writeSymbolTableEntryForControlSection(
589     const ControlSection &CSectionRef, int16_t SectionIndex,
590     XCOFF::StorageClass StorageClass) {
591   // n_name, n_zeros, n_offset
592   writeSymbolName(CSectionRef.getName());
593   // n_value
594   W.write<uint32_t>(CSectionRef.Address);
595   // n_scnum
596   W.write<int16_t>(SectionIndex);
597   // Basic/Derived type. See the description of the n_type field for symbol
598   // table entries for a detailed description. Since we don't yet support
599   // visibility, and all other bits are either optionally set or reserved, this
600   // is always zero.
601   // TODO FIXME How to assert a symbol's visibilty is default?
602   // TODO Set the function indicator (bit 10, 0x0020) for functions
603   // when debugging is enabled.
604   W.write<uint16_t>(0);
605   // n_sclass
606   W.write<uint8_t>(StorageClass);
607   // Always 1 aux entry for now.
608   W.write<uint8_t>(1);
609 
610   // Now output the auxiliary entry.
611   W.write<uint32_t>(CSectionRef.Size);
612   // Parameter typecheck hash. Not supported.
613   W.write<uint32_t>(0);
614   // Typecheck section number. Not supported.
615   W.write<uint16_t>(0);
616   // Symbol type.
617   W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect));
618   // Storage mapping class.
619   W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
620   // Reserved (x_stab).
621   W.write<uint32_t>(0);
622   // Reserved (x_snstab).
623   W.write<uint16_t>(0);
624 }
625 
626 void XCOFFObjectWriter::writeFileHeader() {
627   // Magic.
628   W.write<uint16_t>(0x01df);
629   // Number of sections.
630   W.write<uint16_t>(SectionCount);
631   // Timestamp field. For reproducible output we write a 0, which represents no
632   // timestamp.
633   W.write<int32_t>(0);
634   // Byte Offset to the start of the symbol table.
635   W.write<uint32_t>(SymbolTableOffset);
636   // Number of entries in the symbol table.
637   W.write<int32_t>(SymbolTableEntryCount);
638   // Size of the optional header.
639   W.write<uint16_t>(0);
640   // Flags.
641   W.write<uint16_t>(0);
642 }
643 
644 void XCOFFObjectWriter::writeSectionHeaderTable() {
645   for (const auto *Sec : Sections) {
646     // Nothing to write for this Section.
647     if (Sec->Index == Section::UninitializedIndex)
648       continue;
649 
650     // Write Name.
651     ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
652     W.write(NameRef);
653 
654     // Write the Physical Address and Virtual Address. In an object file these
655     // are the same.
656     W.write<uint32_t>(Sec->Address);
657     W.write<uint32_t>(Sec->Address);
658 
659     W.write<uint32_t>(Sec->Size);
660     W.write<uint32_t>(Sec->FileOffsetToData);
661     W.write<uint32_t>(Sec->FileOffsetToRelocations);
662 
663     // Line number pointer. Not supported yet.
664     W.write<uint32_t>(0);
665 
666     W.write<uint16_t>(Sec->RelocationCount);
667 
668     // Line number counts. Not supported yet.
669     W.write<uint16_t>(0);
670 
671     W.write<int32_t>(Sec->Flags);
672   }
673 }
674 
675 void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc,
676                                         const ControlSection &CSection) {
677   W.write<uint32_t>(CSection.Address + Reloc.FixupOffsetInCsect);
678   W.write<uint32_t>(Reloc.SymbolTableIndex);
679   W.write<uint8_t>(Reloc.SignAndSize);
680   W.write<uint8_t>(Reloc.Type);
681 }
682 
683 void XCOFFObjectWriter::writeRelocations() {
684   for (const auto *Section : Sections) {
685     if (Section->Index == Section::UninitializedIndex)
686       // Nothing to write for this Section.
687       continue;
688 
689     for (const auto *Group : Section->Groups) {
690       if (Group->empty())
691         continue;
692 
693       for (const auto &Csect : *Group) {
694         for (const auto Reloc : Csect.Relocations)
695           writeRelocation(Reloc, Csect);
696       }
697     }
698   }
699 }
700 
701 void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
702   for (const auto &Csect : UndefinedCsects) {
703     writeSymbolTableEntryForControlSection(
704         Csect, XCOFF::ReservedSectionNum::N_UNDEF, Csect.MCCsect->getStorageClass());
705   }
706 
707   for (const auto *Section : Sections) {
708     if (Section->Index == Section::UninitializedIndex)
709       // Nothing to write for this Section.
710       continue;
711 
712     for (const auto *Group : Section->Groups) {
713       if (Group->empty())
714         continue;
715 
716       const int16_t SectionIndex = Section->Index;
717       for (const auto &Csect : *Group) {
718         // Write out the control section first and then each symbol in it.
719         writeSymbolTableEntryForControlSection(
720             Csect, SectionIndex, Csect.MCCsect->getStorageClass());
721 
722         for (const auto &Sym : Csect.Syms)
723           writeSymbolTableEntryForCsectMemberLabel(
724               Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym)));
725       }
726     }
727   }
728 }
729 
730 void XCOFFObjectWriter::finalizeSectionInfo() {
731   for (auto *Section : Sections) {
732     if (Section->Index == Section::UninitializedIndex)
733       // Nothing to record for this Section.
734       continue;
735 
736     for (const auto *Group : Section->Groups) {
737       if (Group->empty())
738         continue;
739 
740       for (auto &Csect : *Group)
741         Section->RelocationCount += Csect.Relocations.size();
742     }
743   }
744 
745   // Calculate the file offset to the relocation entries.
746   uint64_t RawPointer = RelocationEntryOffset;
747   for (auto Sec : Sections) {
748     if (Sec->Index == Section::UninitializedIndex || !Sec->RelocationCount)
749       continue;
750 
751     Sec->FileOffsetToRelocations = RawPointer;
752     const uint32_t RelocationSizeInSec =
753         Sec->RelocationCount * XCOFF::RelocationSerializationSize32;
754     RawPointer += RelocationSizeInSec;
755     if (RawPointer > UINT32_MAX)
756       report_fatal_error("Relocation data overflowed this object file.");
757   }
758 
759   // TODO Error check that the number of symbol table entries fits in 32-bits
760   // signed ...
761   if (SymbolTableEntryCount)
762     SymbolTableOffset = RawPointer;
763 }
764 
765 void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
766   // The first symbol table entry is for the file name. We are not emitting it
767   // yet, so start at index 0.
768   uint32_t SymbolTableIndex = 0;
769 
770   // Calculate indices for undefined symbols.
771   for (auto &Csect : UndefinedCsects) {
772     Csect.Size = 0;
773     Csect.Address = 0;
774     Csect.SymbolTableIndex = SymbolTableIndex;
775     SymbolIndexMap[Csect.MCCsect->getQualNameSymbol()] = Csect.SymbolTableIndex;
776     // 1 main and 1 auxiliary symbol table entry for each contained symbol.
777     SymbolTableIndex += 2;
778   }
779 
780   // The address corrresponds to the address of sections and symbols in the
781   // object file. We place the shared address 0 immediately after the
782   // section header table.
783   uint32_t Address = 0;
784   // Section indices are 1-based in XCOFF.
785   int32_t SectionIndex = 1;
786 
787   for (auto *Section : Sections) {
788     const bool IsEmpty =
789         llvm::all_of(Section->Groups,
790                      [](const CsectGroup *Group) { return Group->empty(); });
791     if (IsEmpty)
792       continue;
793 
794     if (SectionIndex > MaxSectionIndex)
795       report_fatal_error("Section index overflow!");
796     Section->Index = SectionIndex++;
797     SectionCount++;
798 
799     bool SectionAddressSet = false;
800     for (auto *Group : Section->Groups) {
801       if (Group->empty())
802         continue;
803 
804       for (auto &Csect : *Group) {
805         const MCSectionXCOFF *MCSec = Csect.MCCsect;
806         Csect.Address = alignTo(Address, MCSec->getAlignment());
807         Csect.Size = Layout.getSectionAddressSize(MCSec);
808         Address = Csect.Address + Csect.Size;
809         Csect.SymbolTableIndex = SymbolTableIndex;
810         SymbolIndexMap[MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex;
811         // 1 main and 1 auxiliary symbol table entry for the csect.
812         SymbolTableIndex += 2;
813 
814         for (auto &Sym : Csect.Syms) {
815           Sym.SymbolTableIndex = SymbolTableIndex;
816           SymbolIndexMap[Sym.MCSym] = Sym.SymbolTableIndex;
817           // 1 main and 1 auxiliary symbol table entry for each contained
818           // symbol.
819           SymbolTableIndex += 2;
820         }
821       }
822 
823       if (!SectionAddressSet) {
824         Section->Address = Group->front().Address;
825         SectionAddressSet = true;
826       }
827     }
828 
829     // Make sure the address of the next section aligned to
830     // DefaultSectionAlign.
831     Address = alignTo(Address, DefaultSectionAlign);
832     Section->Size = Address - Section->Address;
833   }
834 
835   SymbolTableEntryCount = SymbolTableIndex;
836 
837   // Calculate the RawPointer value for each section.
838   uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
839                         SectionCount * sizeof(XCOFF::SectionHeader32);
840   for (auto *Sec : Sections) {
841     if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual)
842       continue;
843 
844     Sec->FileOffsetToData = RawPointer;
845     RawPointer += Sec->Size;
846     if (RawPointer > UINT32_MAX)
847       report_fatal_error("Section raw data overflowed this object file.");
848   }
849 
850   RelocationEntryOffset = RawPointer;
851 }
852 
853 // Takes the log base 2 of the alignment and shifts the result into the 5 most
854 // significant bits of a byte, then or's in the csect type into the least
855 // significant 3 bits.
856 uint8_t getEncodedType(const MCSectionXCOFF *Sec) {
857   unsigned Align = Sec->getAlignment();
858   assert(isPowerOf2_32(Align) && "Alignment must be a power of 2.");
859   unsigned Log2Align = Log2_32(Align);
860   // Result is a number in the range [0, 31] which fits in the 5 least
861   // significant bits. Shift this value into the 5 most significant bits, and
862   // bitwise-or in the csect type.
863   uint8_t EncodedAlign = Log2Align << 3;
864   return EncodedAlign | Sec->getCSectType();
865 }
866 
867 } // end anonymous namespace
868 
869 std::unique_ptr<MCObjectWriter>
870 llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
871                               raw_pwrite_stream &OS) {
872   return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
873 }
874