1351278Sdim//===-- lib/MC/XCOFFObjectWriter.cpp - XCOFF file writer ------------------===//
2351278Sdim//
3351278Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4351278Sdim// See https://llvm.org/LICENSE.txt for license information.
5351278Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6351278Sdim//
7351278Sdim//===----------------------------------------------------------------------===//
8351278Sdim//
9351278Sdim// This file implements XCOFF object file writer information.
10351278Sdim//
11351278Sdim//===----------------------------------------------------------------------===//
12351278Sdim
13360784Sdim#include "llvm/BinaryFormat/XCOFF.h"
14360784Sdim#include "llvm/MC/MCAsmLayout.h"
15351278Sdim#include "llvm/MC/MCAssembler.h"
16351278Sdim#include "llvm/MC/MCObjectWriter.h"
17360784Sdim#include "llvm/MC/MCSectionXCOFF.h"
18360784Sdim#include "llvm/MC/MCSymbolXCOFF.h"
19351278Sdim#include "llvm/MC/MCValue.h"
20351278Sdim#include "llvm/MC/MCXCOFFObjectWriter.h"
21360784Sdim#include "llvm/MC/StringTableBuilder.h"
22360784Sdim#include "llvm/Support/Error.h"
23360784Sdim#include "llvm/Support/MathExtras.h"
24351278Sdim
25360784Sdim#include <deque>
26360784Sdim
27351278Sdimusing namespace llvm;
28351278Sdim
29360784Sdim// An XCOFF object file has a limited set of predefined sections. The most
30360784Sdim// important ones for us (right now) are:
31360784Sdim// .text --> contains program code and read-only data.
32360784Sdim// .data --> contains initialized data, function descriptors, and the TOC.
33360784Sdim// .bss  --> contains uninitialized data.
34360784Sdim// Each of these sections is composed of 'Control Sections'. A Control Section
35360784Sdim// is more commonly referred to as a csect. A csect is an indivisible unit of
36360784Sdim// code or data, and acts as a container for symbols. A csect is mapped
37360784Sdim// into a section based on its storage-mapping class, with the exception of
38360784Sdim// XMC_RW which gets mapped to either .data or .bss based on whether it's
39360784Sdim// explicitly initialized or not.
40360784Sdim//
41360784Sdim// We don't represent the sections in the MC layer as there is nothing
42360784Sdim// interesting about them at at that level: they carry information that is
43360784Sdim// only relevant to the ObjectWriter, so we materialize them in this class.
44351278Sdimnamespace {
45351278Sdim
46360784Sdimconstexpr unsigned DefaultSectionAlign = 4;
47360784Sdimconstexpr int16_t MaxSectionIndex = INT16_MAX;
48360784Sdim
49360784Sdim// Packs the csect's alignment and type into a byte.
50360784Sdimuint8_t getEncodedType(const MCSectionXCOFF *);
51360784Sdim
52360784Sdim// Wrapper around an MCSymbolXCOFF.
53360784Sdimstruct Symbol {
54360784Sdim  const MCSymbolXCOFF *const MCSym;
55360784Sdim  uint32_t SymbolTableIndex;
56360784Sdim
57360784Sdim  XCOFF::StorageClass getStorageClass() const {
58360784Sdim    return MCSym->getStorageClass();
59360784Sdim  }
60360784Sdim  StringRef getName() const { return MCSym->getName(); }
61360784Sdim  Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {}
62360784Sdim};
63360784Sdim
64360784Sdim// Wrapper for an MCSectionXCOFF.
65360784Sdimstruct ControlSection {
66360784Sdim  const MCSectionXCOFF *const MCCsect;
67360784Sdim  uint32_t SymbolTableIndex;
68360784Sdim  uint32_t Address;
69360784Sdim  uint32_t Size;
70360784Sdim
71360784Sdim  SmallVector<Symbol, 1> Syms;
72360784Sdim  StringRef getName() const { return MCCsect->getSectionName(); }
73360784Sdim  ControlSection(const MCSectionXCOFF *MCSec)
74360784Sdim      : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {}
75360784Sdim};
76360784Sdim
77360784Sdim// Type to be used for a container representing a set of csects with
78360784Sdim// (approximately) the same storage mapping class. For example all the csects
79360784Sdim// with a storage mapping class of `xmc_pr` will get placed into the same
80360784Sdim// container.
81360784Sdimusing CsectGroup = std::deque<ControlSection>;
82360784Sdim
83360784Sdimusing CsectGroups = std::deque<CsectGroup *>;
84360784Sdim
85360784Sdim// Represents the data related to a section excluding the csects that make up
86360784Sdim// the raw data of the section. The csects are stored separately as not all
87360784Sdim// sections contain csects, and some sections contain csects which are better
88360784Sdim// stored separately, e.g. the .data section containing read-write, descriptor,
89360784Sdim// TOCBase and TOC-entry csects.
90360784Sdimstruct Section {
91360784Sdim  char Name[XCOFF::NameSize];
92360784Sdim  // The physical/virtual address of the section. For an object file
93360784Sdim  // these values are equivalent.
94360784Sdim  uint32_t Address;
95360784Sdim  uint32_t Size;
96360784Sdim  uint32_t FileOffsetToData;
97360784Sdim  uint32_t FileOffsetToRelocations;
98360784Sdim  uint32_t RelocationCount;
99360784Sdim  int32_t Flags;
100360784Sdim
101360784Sdim  int16_t Index;
102360784Sdim
103360784Sdim  // Virtual sections do not need storage allocated in the object file.
104360784Sdim  const bool IsVirtual;
105360784Sdim
106360784Sdim  // XCOFF has special section numbers for symbols:
107360784Sdim  // -2 Specifies N_DEBUG, a special symbolic debugging symbol.
108360784Sdim  // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not
109360784Sdim  // relocatable.
110360784Sdim  //  0 Specifies N_UNDEF, an undefined external symbol.
111360784Sdim  // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that
112360784Sdim  // hasn't been initialized.
113360784Sdim  static constexpr int16_t UninitializedIndex =
114360784Sdim      XCOFF::ReservedSectionNum::N_DEBUG - 1;
115360784Sdim
116360784Sdim  CsectGroups Groups;
117360784Sdim
118360784Sdim  void reset() {
119360784Sdim    Address = 0;
120360784Sdim    Size = 0;
121360784Sdim    FileOffsetToData = 0;
122360784Sdim    FileOffsetToRelocations = 0;
123360784Sdim    RelocationCount = 0;
124360784Sdim    Index = UninitializedIndex;
125360784Sdim    // Clear any csects we have stored.
126360784Sdim    for (auto *Group : Groups)
127360784Sdim      Group->clear();
128360784Sdim  }
129360784Sdim
130360784Sdim  Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual,
131360784Sdim          CsectGroups Groups)
132360784Sdim      : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0),
133360784Sdim        RelocationCount(0), Flags(Flags), Index(UninitializedIndex),
134360784Sdim        IsVirtual(IsVirtual), Groups(Groups) {
135360784Sdim    strncpy(Name, N, XCOFF::NameSize);
136360784Sdim  }
137360784Sdim};
138360784Sdim
139351278Sdimclass XCOFFObjectWriter : public MCObjectWriter {
140360784Sdim
141360784Sdim  uint32_t SymbolTableEntryCount = 0;
142360784Sdim  uint32_t SymbolTableOffset = 0;
143360784Sdim  uint16_t SectionCount = 0;
144360784Sdim
145351278Sdim  support::endian::Writer W;
146351278Sdim  std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
147360784Sdim  StringTableBuilder Strings;
148351278Sdim
149360784Sdim  // CsectGroups. These store the csects which make up different parts of
150360784Sdim  // the sections. Should have one for each set of csects that get mapped into
151360784Sdim  // the same section and get handled in a 'similar' way.
152360784Sdim  CsectGroup UndefinedCsects;
153360784Sdim  CsectGroup ProgramCodeCsects;
154360784Sdim  CsectGroup ReadOnlyCsects;
155360784Sdim  CsectGroup DataCsects;
156360784Sdim  CsectGroup FuncDSCsects;
157360784Sdim  CsectGroup TOCCsects;
158360784Sdim  CsectGroup BSSCsects;
159360784Sdim
160360784Sdim  // The Predefined sections.
161360784Sdim  Section Text;
162360784Sdim  Section Data;
163360784Sdim  Section BSS;
164360784Sdim
165360784Sdim  // All the XCOFF sections, in the order they will appear in the section header
166360784Sdim  // table.
167360784Sdim  std::array<Section *const, 3> Sections{{&Text, &Data, &BSS}};
168360784Sdim
169360784Sdim  CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec);
170360784Sdim
171360784Sdim  virtual void reset() override;
172360784Sdim
173351278Sdim  void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
174351278Sdim
175351278Sdim  void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *,
176351278Sdim                        const MCFixup &, MCValue, uint64_t &) override;
177351278Sdim
178351278Sdim  uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
179351278Sdim
180360784Sdim  static bool nameShouldBeInStringTable(const StringRef &);
181360784Sdim  void writeSymbolName(const StringRef &);
182360784Sdim  void writeSymbolTableEntryForCsectMemberLabel(const Symbol &,
183360784Sdim                                                const ControlSection &, int16_t,
184360784Sdim                                                uint64_t);
185360784Sdim  void writeSymbolTableEntryForControlSection(const ControlSection &, int16_t,
186360784Sdim                                              XCOFF::StorageClass);
187360784Sdim  void writeFileHeader();
188360784Sdim  void writeSectionHeaderTable();
189360784Sdim  void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout);
190360784Sdim  void writeSymbolTable(const MCAsmLayout &Layout);
191360784Sdim
192360784Sdim  // Called after all the csects and symbols have been processed by
193360784Sdim  // `executePostLayoutBinding`, this function handles building up the majority
194360784Sdim  // of the structures in the object file representation. Namely:
195360784Sdim  // *) Calculates physical/virtual addresses, raw-pointer offsets, and section
196360784Sdim  //    sizes.
197360784Sdim  // *) Assigns symbol table indices.
198360784Sdim  // *) Builds up the section header table by adding any non-empty sections to
199360784Sdim  //    `Sections`.
200360784Sdim  void assignAddressesAndIndices(const MCAsmLayout &);
201360784Sdim
202360784Sdim  bool
203360784Sdim  needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */
204360784Sdim    return false;
205360784Sdim  }
206360784Sdim
207360784Sdim  // Returns the size of the auxiliary header to be written to the object file.
208360784Sdim  size_t auxiliaryHeaderSize() const {
209360784Sdim    assert(!needsAuxiliaryHeader() &&
210360784Sdim           "Auxiliary header support not implemented.");
211360784Sdim    return 0;
212360784Sdim  }
213360784Sdim
214351278Sdimpublic:
215351278Sdim  XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
216351278Sdim                    raw_pwrite_stream &OS);
217351278Sdim};
218351278Sdim
219351278SdimXCOFFObjectWriter::XCOFFObjectWriter(
220351278Sdim    std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
221360784Sdim    : W(OS, support::big), TargetObjectWriter(std::move(MOTW)),
222360784Sdim      Strings(StringTableBuilder::XCOFF),
223360784Sdim      Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false,
224360784Sdim           CsectGroups{&ProgramCodeCsects, &ReadOnlyCsects}),
225360784Sdim      Data(".data", XCOFF::STYP_DATA, /* IsVirtual */ false,
226360784Sdim           CsectGroups{&DataCsects, &FuncDSCsects, &TOCCsects}),
227360784Sdim      BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true,
228360784Sdim          CsectGroups{&BSSCsects}) {}
229351278Sdim
230360784Sdimvoid XCOFFObjectWriter::reset() {
231360784Sdim  UndefinedCsects.clear();
232360784Sdim
233360784Sdim  // Reset any sections we have written to, and empty the section header table.
234360784Sdim  for (auto *Sec : Sections)
235360784Sdim    Sec->reset();
236360784Sdim
237360784Sdim  // Reset the symbol table and string table.
238360784Sdim  SymbolTableEntryCount = 0;
239360784Sdim  SymbolTableOffset = 0;
240360784Sdim  SectionCount = 0;
241360784Sdim  Strings.clear();
242360784Sdim
243360784Sdim  MCObjectWriter::reset();
244351278Sdim}
245351278Sdim
246360784SdimCsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) {
247360784Sdim  switch (MCSec->getMappingClass()) {
248360784Sdim  case XCOFF::XMC_PR:
249360784Sdim    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
250360784Sdim           "Only an initialized csect can contain program code.");
251360784Sdim    return ProgramCodeCsects;
252360784Sdim  case XCOFF::XMC_RO:
253360784Sdim    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
254360784Sdim           "Only an initialized csect can contain read only data.");
255360784Sdim    return ReadOnlyCsects;
256360784Sdim  case XCOFF::XMC_RW:
257360784Sdim    if (XCOFF::XTY_CM == MCSec->getCSectType())
258360784Sdim      return BSSCsects;
259360784Sdim
260360784Sdim    if (XCOFF::XTY_SD == MCSec->getCSectType())
261360784Sdim      return DataCsects;
262360784Sdim
263360784Sdim    report_fatal_error("Unhandled mapping of read-write csect to section.");
264360784Sdim  case XCOFF::XMC_DS:
265360784Sdim    return FuncDSCsects;
266360784Sdim  case XCOFF::XMC_BS:
267360784Sdim    assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
268360784Sdim           "Mapping invalid csect. CSECT with bss storage class must be "
269360784Sdim           "common type.");
270360784Sdim    return BSSCsects;
271360784Sdim  case XCOFF::XMC_TC0:
272360784Sdim    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
273360784Sdim           "Only an initialized csect can contain TOC-base.");
274360784Sdim    assert(TOCCsects.empty() &&
275360784Sdim           "We should have only one TOC-base, and it should be the first csect "
276360784Sdim           "in this CsectGroup.");
277360784Sdim    return TOCCsects;
278360784Sdim  case XCOFF::XMC_TC:
279360784Sdim    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
280360784Sdim           "Only an initialized csect can contain TC entry.");
281360784Sdim    assert(!TOCCsects.empty() &&
282360784Sdim           "We should at least have a TOC-base in this CsectGroup.");
283360784Sdim    return TOCCsects;
284360784Sdim  default:
285360784Sdim    report_fatal_error("Unhandled mapping of csect to section.");
286360784Sdim  }
287360784Sdim}
288360784Sdim
289360784Sdimvoid XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
290360784Sdim                                                 const MCAsmLayout &Layout) {
291360784Sdim  if (TargetObjectWriter->is64Bit())
292360784Sdim    report_fatal_error("64-bit XCOFF object files are not supported yet.");
293360784Sdim
294360784Sdim  // Maps the MC Section representation to its corresponding ControlSection
295360784Sdim  // wrapper. Needed for finding the ControlSection to insert an MCSymbol into
296360784Sdim  // from its containing MCSectionXCOFF.
297360784Sdim  DenseMap<const MCSectionXCOFF *, ControlSection *> WrapperMap;
298360784Sdim
299360784Sdim  for (const auto &S : Asm) {
300360784Sdim    const auto *MCSec = cast<const MCSectionXCOFF>(&S);
301360784Sdim    assert(WrapperMap.find(MCSec) == WrapperMap.end() &&
302360784Sdim           "Cannot add a csect twice.");
303360784Sdim    assert(XCOFF::XTY_ER != MCSec->getCSectType() &&
304360784Sdim           "An undefined csect should not get registered.");
305360784Sdim
306360784Sdim    // If the name does not fit in the storage provided in the symbol table
307360784Sdim    // entry, add it to the string table.
308360784Sdim    if (nameShouldBeInStringTable(MCSec->getSectionName()))
309360784Sdim      Strings.add(MCSec->getSectionName());
310360784Sdim
311360784Sdim    CsectGroup &Group = getCsectGroup(MCSec);
312360784Sdim    Group.emplace_back(MCSec);
313360784Sdim    WrapperMap[MCSec] = &Group.back();
314360784Sdim  }
315360784Sdim
316360784Sdim  for (const MCSymbol &S : Asm.symbols()) {
317360784Sdim    // Nothing to do for temporary symbols.
318360784Sdim    if (S.isTemporary())
319360784Sdim      continue;
320360784Sdim
321360784Sdim    const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S);
322360784Sdim    const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect();
323360784Sdim
324360784Sdim    // Handle undefined symbol.
325360784Sdim    if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) {
326360784Sdim      UndefinedCsects.emplace_back(ContainingCsect);
327360784Sdim      continue;
328360784Sdim    }
329360784Sdim
330360784Sdim    // If the symbol is the csect itself, we don't need to put the symbol
331360784Sdim    // into csect's Syms.
332360784Sdim    if (XSym == ContainingCsect->getQualNameSymbol())
333360784Sdim      continue;
334360784Sdim
335360784Sdim    assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() &&
336360784Sdim           "Expected containing csect to exist in map");
337360784Sdim
338360784Sdim    // Lookup the containing csect and add the symbol to it.
339360784Sdim    WrapperMap[ContainingCsect]->Syms.emplace_back(XSym);
340360784Sdim
341360784Sdim    // If the name does not fit in the storage provided in the symbol table
342360784Sdim    // entry, add it to the string table.
343360784Sdim    if (nameShouldBeInStringTable(XSym->getName()))
344360784Sdim      Strings.add(XSym->getName());
345360784Sdim    }
346360784Sdim
347360784Sdim  Strings.finalize();
348360784Sdim  assignAddressesAndIndices(Layout);
349360784Sdim}
350360784Sdim
351351278Sdimvoid XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &,
352351278Sdim                                         const MCFragment *, const MCFixup &,
353351278Sdim                                         MCValue, uint64_t &) {
354360784Sdim  // TODO: recordRelocation is not yet implemented.
355351278Sdim}
356351278Sdim
357360784Sdimvoid XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
358360784Sdim                                      const MCAsmLayout &Layout) {
359360784Sdim  uint32_t CurrentAddressLocation = 0;
360360784Sdim  for (const auto *Section : Sections) {
361360784Sdim    // Nothing to write for this Section.
362360784Sdim    if (Section->Index == Section::UninitializedIndex || Section->IsVirtual)
363360784Sdim      continue;
364360784Sdim
365360784Sdim    assert(CurrentAddressLocation == Section->Address &&
366360784Sdim           "Sections should be written consecutively.");
367360784Sdim    for (const auto *Group : Section->Groups) {
368360784Sdim      for (const auto &Csect : *Group) {
369360784Sdim        if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation)
370360784Sdim          W.OS.write_zeros(PaddingSize);
371360784Sdim        if (Csect.Size)
372360784Sdim          Asm.writeSectionData(W.OS, Csect.MCCsect, Layout);
373360784Sdim        CurrentAddressLocation = Csect.Address + Csect.Size;
374360784Sdim      }
375360784Sdim    }
376360784Sdim
377360784Sdim    // The size of the tail padding in a section is the end virtual address of
378360784Sdim    // the current section minus the the end virtual address of the last csect
379360784Sdim    // in that section.
380360784Sdim    if (uint32_t PaddingSize =
381360784Sdim            Section->Address + Section->Size - CurrentAddressLocation) {
382360784Sdim      W.OS.write_zeros(PaddingSize);
383360784Sdim      CurrentAddressLocation += PaddingSize;
384360784Sdim    }
385360784Sdim  }
386360784Sdim}
387360784Sdim
388360784Sdimuint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm,
389360784Sdim                                        const MCAsmLayout &Layout) {
390351278Sdim  // We always emit a timestamp of 0 for reproducibility, so ensure incremental
391351278Sdim  // linking is not enabled, in case, like with Windows COFF, such a timestamp
392351278Sdim  // is incompatible with incremental linking of XCOFF.
393351278Sdim  if (Asm.isIncrementalLinkerCompatible())
394351278Sdim    report_fatal_error("Incremental linking not supported for XCOFF.");
395351278Sdim
396351278Sdim  if (TargetObjectWriter->is64Bit())
397351278Sdim    report_fatal_error("64-bit XCOFF object files are not supported yet.");
398351278Sdim
399351278Sdim  uint64_t StartOffset = W.OS.tell();
400351278Sdim
401360784Sdim  writeFileHeader();
402360784Sdim  writeSectionHeaderTable();
403360784Sdim  writeSections(Asm, Layout);
404360784Sdim  // TODO writeRelocations();
405351278Sdim
406360784Sdim  writeSymbolTable(Layout);
407360784Sdim  // Write the string table.
408360784Sdim  Strings.write(W.OS);
409351278Sdim
410360784Sdim  return W.OS.tell() - StartOffset;
411360784Sdim}
412360784Sdim
413360784Sdimbool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) {
414360784Sdim  return SymbolName.size() > XCOFF::NameSize;
415360784Sdim}
416360784Sdim
417360784Sdimvoid XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) {
418360784Sdim  if (nameShouldBeInStringTable(SymbolName)) {
419360784Sdim    W.write<int32_t>(0);
420360784Sdim    W.write<uint32_t>(Strings.getOffset(SymbolName));
421360784Sdim  } else {
422360784Sdim    char Name[XCOFF::NameSize+1];
423360784Sdim    std::strncpy(Name, SymbolName.data(), XCOFF::NameSize);
424360784Sdim    ArrayRef<char> NameRef(Name, XCOFF::NameSize);
425360784Sdim    W.write(NameRef);
426360784Sdim  }
427360784Sdim}
428360784Sdim
429360784Sdimvoid XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel(
430360784Sdim    const Symbol &SymbolRef, const ControlSection &CSectionRef,
431360784Sdim    int16_t SectionIndex, uint64_t SymbolOffset) {
432360784Sdim  // Name or Zeros and string table offset
433360784Sdim  writeSymbolName(SymbolRef.getName());
434360784Sdim  assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address &&
435360784Sdim         "Symbol address overflows.");
436360784Sdim  W.write<uint32_t>(CSectionRef.Address + SymbolOffset);
437360784Sdim  W.write<int16_t>(SectionIndex);
438360784Sdim  // Basic/Derived type. See the description of the n_type field for symbol
439360784Sdim  // table entries for a detailed description. Since we don't yet support
440360784Sdim  // visibility, and all other bits are either optionally set or reserved, this
441360784Sdim  // is always zero.
442360784Sdim  // TODO FIXME How to assert a symbol's visibilty is default?
443360784Sdim  // TODO Set the function indicator (bit 10, 0x0020) for functions
444360784Sdim  // when debugging is enabled.
445360784Sdim  W.write<uint16_t>(0);
446360784Sdim  W.write<uint8_t>(SymbolRef.getStorageClass());
447360784Sdim  // Always 1 aux entry for now.
448360784Sdim  W.write<uint8_t>(1);
449360784Sdim
450360784Sdim  // Now output the auxiliary entry.
451360784Sdim  W.write<uint32_t>(CSectionRef.SymbolTableIndex);
452360784Sdim  // Parameter typecheck hash. Not supported.
453360784Sdim  W.write<uint32_t>(0);
454360784Sdim  // Typecheck section number. Not supported.
455360784Sdim  W.write<uint16_t>(0);
456360784Sdim  // Symbol type: Label
457360784Sdim  W.write<uint8_t>(XCOFF::XTY_LD);
458360784Sdim  // Storage mapping class.
459360784Sdim  W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
460360784Sdim  // Reserved (x_stab).
461360784Sdim  W.write<uint32_t>(0);
462360784Sdim  // Reserved (x_snstab).
463360784Sdim  W.write<uint16_t>(0);
464360784Sdim}
465360784Sdim
466360784Sdimvoid XCOFFObjectWriter::writeSymbolTableEntryForControlSection(
467360784Sdim    const ControlSection &CSectionRef, int16_t SectionIndex,
468360784Sdim    XCOFF::StorageClass StorageClass) {
469360784Sdim  // n_name, n_zeros, n_offset
470360784Sdim  writeSymbolName(CSectionRef.getName());
471360784Sdim  // n_value
472360784Sdim  W.write<uint32_t>(CSectionRef.Address);
473360784Sdim  // n_scnum
474360784Sdim  W.write<int16_t>(SectionIndex);
475360784Sdim  // Basic/Derived type. See the description of the n_type field for symbol
476360784Sdim  // table entries for a detailed description. Since we don't yet support
477360784Sdim  // visibility, and all other bits are either optionally set or reserved, this
478360784Sdim  // is always zero.
479360784Sdim  // TODO FIXME How to assert a symbol's visibilty is default?
480360784Sdim  // TODO Set the function indicator (bit 10, 0x0020) for functions
481360784Sdim  // when debugging is enabled.
482360784Sdim  W.write<uint16_t>(0);
483360784Sdim  // n_sclass
484360784Sdim  W.write<uint8_t>(StorageClass);
485360784Sdim  // Always 1 aux entry for now.
486360784Sdim  W.write<uint8_t>(1);
487360784Sdim
488360784Sdim  // Now output the auxiliary entry.
489360784Sdim  W.write<uint32_t>(CSectionRef.Size);
490360784Sdim  // Parameter typecheck hash. Not supported.
491360784Sdim  W.write<uint32_t>(0);
492360784Sdim  // Typecheck section number. Not supported.
493360784Sdim  W.write<uint16_t>(0);
494360784Sdim  // Symbol type.
495360784Sdim  W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect));
496360784Sdim  // Storage mapping class.
497360784Sdim  W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
498360784Sdim  // Reserved (x_stab).
499360784Sdim  W.write<uint32_t>(0);
500360784Sdim  // Reserved (x_snstab).
501360784Sdim  W.write<uint16_t>(0);
502360784Sdim}
503360784Sdim
504360784Sdimvoid XCOFFObjectWriter::writeFileHeader() {
505351278Sdim  // Magic.
506351278Sdim  W.write<uint16_t>(0x01df);
507351278Sdim  // Number of sections.
508360784Sdim  W.write<uint16_t>(SectionCount);
509351278Sdim  // Timestamp field. For reproducible output we write a 0, which represents no
510351278Sdim  // timestamp.
511351278Sdim  W.write<int32_t>(0);
512351278Sdim  // Byte Offset to the start of the symbol table.
513360784Sdim  W.write<uint32_t>(SymbolTableOffset);
514351278Sdim  // Number of entries in the symbol table.
515360784Sdim  W.write<int32_t>(SymbolTableEntryCount);
516351278Sdim  // Size of the optional header.
517351278Sdim  W.write<uint16_t>(0);
518351278Sdim  // Flags.
519351278Sdim  W.write<uint16_t>(0);
520360784Sdim}
521351278Sdim
522360784Sdimvoid XCOFFObjectWriter::writeSectionHeaderTable() {
523360784Sdim  for (const auto *Sec : Sections) {
524360784Sdim    // Nothing to write for this Section.
525360784Sdim    if (Sec->Index == Section::UninitializedIndex)
526360784Sdim      continue;
527360784Sdim
528360784Sdim    // Write Name.
529360784Sdim    ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
530360784Sdim    W.write(NameRef);
531360784Sdim
532360784Sdim    // Write the Physical Address and Virtual Address. In an object file these
533360784Sdim    // are the same.
534360784Sdim    W.write<uint32_t>(Sec->Address);
535360784Sdim    W.write<uint32_t>(Sec->Address);
536360784Sdim
537360784Sdim    W.write<uint32_t>(Sec->Size);
538360784Sdim    W.write<uint32_t>(Sec->FileOffsetToData);
539360784Sdim
540360784Sdim    // Relocation pointer and Lineno pointer. Not supported yet.
541360784Sdim    W.write<uint32_t>(0);
542360784Sdim    W.write<uint32_t>(0);
543360784Sdim
544360784Sdim    // Relocation and line-number counts. Not supported yet.
545360784Sdim    W.write<uint16_t>(0);
546360784Sdim    W.write<uint16_t>(0);
547360784Sdim
548360784Sdim    W.write<int32_t>(Sec->Flags);
549360784Sdim  }
550351278Sdim}
551351278Sdim
552360784Sdimvoid XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
553360784Sdim  for (const auto &Csect : UndefinedCsects) {
554360784Sdim    writeSymbolTableEntryForControlSection(
555360784Sdim        Csect, XCOFF::ReservedSectionNum::N_UNDEF, Csect.MCCsect->getStorageClass());
556360784Sdim  }
557360784Sdim
558360784Sdim  for (const auto *Section : Sections) {
559360784Sdim    // Nothing to write for this Section.
560360784Sdim    if (Section->Index == Section::UninitializedIndex)
561360784Sdim      continue;
562360784Sdim
563360784Sdim    for (const auto *Group : Section->Groups) {
564360784Sdim      if (Group->empty())
565360784Sdim        continue;
566360784Sdim
567360784Sdim      const int16_t SectionIndex = Section->Index;
568360784Sdim      for (const auto &Csect : *Group) {
569360784Sdim        // Write out the control section first and then each symbol in it.
570360784Sdim        writeSymbolTableEntryForControlSection(
571360784Sdim            Csect, SectionIndex, Csect.MCCsect->getStorageClass());
572360784Sdim
573360784Sdim        for (const auto &Sym : Csect.Syms)
574360784Sdim          writeSymbolTableEntryForCsectMemberLabel(
575360784Sdim              Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym)));
576360784Sdim      }
577360784Sdim    }
578360784Sdim  }
579360784Sdim}
580360784Sdim
581360784Sdimvoid XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
582360784Sdim  // The first symbol table entry is for the file name. We are not emitting it
583360784Sdim  // yet, so start at index 0.
584360784Sdim  uint32_t SymbolTableIndex = 0;
585360784Sdim
586360784Sdim  // Calculate indices for undefined symbols.
587360784Sdim  for (auto &Csect : UndefinedCsects) {
588360784Sdim    Csect.Size = 0;
589360784Sdim    Csect.Address = 0;
590360784Sdim    Csect.SymbolTableIndex = SymbolTableIndex;
591360784Sdim    // 1 main and 1 auxiliary symbol table entry for each contained symbol.
592360784Sdim    SymbolTableIndex += 2;
593360784Sdim  }
594360784Sdim
595360784Sdim  // The address corrresponds to the address of sections and symbols in the
596360784Sdim  // object file. We place the shared address 0 immediately after the
597360784Sdim  // section header table.
598360784Sdim  uint32_t Address = 0;
599360784Sdim  // Section indices are 1-based in XCOFF.
600360784Sdim  int32_t SectionIndex = 1;
601360784Sdim
602360784Sdim  for (auto *Section : Sections) {
603360784Sdim    const bool IsEmpty =
604360784Sdim        llvm::all_of(Section->Groups,
605360784Sdim                     [](const CsectGroup *Group) { return Group->empty(); });
606360784Sdim    if (IsEmpty)
607360784Sdim      continue;
608360784Sdim
609360784Sdim    if (SectionIndex > MaxSectionIndex)
610360784Sdim      report_fatal_error("Section index overflow!");
611360784Sdim    Section->Index = SectionIndex++;
612360784Sdim    SectionCount++;
613360784Sdim
614360784Sdim    bool SectionAddressSet = false;
615360784Sdim    for (auto *Group : Section->Groups) {
616360784Sdim      if (Group->empty())
617360784Sdim        continue;
618360784Sdim
619360784Sdim      for (auto &Csect : *Group) {
620360784Sdim        const MCSectionXCOFF *MCSec = Csect.MCCsect;
621360784Sdim        Csect.Address = alignTo(Address, MCSec->getAlignment());
622360784Sdim        Csect.Size = Layout.getSectionAddressSize(MCSec);
623360784Sdim        Address = Csect.Address + Csect.Size;
624360784Sdim        Csect.SymbolTableIndex = SymbolTableIndex;
625360784Sdim        // 1 main and 1 auxiliary symbol table entry for the csect.
626360784Sdim        SymbolTableIndex += 2;
627360784Sdim
628360784Sdim        for (auto &Sym : Csect.Syms) {
629360784Sdim          Sym.SymbolTableIndex = SymbolTableIndex;
630360784Sdim          // 1 main and 1 auxiliary symbol table entry for each contained
631360784Sdim          // symbol.
632360784Sdim          SymbolTableIndex += 2;
633360784Sdim        }
634360784Sdim      }
635360784Sdim
636360784Sdim      if (!SectionAddressSet) {
637360784Sdim        Section->Address = Group->front().Address;
638360784Sdim        SectionAddressSet = true;
639360784Sdim      }
640360784Sdim    }
641360784Sdim
642360784Sdim    // Make sure the address of the next section aligned to
643360784Sdim    // DefaultSectionAlign.
644360784Sdim    Address = alignTo(Address, DefaultSectionAlign);
645360784Sdim    Section->Size = Address - Section->Address;
646360784Sdim  }
647360784Sdim
648360784Sdim  SymbolTableEntryCount = SymbolTableIndex;
649360784Sdim
650360784Sdim  // Calculate the RawPointer value for each section.
651360784Sdim  uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
652360784Sdim                        SectionCount * sizeof(XCOFF::SectionHeader32);
653360784Sdim  for (auto *Sec : Sections) {
654360784Sdim    if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual)
655360784Sdim      continue;
656360784Sdim
657360784Sdim    Sec->FileOffsetToData = RawPointer;
658360784Sdim    RawPointer += Sec->Size;
659360784Sdim  }
660360784Sdim
661360784Sdim  // TODO Add in Relocation storage to the RawPointer Calculation.
662360784Sdim  // TODO What to align the SymbolTable to?
663360784Sdim  // TODO Error check that the number of symbol table entries fits in 32-bits
664360784Sdim  // signed ...
665360784Sdim  if (SymbolTableEntryCount)
666360784Sdim    SymbolTableOffset = RawPointer;
667360784Sdim}
668360784Sdim
669360784Sdim// Takes the log base 2 of the alignment and shifts the result into the 5 most
670360784Sdim// significant bits of a byte, then or's in the csect type into the least
671360784Sdim// significant 3 bits.
672360784Sdimuint8_t getEncodedType(const MCSectionXCOFF *Sec) {
673360784Sdim  unsigned Align = Sec->getAlignment();
674360784Sdim  assert(isPowerOf2_32(Align) && "Alignment must be a power of 2.");
675360784Sdim  unsigned Log2Align = Log2_32(Align);
676360784Sdim  // Result is a number in the range [0, 31] which fits in the 5 least
677360784Sdim  // significant bits. Shift this value into the 5 most significant bits, and
678360784Sdim  // bitwise-or in the csect type.
679360784Sdim  uint8_t EncodedAlign = Log2Align << 3;
680360784Sdim  return EncodedAlign | Sec->getCSectType();
681360784Sdim}
682360784Sdim
683351278Sdim} // end anonymous namespace
684351278Sdim
685351278Sdimstd::unique_ptr<MCObjectWriter>
686351278Sdimllvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
687351278Sdim                              raw_pwrite_stream &OS) {
688360784Sdim  return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
689351278Sdim}
690