xref: /freebsd/contrib/llvm-project/llvm/lib/MC/XCOFFObjectWriter.cpp (revision dd41de95a84d979615a2ef11df6850622bf6184e)
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 getSymbolTableName() const { return MCSym->getSymbolTableName(); }
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 getSymbolTableName() const { return MCCsect->getSymbolTableName(); }
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->getSymbolTableName()))
338       Strings.add(MCSec->getSymbolTableName());
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       if (nameShouldBeInStringTable(ContainingCsect->getSymbolTableName()))
358         Strings.add(ContainingCsect->getSymbolTableName());
359       continue;
360     }
361 
362     // If the symbol is the csect itself, we don't need to put the symbol
363     // into csect's Syms.
364     if (XSym == ContainingCsect->getQualNameSymbol())
365       continue;
366 
367     // Only put a label into the symbol table when it is an external label.
368     if (!XSym->isExternal())
369       continue;
370 
371     assert(SectionMap.find(ContainingCsect) != SectionMap.end() &&
372            "Expected containing csect to exist in map");
373     // Lookup the containing csect and add the symbol to it.
374     SectionMap[ContainingCsect]->Syms.emplace_back(XSym);
375 
376     // If the name does not fit in the storage provided in the symbol table
377     // entry, add it to the string table.
378     if (nameShouldBeInStringTable(XSym->getSymbolTableName()))
379       Strings.add(XSym->getSymbolTableName());
380   }
381 
382   Strings.finalize();
383   assignAddressesAndIndices(Layout);
384 }
385 
386 void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
387                                          const MCAsmLayout &Layout,
388                                          const MCFragment *Fragment,
389                                          const MCFixup &Fixup, MCValue Target,
390                                          uint64_t &FixedValue) {
391   auto getIndex = [this](const MCSymbol *Sym,
392                          const MCSectionXCOFF *ContainingCsect) {
393     // If we could not find the symbol directly in SymbolIndexMap, this symbol
394     // could either be a temporary symbol or an undefined symbol. In this case,
395     // we would need to have the relocation reference its csect instead.
396     return SymbolIndexMap.find(Sym) != SymbolIndexMap.end()
397                ? SymbolIndexMap[Sym]
398                : SymbolIndexMap[ContainingCsect->getQualNameSymbol()];
399   };
400 
401   auto getVirtualAddress = [this,
402                             &Layout](const MCSymbol *Sym,
403                                      const MCSectionXCOFF *ContainingCsect) {
404     // If Sym is a csect, return csect's address.
405     // If Sym is a label, return csect's address + label's offset from the csect.
406     return SectionMap[ContainingCsect]->Address +
407            (Sym->isDefined() ? Layout.getSymbolOffset(*Sym) : 0);
408   };
409 
410   const MCSymbol *const SymA = &Target.getSymA()->getSymbol();
411 
412   MCAsmBackend &Backend = Asm.getBackend();
413   bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
414                  MCFixupKindInfo::FKF_IsPCRel;
415 
416   uint8_t Type;
417   uint8_t SignAndSize;
418   std::tie(Type, SignAndSize) =
419       TargetObjectWriter->getRelocTypeAndSignSize(Target, Fixup, IsPCRel);
420 
421   const MCSectionXCOFF *SymASec = getContainingCsect(cast<MCSymbolXCOFF>(SymA));
422   assert(SectionMap.find(SymASec) != SectionMap.end() &&
423          "Expected containing csect to exist in map.");
424 
425   const uint32_t Index = getIndex(SymA, SymASec);
426   if (Type == XCOFF::RelocationType::R_POS)
427     // The FixedValue should be symbol's virtual address in this object file
428     // plus any constant value that we might get.
429     FixedValue = getVirtualAddress(SymA, SymASec) + Target.getConstant();
430   else if (Type == XCOFF::RelocationType::R_TOC)
431     // The FixedValue should be the TC entry offset from TOC-base.
432     FixedValue = SectionMap[SymASec]->Address - TOCCsects.front().Address;
433 
434   assert(
435       (TargetObjectWriter->is64Bit() ||
436        Fixup.getOffset() <= UINT32_MAX - Layout.getFragmentOffset(Fragment)) &&
437       "Fragment offset + fixup offset is overflowed in 32-bit mode.");
438   uint32_t FixupOffsetInCsect =
439       Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
440 
441   XCOFFRelocation Reloc = {Index, FixupOffsetInCsect, SignAndSize, Type};
442   MCSectionXCOFF *RelocationSec = cast<MCSectionXCOFF>(Fragment->getParent());
443   assert(SectionMap.find(RelocationSec) != SectionMap.end() &&
444          "Expected containing csect to exist in map.");
445   SectionMap[RelocationSec]->Relocations.push_back(Reloc);
446 
447   if (!Target.getSymB())
448     return;
449 
450   const MCSymbol *const SymB = &Target.getSymB()->getSymbol();
451   if (SymA == SymB)
452     report_fatal_error("relocation for opposite term is not yet supported");
453 
454   const MCSectionXCOFF *SymBSec = getContainingCsect(cast<MCSymbolXCOFF>(SymB));
455   assert(SectionMap.find(SymBSec) != SectionMap.end() &&
456          "Expected containing csect to exist in map.");
457   if (SymASec == SymBSec)
458     report_fatal_error(
459         "relocation for paired relocatable term is not yet supported");
460 
461   assert(Type == XCOFF::RelocationType::R_POS &&
462          "SymA must be R_POS here if it's not opposite term or paired "
463          "relocatable term.");
464   const uint32_t IndexB = getIndex(SymB, SymBSec);
465   // SymB must be R_NEG here, given the general form of Target(MCValue) is
466   // "SymbolA - SymbolB + imm64".
467   const uint8_t TypeB = XCOFF::RelocationType::R_NEG;
468   XCOFFRelocation RelocB = {IndexB, FixupOffsetInCsect, SignAndSize, TypeB};
469   SectionMap[RelocationSec]->Relocations.push_back(RelocB);
470   // We already folded "SymbolA + imm64" above when Type is R_POS for SymbolA,
471   // now we just need to fold "- SymbolB" here.
472   FixedValue -= getVirtualAddress(SymB, SymBSec);
473 }
474 
475 void XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
476                                       const MCAsmLayout &Layout) {
477   uint32_t CurrentAddressLocation = 0;
478   for (const auto *Section : Sections) {
479     // Nothing to write for this Section.
480     if (Section->Index == Section::UninitializedIndex || Section->IsVirtual)
481       continue;
482 
483     // There could be a gap (without corresponding zero padding) between
484     // sections.
485     assert(CurrentAddressLocation <= Section->Address &&
486            "CurrentAddressLocation should be less than or equal to section "
487            "address.");
488 
489     CurrentAddressLocation = Section->Address;
490 
491     for (const auto *Group : Section->Groups) {
492       for (const auto &Csect : *Group) {
493         if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation)
494           W.OS.write_zeros(PaddingSize);
495         if (Csect.Size)
496           Asm.writeSectionData(W.OS, Csect.MCCsect, Layout);
497         CurrentAddressLocation = Csect.Address + Csect.Size;
498       }
499     }
500 
501     // The size of the tail padding in a section is the end virtual address of
502     // the current section minus the the end virtual address of the last csect
503     // in that section.
504     if (uint32_t PaddingSize =
505             Section->Address + Section->Size - CurrentAddressLocation) {
506       W.OS.write_zeros(PaddingSize);
507       CurrentAddressLocation += PaddingSize;
508     }
509   }
510 }
511 
512 uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm,
513                                         const MCAsmLayout &Layout) {
514   // We always emit a timestamp of 0 for reproducibility, so ensure incremental
515   // linking is not enabled, in case, like with Windows COFF, such a timestamp
516   // is incompatible with incremental linking of XCOFF.
517   if (Asm.isIncrementalLinkerCompatible())
518     report_fatal_error("Incremental linking not supported for XCOFF.");
519 
520   if (TargetObjectWriter->is64Bit())
521     report_fatal_error("64-bit XCOFF object files are not supported yet.");
522 
523   finalizeSectionInfo();
524   uint64_t StartOffset = W.OS.tell();
525 
526   writeFileHeader();
527   writeSectionHeaderTable();
528   writeSections(Asm, Layout);
529   writeRelocations();
530 
531   writeSymbolTable(Layout);
532   // Write the string table.
533   Strings.write(W.OS);
534 
535   return W.OS.tell() - StartOffset;
536 }
537 
538 bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) {
539   return SymbolName.size() > XCOFF::NameSize;
540 }
541 
542 void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) {
543   if (nameShouldBeInStringTable(SymbolName)) {
544     W.write<int32_t>(0);
545     W.write<uint32_t>(Strings.getOffset(SymbolName));
546   } else {
547     char Name[XCOFF::NameSize+1];
548     std::strncpy(Name, SymbolName.data(), XCOFF::NameSize);
549     ArrayRef<char> NameRef(Name, XCOFF::NameSize);
550     W.write(NameRef);
551   }
552 }
553 
554 void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel(
555     const Symbol &SymbolRef, const ControlSection &CSectionRef,
556     int16_t SectionIndex, uint64_t SymbolOffset) {
557   // Name or Zeros and string table offset
558   writeSymbolName(SymbolRef.getSymbolTableName());
559   assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address &&
560          "Symbol address overflows.");
561   W.write<uint32_t>(CSectionRef.Address + SymbolOffset);
562   W.write<int16_t>(SectionIndex);
563   // Basic/Derived type. See the description of the n_type field for symbol
564   // table entries for a detailed description. Since we don't yet support
565   // visibility, and all other bits are either optionally set or reserved, this
566   // is always zero.
567   // TODO FIXME How to assert a symbol's visibilty is default?
568   // TODO Set the function indicator (bit 10, 0x0020) for functions
569   // when debugging is enabled.
570   W.write<uint16_t>(0);
571   W.write<uint8_t>(SymbolRef.getStorageClass());
572   // Always 1 aux entry for now.
573   W.write<uint8_t>(1);
574 
575   // Now output the auxiliary entry.
576   W.write<uint32_t>(CSectionRef.SymbolTableIndex);
577   // Parameter typecheck hash. Not supported.
578   W.write<uint32_t>(0);
579   // Typecheck section number. Not supported.
580   W.write<uint16_t>(0);
581   // Symbol type: Label
582   W.write<uint8_t>(XCOFF::XTY_LD);
583   // Storage mapping class.
584   W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
585   // Reserved (x_stab).
586   W.write<uint32_t>(0);
587   // Reserved (x_snstab).
588   W.write<uint16_t>(0);
589 }
590 
591 void XCOFFObjectWriter::writeSymbolTableEntryForControlSection(
592     const ControlSection &CSectionRef, int16_t SectionIndex,
593     XCOFF::StorageClass StorageClass) {
594   // n_name, n_zeros, n_offset
595   writeSymbolName(CSectionRef.getSymbolTableName());
596   // n_value
597   W.write<uint32_t>(CSectionRef.Address);
598   // n_scnum
599   W.write<int16_t>(SectionIndex);
600   // Basic/Derived type. See the description of the n_type field for symbol
601   // table entries for a detailed description. Since we don't yet support
602   // visibility, and all other bits are either optionally set or reserved, this
603   // is always zero.
604   // TODO FIXME How to assert a symbol's visibilty is default?
605   // TODO Set the function indicator (bit 10, 0x0020) for functions
606   // when debugging is enabled.
607   W.write<uint16_t>(0);
608   // n_sclass
609   W.write<uint8_t>(StorageClass);
610   // Always 1 aux entry for now.
611   W.write<uint8_t>(1);
612 
613   // Now output the auxiliary entry.
614   W.write<uint32_t>(CSectionRef.Size);
615   // Parameter typecheck hash. Not supported.
616   W.write<uint32_t>(0);
617   // Typecheck section number. Not supported.
618   W.write<uint16_t>(0);
619   // Symbol type.
620   W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect));
621   // Storage mapping class.
622   W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
623   // Reserved (x_stab).
624   W.write<uint32_t>(0);
625   // Reserved (x_snstab).
626   W.write<uint16_t>(0);
627 }
628 
629 void XCOFFObjectWriter::writeFileHeader() {
630   // Magic.
631   W.write<uint16_t>(0x01df);
632   // Number of sections.
633   W.write<uint16_t>(SectionCount);
634   // Timestamp field. For reproducible output we write a 0, which represents no
635   // timestamp.
636   W.write<int32_t>(0);
637   // Byte Offset to the start of the symbol table.
638   W.write<uint32_t>(SymbolTableOffset);
639   // Number of entries in the symbol table.
640   W.write<int32_t>(SymbolTableEntryCount);
641   // Size of the optional header.
642   W.write<uint16_t>(0);
643   // Flags.
644   W.write<uint16_t>(0);
645 }
646 
647 void XCOFFObjectWriter::writeSectionHeaderTable() {
648   for (const auto *Sec : Sections) {
649     // Nothing to write for this Section.
650     if (Sec->Index == Section::UninitializedIndex)
651       continue;
652 
653     // Write Name.
654     ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
655     W.write(NameRef);
656 
657     // Write the Physical Address and Virtual Address. In an object file these
658     // are the same.
659     W.write<uint32_t>(Sec->Address);
660     W.write<uint32_t>(Sec->Address);
661 
662     W.write<uint32_t>(Sec->Size);
663     W.write<uint32_t>(Sec->FileOffsetToData);
664     W.write<uint32_t>(Sec->FileOffsetToRelocations);
665 
666     // Line number pointer. Not supported yet.
667     W.write<uint32_t>(0);
668 
669     W.write<uint16_t>(Sec->RelocationCount);
670 
671     // Line number counts. Not supported yet.
672     W.write<uint16_t>(0);
673 
674     W.write<int32_t>(Sec->Flags);
675   }
676 }
677 
678 void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc,
679                                         const ControlSection &CSection) {
680   W.write<uint32_t>(CSection.Address + Reloc.FixupOffsetInCsect);
681   W.write<uint32_t>(Reloc.SymbolTableIndex);
682   W.write<uint8_t>(Reloc.SignAndSize);
683   W.write<uint8_t>(Reloc.Type);
684 }
685 
686 void XCOFFObjectWriter::writeRelocations() {
687   for (const auto *Section : Sections) {
688     if (Section->Index == Section::UninitializedIndex)
689       // Nothing to write for this Section.
690       continue;
691 
692     for (const auto *Group : Section->Groups) {
693       if (Group->empty())
694         continue;
695 
696       for (const auto &Csect : *Group) {
697         for (const auto Reloc : Csect.Relocations)
698           writeRelocation(Reloc, Csect);
699       }
700     }
701   }
702 }
703 
704 void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
705   for (const auto &Csect : UndefinedCsects) {
706     writeSymbolTableEntryForControlSection(
707         Csect, XCOFF::ReservedSectionNum::N_UNDEF, Csect.MCCsect->getStorageClass());
708   }
709 
710   for (const auto *Section : Sections) {
711     if (Section->Index == Section::UninitializedIndex)
712       // Nothing to write for this Section.
713       continue;
714 
715     for (const auto *Group : Section->Groups) {
716       if (Group->empty())
717         continue;
718 
719       const int16_t SectionIndex = Section->Index;
720       for (const auto &Csect : *Group) {
721         // Write out the control section first and then each symbol in it.
722         writeSymbolTableEntryForControlSection(
723             Csect, SectionIndex, Csect.MCCsect->getStorageClass());
724 
725         for (const auto &Sym : Csect.Syms)
726           writeSymbolTableEntryForCsectMemberLabel(
727               Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym)));
728       }
729     }
730   }
731 }
732 
733 void XCOFFObjectWriter::finalizeSectionInfo() {
734   for (auto *Section : Sections) {
735     if (Section->Index == Section::UninitializedIndex)
736       // Nothing to record for this Section.
737       continue;
738 
739     for (const auto *Group : Section->Groups) {
740       if (Group->empty())
741         continue;
742 
743       for (auto &Csect : *Group) {
744         const size_t CsectRelocCount = Csect.Relocations.size();
745         if (CsectRelocCount >= XCOFF::RelocOverflow ||
746             Section->RelocationCount >= XCOFF::RelocOverflow - CsectRelocCount)
747           report_fatal_error(
748               "relocation entries overflowed; overflow section is "
749               "not implemented yet");
750 
751         Section->RelocationCount += CsectRelocCount;
752       }
753     }
754   }
755 
756   // Calculate the file offset to the relocation entries.
757   uint64_t RawPointer = RelocationEntryOffset;
758   for (auto Sec : Sections) {
759     if (Sec->Index == Section::UninitializedIndex || !Sec->RelocationCount)
760       continue;
761 
762     Sec->FileOffsetToRelocations = RawPointer;
763     const uint32_t RelocationSizeInSec =
764         Sec->RelocationCount * XCOFF::RelocationSerializationSize32;
765     RawPointer += RelocationSizeInSec;
766     if (RawPointer > UINT32_MAX)
767       report_fatal_error("Relocation data overflowed this object file.");
768   }
769 
770   // TODO Error check that the number of symbol table entries fits in 32-bits
771   // signed ...
772   if (SymbolTableEntryCount)
773     SymbolTableOffset = RawPointer;
774 }
775 
776 void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
777   // The first symbol table entry is for the file name. We are not emitting it
778   // yet, so start at index 0.
779   uint32_t SymbolTableIndex = 0;
780 
781   // Calculate indices for undefined symbols.
782   for (auto &Csect : UndefinedCsects) {
783     Csect.Size = 0;
784     Csect.Address = 0;
785     Csect.SymbolTableIndex = SymbolTableIndex;
786     SymbolIndexMap[Csect.MCCsect->getQualNameSymbol()] = Csect.SymbolTableIndex;
787     // 1 main and 1 auxiliary symbol table entry for each contained symbol.
788     SymbolTableIndex += 2;
789   }
790 
791   // The address corrresponds to the address of sections and symbols in the
792   // object file. We place the shared address 0 immediately after the
793   // section header table.
794   uint32_t Address = 0;
795   // Section indices are 1-based in XCOFF.
796   int32_t SectionIndex = 1;
797 
798   for (auto *Section : Sections) {
799     const bool IsEmpty =
800         llvm::all_of(Section->Groups,
801                      [](const CsectGroup *Group) { return Group->empty(); });
802     if (IsEmpty)
803       continue;
804 
805     if (SectionIndex > MaxSectionIndex)
806       report_fatal_error("Section index overflow!");
807     Section->Index = SectionIndex++;
808     SectionCount++;
809 
810     bool SectionAddressSet = false;
811     for (auto *Group : Section->Groups) {
812       if (Group->empty())
813         continue;
814 
815       for (auto &Csect : *Group) {
816         const MCSectionXCOFF *MCSec = Csect.MCCsect;
817         Csect.Address = alignTo(Address, MCSec->getAlignment());
818         Csect.Size = Layout.getSectionAddressSize(MCSec);
819         Address = Csect.Address + Csect.Size;
820         Csect.SymbolTableIndex = SymbolTableIndex;
821         SymbolIndexMap[MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex;
822         // 1 main and 1 auxiliary symbol table entry for the csect.
823         SymbolTableIndex += 2;
824 
825         for (auto &Sym : Csect.Syms) {
826           Sym.SymbolTableIndex = SymbolTableIndex;
827           SymbolIndexMap[Sym.MCSym] = Sym.SymbolTableIndex;
828           // 1 main and 1 auxiliary symbol table entry for each contained
829           // symbol.
830           SymbolTableIndex += 2;
831         }
832       }
833 
834       if (!SectionAddressSet) {
835         Section->Address = Group->front().Address;
836         SectionAddressSet = true;
837       }
838     }
839 
840     // Make sure the address of the next section aligned to
841     // DefaultSectionAlign.
842     Address = alignTo(Address, DefaultSectionAlign);
843     Section->Size = Address - Section->Address;
844   }
845 
846   SymbolTableEntryCount = SymbolTableIndex;
847 
848   // Calculate the RawPointer value for each section.
849   uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
850                         SectionCount * sizeof(XCOFF::SectionHeader32);
851   for (auto *Sec : Sections) {
852     if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual)
853       continue;
854 
855     Sec->FileOffsetToData = RawPointer;
856     RawPointer += Sec->Size;
857     if (RawPointer > UINT32_MAX)
858       report_fatal_error("Section raw data overflowed this object file.");
859   }
860 
861   RelocationEntryOffset = RawPointer;
862 }
863 
864 // Takes the log base 2 of the alignment and shifts the result into the 5 most
865 // significant bits of a byte, then or's in the csect type into the least
866 // significant 3 bits.
867 uint8_t getEncodedType(const MCSectionXCOFF *Sec) {
868   unsigned Align = Sec->getAlignment();
869   assert(isPowerOf2_32(Align) && "Alignment must be a power of 2.");
870   unsigned Log2Align = Log2_32(Align);
871   // Result is a number in the range [0, 31] which fits in the 5 least
872   // significant bits. Shift this value into the 5 most significant bits, and
873   // bitwise-or in the csect type.
874   uint8_t EncodedAlign = Log2Align << 3;
875   return EncodedAlign | Sec->getCSectType();
876 }
877 
878 } // end anonymous namespace
879 
880 std::unique_ptr<MCObjectWriter>
881 llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
882                               raw_pwrite_stream &OS) {
883   return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
884 }
885