|  | //===-- lib/MC/XCOFFObjectWriter.cpp - XCOFF file writer ------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file implements XCOFF object file writer information. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/BinaryFormat/XCOFF.h" | 
|  | #include "llvm/MC/MCAsmLayout.h" | 
|  | #include "llvm/MC/MCAssembler.h" | 
|  | #include "llvm/MC/MCObjectWriter.h" | 
|  | #include "llvm/MC/MCSectionXCOFF.h" | 
|  | #include "llvm/MC/MCSymbolXCOFF.h" | 
|  | #include "llvm/MC/MCValue.h" | 
|  | #include "llvm/MC/MCXCOFFObjectWriter.h" | 
|  | #include "llvm/MC/StringTableBuilder.h" | 
|  | #include "llvm/Support/Error.h" | 
|  | #include "llvm/Support/MathExtras.h" | 
|  |  | 
|  | #include <deque> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | // An XCOFF object file has a limited set of predefined sections. The most | 
|  | // important ones for us (right now) are: | 
|  | // .text --> contains program code and read-only data. | 
|  | // .data --> contains initialized data, function descriptors, and the TOC. | 
|  | // .bss  --> contains uninitialized data. | 
|  | // Each of these sections is composed of 'Control Sections'. A Control Section | 
|  | // is more commonly referred to as a csect. A csect is an indivisible unit of | 
|  | // code or data, and acts as a container for symbols. A csect is mapped | 
|  | // into a section based on its storage-mapping class, with the exception of | 
|  | // XMC_RW which gets mapped to either .data or .bss based on whether it's | 
|  | // explicitly initialized or not. | 
|  | // | 
|  | // We don't represent the sections in the MC layer as there is nothing | 
|  | // interesting about them at at that level: they carry information that is | 
|  | // only relevant to the ObjectWriter, so we materialize them in this class. | 
|  | namespace { | 
|  |  | 
|  | constexpr unsigned DefaultSectionAlign = 4; | 
|  |  | 
|  | // Packs the csect's alignment and type into a byte. | 
|  | uint8_t getEncodedType(const MCSectionXCOFF *); | 
|  |  | 
|  | // Wrapper around an MCSymbolXCOFF. | 
|  | struct Symbol { | 
|  | const MCSymbolXCOFF *const MCSym; | 
|  | uint32_t SymbolTableIndex; | 
|  |  | 
|  | XCOFF::StorageClass getStorageClass() const { | 
|  | return MCSym->getStorageClass(); | 
|  | } | 
|  | StringRef getName() const { return MCSym->getName(); } | 
|  | Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {} | 
|  | }; | 
|  |  | 
|  | // Wrapper for an MCSectionXCOFF. | 
|  | struct ControlSection { | 
|  | const MCSectionXCOFF *const MCCsect; | 
|  | uint32_t SymbolTableIndex; | 
|  | uint32_t Address; | 
|  | uint32_t Size; | 
|  |  | 
|  | SmallVector<Symbol, 1> Syms; | 
|  | StringRef getName() const { return MCCsect->getSectionName(); } | 
|  | ControlSection(const MCSectionXCOFF *MCSec) | 
|  | : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} | 
|  | }; | 
|  |  | 
|  | // Represents the data related to a section excluding the csects that make up | 
|  | // the raw data of the section. The csects are stored separately as not all | 
|  | // sections contain csects, and some sections contain csects which are better | 
|  | // stored separately, e.g. the .data section containing read-write, descriptor, | 
|  | // TOCBase and TOC-entry csects. | 
|  | struct Section { | 
|  | char Name[XCOFF::NameSize]; | 
|  | // The physical/virtual address of the section. For an object file | 
|  | // these values are equivalent. | 
|  | uint32_t Address; | 
|  | uint32_t Size; | 
|  | uint32_t FileOffsetToData; | 
|  | uint32_t FileOffsetToRelocations; | 
|  | uint32_t RelocationCount; | 
|  | int32_t Flags; | 
|  |  | 
|  | int16_t Index; | 
|  |  | 
|  | // Virtual sections do not need storage allocated in the object file. | 
|  | const bool IsVirtual; | 
|  |  | 
|  | void reset() { | 
|  | Address = 0; | 
|  | Size = 0; | 
|  | FileOffsetToData = 0; | 
|  | FileOffsetToRelocations = 0; | 
|  | RelocationCount = 0; | 
|  | Index = -1; | 
|  | } | 
|  |  | 
|  | Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual) | 
|  | : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0), | 
|  | RelocationCount(0), Flags(Flags), Index(-1), IsVirtual(IsVirtual) { | 
|  | strncpy(Name, N, XCOFF::NameSize); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class XCOFFObjectWriter : public MCObjectWriter { | 
|  | // Type to be used for a container representing a set of csects with | 
|  | // (approximately) the same storage mapping class. For example all the csects | 
|  | // with a storage mapping class of `xmc_pr` will get placed into the same | 
|  | // container. | 
|  | using CsectGroup = std::deque<ControlSection>; | 
|  |  | 
|  | support::endian::Writer W; | 
|  | std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter; | 
|  | StringTableBuilder Strings; | 
|  |  | 
|  | // The non-empty sections, in the order they will appear in the section header | 
|  | // table. | 
|  | std::vector<Section *> Sections; | 
|  |  | 
|  | // The Predefined sections. | 
|  | Section Text; | 
|  | Section BSS; | 
|  |  | 
|  | // CsectGroups. These store the csects which make up different parts of | 
|  | // the sections. Should have one for each set of csects that get mapped into | 
|  | // the same section and get handled in a 'similar' way. | 
|  | CsectGroup ProgramCodeCsects; | 
|  | CsectGroup BSSCsects; | 
|  |  | 
|  | uint32_t SymbolTableEntryCount = 0; | 
|  | uint32_t SymbolTableOffset = 0; | 
|  |  | 
|  | virtual void reset() override; | 
|  |  | 
|  | void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override; | 
|  |  | 
|  | void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *, | 
|  | const MCFixup &, MCValue, uint64_t &) override; | 
|  |  | 
|  | uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; | 
|  |  | 
|  | static bool nameShouldBeInStringTable(const StringRef &); | 
|  | void writeSymbolName(const StringRef &); | 
|  | void writeSymbolTableEntryForCsectMemberLabel(const Symbol &, | 
|  | const ControlSection &, int16_t, | 
|  | uint64_t); | 
|  | void writeSymbolTableEntryForControlSection(const ControlSection &, int16_t, | 
|  | XCOFF::StorageClass); | 
|  | void writeFileHeader(); | 
|  | void writeSectionHeaderTable(); | 
|  | void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout); | 
|  | void writeSymbolTable(const MCAsmLayout &Layout); | 
|  |  | 
|  | // Called after all the csects and symbols have been processed by | 
|  | // `executePostLayoutBinding`, this function handles building up the majority | 
|  | // of the structures in the object file representation. Namely: | 
|  | // *) Calculates physical/virtual addresses, raw-pointer offsets, and section | 
|  | //    sizes. | 
|  | // *) Assigns symbol table indices. | 
|  | // *) Builds up the section header table by adding any non-empty sections to | 
|  | //    `Sections`. | 
|  | void assignAddressesAndIndices(const MCAsmLayout &); | 
|  |  | 
|  | bool | 
|  | needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */ | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Returns the size of the auxiliary header to be written to the object file. | 
|  | size_t auxiliaryHeaderSize() const { | 
|  | assert(!needsAuxiliaryHeader() && | 
|  | "Auxiliary header support not implemented."); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | public: | 
|  | XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, | 
|  | raw_pwrite_stream &OS); | 
|  | }; | 
|  |  | 
|  | XCOFFObjectWriter::XCOFFObjectWriter( | 
|  | std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) | 
|  | : W(OS, support::big), TargetObjectWriter(std::move(MOTW)), | 
|  | Strings(StringTableBuilder::XCOFF), | 
|  | Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false), | 
|  | BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true) {} | 
|  |  | 
|  | void XCOFFObjectWriter::reset() { | 
|  | // Reset any sections we have written to, and empty the section header table. | 
|  | for (auto *Sec : Sections) | 
|  | Sec->reset(); | 
|  | Sections.clear(); | 
|  |  | 
|  | // Clear any csects we have stored. | 
|  | ProgramCodeCsects.clear(); | 
|  | BSSCsects.clear(); | 
|  |  | 
|  | // Reset the symbol table and string table. | 
|  | SymbolTableEntryCount = 0; | 
|  | SymbolTableOffset = 0; | 
|  | Strings.clear(); | 
|  |  | 
|  | MCObjectWriter::reset(); | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, | 
|  | const MCAsmLayout &Layout) { | 
|  | if (TargetObjectWriter->is64Bit()) | 
|  | report_fatal_error("64-bit XCOFF object files are not supported yet."); | 
|  |  | 
|  | // Maps the MC Section representation to its corresponding ControlSection | 
|  | // wrapper. Needed for finding the ControlSection to insert an MCSymbol into | 
|  | // from its containing MCSectionXCOFF. | 
|  | DenseMap<const MCSectionXCOFF *, ControlSection *> WrapperMap; | 
|  |  | 
|  | for (const auto &S : Asm) { | 
|  | const auto *MCSec = cast<const MCSectionXCOFF>(&S); | 
|  | assert(WrapperMap.find(MCSec) == WrapperMap.end() && | 
|  | "Cannot add a csect twice."); | 
|  |  | 
|  | // If the name does not fit in the storage provided in the symbol table | 
|  | // entry, add it to the string table. | 
|  | if (nameShouldBeInStringTable(MCSec->getSectionName())) | 
|  | Strings.add(MCSec->getSectionName()); | 
|  |  | 
|  | switch (MCSec->getMappingClass()) { | 
|  | case XCOFF::XMC_PR: | 
|  | assert(XCOFF::XTY_SD == MCSec->getCSectType() && | 
|  | "Only an initialized csect can contain program code."); | 
|  | ProgramCodeCsects.emplace_back(MCSec); | 
|  | WrapperMap[MCSec] = &ProgramCodeCsects.back(); | 
|  | break; | 
|  | case XCOFF::XMC_RW: | 
|  | if (XCOFF::XTY_CM == MCSec->getCSectType()) { | 
|  | BSSCsects.emplace_back(MCSec); | 
|  | WrapperMap[MCSec] = &BSSCsects.back(); | 
|  | break; | 
|  | } | 
|  | report_fatal_error("Unhandled mapping of read-write csect to section."); | 
|  | case XCOFF::XMC_TC0: | 
|  | // TODO FIXME Handle emiting the TOC base. | 
|  | break; | 
|  | case XCOFF::XMC_BS: | 
|  | assert(XCOFF::XTY_CM == MCSec->getCSectType() && | 
|  | "Mapping invalid csect. CSECT with bss storage class must be " | 
|  | "common type."); | 
|  | BSSCsects.emplace_back(MCSec); | 
|  | WrapperMap[MCSec] = &BSSCsects.back(); | 
|  | break; | 
|  | default: | 
|  | report_fatal_error("Unhandled mapping of csect to section."); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (const MCSymbol &S : Asm.symbols()) { | 
|  | // Nothing to do for temporary symbols. | 
|  | if (S.isTemporary()) | 
|  | continue; | 
|  | const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S); | 
|  |  | 
|  | // Map the symbol into its containing csect. | 
|  | const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect(); | 
|  | assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() && | 
|  | "Expected containing csect to exist in map"); | 
|  |  | 
|  | // Lookup the containing csect and add the symbol to it. | 
|  | WrapperMap[ContainingCsect]->Syms.emplace_back(XSym); | 
|  |  | 
|  | // If the name does not fit in the storage provided in the symbol table | 
|  | // entry, add it to the string table. | 
|  | if (nameShouldBeInStringTable(XSym->getName())) | 
|  | Strings.add(XSym->getName()); | 
|  | } | 
|  |  | 
|  | Strings.finalize(); | 
|  | assignAddressesAndIndices(Layout); | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, | 
|  | const MCFragment *, const MCFixup &, | 
|  | MCValue, uint64_t &) { | 
|  | report_fatal_error("XCOFF relocations not supported."); | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, | 
|  | const MCAsmLayout &Layout) { | 
|  | // Write the program code control sections one at a time. | 
|  | uint32_t CurrentAddressLocation = Text.Address; | 
|  | for (const auto &Csect : ProgramCodeCsects) { | 
|  | if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) | 
|  | W.OS.write_zeros(PaddingSize); | 
|  | Asm.writeSectionData(W.OS, Csect.MCCsect, Layout); | 
|  | CurrentAddressLocation = Csect.Address + Csect.Size; | 
|  | } | 
|  |  | 
|  | if (Text.Index != -1) { | 
|  | // The size of the tail padding in a section is the end virtual address of | 
|  | // the current section minus the the end virtual address of the last csect | 
|  | // in that section. | 
|  | if (uint32_t PaddingSize = | 
|  | Text.Address + Text.Size - CurrentAddressLocation) | 
|  | W.OS.write_zeros(PaddingSize); | 
|  | } | 
|  | } | 
|  |  | 
|  | uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, | 
|  | const MCAsmLayout &Layout) { | 
|  | // We always emit a timestamp of 0 for reproducibility, so ensure incremental | 
|  | // linking is not enabled, in case, like with Windows COFF, such a timestamp | 
|  | // is incompatible with incremental linking of XCOFF. | 
|  | if (Asm.isIncrementalLinkerCompatible()) | 
|  | report_fatal_error("Incremental linking not supported for XCOFF."); | 
|  |  | 
|  | if (TargetObjectWriter->is64Bit()) | 
|  | report_fatal_error("64-bit XCOFF object files are not supported yet."); | 
|  |  | 
|  | uint64_t StartOffset = W.OS.tell(); | 
|  |  | 
|  | writeFileHeader(); | 
|  | writeSectionHeaderTable(); | 
|  | writeSections(Asm, Layout); | 
|  | // TODO writeRelocations(); | 
|  |  | 
|  | writeSymbolTable(Layout); | 
|  | // Write the string table. | 
|  | Strings.write(W.OS); | 
|  |  | 
|  | return W.OS.tell() - StartOffset; | 
|  | } | 
|  |  | 
|  | bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) { | 
|  | return SymbolName.size() > XCOFF::NameSize; | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) { | 
|  | if (nameShouldBeInStringTable(SymbolName)) { | 
|  | W.write<int32_t>(0); | 
|  | W.write<uint32_t>(Strings.getOffset(SymbolName)); | 
|  | } else { | 
|  | char Name[XCOFF::NameSize]; | 
|  | std::strncpy(Name, SymbolName.data(), XCOFF::NameSize); | 
|  | ArrayRef<char> NameRef(Name, XCOFF::NameSize); | 
|  | W.write(NameRef); | 
|  | } | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel( | 
|  | const Symbol &SymbolRef, const ControlSection &CSectionRef, | 
|  | int16_t SectionIndex, uint64_t SymbolOffset) { | 
|  | // Name or Zeros and string table offset | 
|  | writeSymbolName(SymbolRef.getName()); | 
|  | assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address && | 
|  | "Symbol address overflows."); | 
|  | W.write<uint32_t>(CSectionRef.Address + SymbolOffset); | 
|  | W.write<int16_t>(SectionIndex); | 
|  | // Basic/Derived type. See the description of the n_type field for symbol | 
|  | // table entries for a detailed description. Since we don't yet support | 
|  | // visibility, and all other bits are either optionally set or reserved, this | 
|  | // is always zero. | 
|  | // TODO FIXME How to assert a symbol's visibilty is default? | 
|  | // TODO Set the function indicator (bit 10, 0x0020) for functions | 
|  | // when debugging is enabled. | 
|  | W.write<uint16_t>(0); | 
|  | W.write<uint8_t>(SymbolRef.getStorageClass()); | 
|  | // Always 1 aux entry for now. | 
|  | W.write<uint8_t>(1); | 
|  |  | 
|  | // Now output the auxiliary entry. | 
|  | W.write<uint32_t>(CSectionRef.SymbolTableIndex); | 
|  | // Parameter typecheck hash. Not supported. | 
|  | W.write<uint32_t>(0); | 
|  | // Typecheck section number. Not supported. | 
|  | W.write<uint16_t>(0); | 
|  | // Symbol type: Label | 
|  | W.write<uint8_t>(XCOFF::XTY_LD); | 
|  | // Storage mapping class. | 
|  | W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass()); | 
|  | // Reserved (x_stab). | 
|  | W.write<uint32_t>(0); | 
|  | // Reserved (x_snstab). | 
|  | W.write<uint16_t>(0); | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::writeSymbolTableEntryForControlSection( | 
|  | const ControlSection &CSectionRef, int16_t SectionIndex, | 
|  | XCOFF::StorageClass StorageClass) { | 
|  | // n_name, n_zeros, n_offset | 
|  | writeSymbolName(CSectionRef.getName()); | 
|  | // n_value | 
|  | W.write<uint32_t>(CSectionRef.Address); | 
|  | // n_scnum | 
|  | W.write<int16_t>(SectionIndex); | 
|  | // Basic/Derived type. See the description of the n_type field for symbol | 
|  | // table entries for a detailed description. Since we don't yet support | 
|  | // visibility, and all other bits are either optionally set or reserved, this | 
|  | // is always zero. | 
|  | // TODO FIXME How to assert a symbol's visibilty is default? | 
|  | // TODO Set the function indicator (bit 10, 0x0020) for functions | 
|  | // when debugging is enabled. | 
|  | W.write<uint16_t>(0); | 
|  | // n_sclass | 
|  | W.write<uint8_t>(StorageClass); | 
|  | // Always 1 aux entry for now. | 
|  | W.write<uint8_t>(1); | 
|  |  | 
|  | // Now output the auxiliary entry. | 
|  | W.write<uint32_t>(CSectionRef.Size); | 
|  | // Parameter typecheck hash. Not supported. | 
|  | W.write<uint32_t>(0); | 
|  | // Typecheck section number. Not supported. | 
|  | W.write<uint16_t>(0); | 
|  | // Symbol type. | 
|  | W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect)); | 
|  | // Storage mapping class. | 
|  | W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass()); | 
|  | // Reserved (x_stab). | 
|  | W.write<uint32_t>(0); | 
|  | // Reserved (x_snstab). | 
|  | W.write<uint16_t>(0); | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::writeFileHeader() { | 
|  | // Magic. | 
|  | W.write<uint16_t>(0x01df); | 
|  | // Number of sections. | 
|  | W.write<uint16_t>(Sections.size()); | 
|  | // Timestamp field. For reproducible output we write a 0, which represents no | 
|  | // timestamp. | 
|  | W.write<int32_t>(0); | 
|  | // Byte Offset to the start of the symbol table. | 
|  | W.write<uint32_t>(SymbolTableOffset); | 
|  | // Number of entries in the symbol table. | 
|  | W.write<int32_t>(SymbolTableEntryCount); | 
|  | // Size of the optional header. | 
|  | W.write<uint16_t>(0); | 
|  | // Flags. | 
|  | W.write<uint16_t>(0); | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::writeSectionHeaderTable() { | 
|  | for (const auto *Sec : Sections) { | 
|  | // Write Name. | 
|  | ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize); | 
|  | W.write(NameRef); | 
|  |  | 
|  | // Write the Physical Address and Virtual Address. In an object file these | 
|  | // are the same. | 
|  | W.write<uint32_t>(Sec->Address); | 
|  | W.write<uint32_t>(Sec->Address); | 
|  |  | 
|  | W.write<uint32_t>(Sec->Size); | 
|  | W.write<uint32_t>(Sec->FileOffsetToData); | 
|  |  | 
|  | // Relocation pointer and Lineno pointer. Not supported yet. | 
|  | W.write<uint32_t>(0); | 
|  | W.write<uint32_t>(0); | 
|  |  | 
|  | // Relocation and line-number counts. Not supported yet. | 
|  | W.write<uint16_t>(0); | 
|  | W.write<uint16_t>(0); | 
|  |  | 
|  | W.write<int32_t>(Sec->Flags); | 
|  | } | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { | 
|  | // Print out symbol table for the program code. | 
|  | for (const auto &Csect : ProgramCodeCsects) { | 
|  | // Write out the control section first and then each symbol in it. | 
|  | writeSymbolTableEntryForControlSection(Csect, Text.Index, | 
|  | Csect.MCCsect->getStorageClass()); | 
|  | for (const auto &Sym : Csect.Syms) | 
|  | writeSymbolTableEntryForCsectMemberLabel( | 
|  | Sym, Csect, Text.Index, Layout.getSymbolOffset(*Sym.MCSym)); | 
|  | } | 
|  |  | 
|  | // The BSS Section is special in that the csects must contain a single symbol, | 
|  | // and the contained symbol cannot be represented in the symbol table as a | 
|  | // label definition. | 
|  | for (auto &Csect : BSSCsects) { | 
|  | assert(Csect.Syms.size() == 1 && | 
|  | "Uninitialized csect cannot contain more then 1 symbol."); | 
|  | Symbol &Sym = Csect.Syms.back(); | 
|  | writeSymbolTableEntryForControlSection(Csect, BSS.Index, | 
|  | Sym.getStorageClass()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { | 
|  | // The address corrresponds to the address of sections and symbols in the | 
|  | // object file. We place the shared address 0 immediately after the | 
|  | // section header table. | 
|  | uint32_t Address = 0; | 
|  | // Section indices are 1-based in XCOFF. | 
|  | int16_t SectionIndex = 1; | 
|  | // The first symbol table entry is for the file name. We are not emitting it | 
|  | // yet, so start at index 0. | 
|  | uint32_t SymbolTableIndex = 0; | 
|  |  | 
|  | // Text section comes first. | 
|  | if (!ProgramCodeCsects.empty()) { | 
|  | Sections.push_back(&Text); | 
|  | Text.Index = SectionIndex++; | 
|  | for (auto &Csect : ProgramCodeCsects) { | 
|  | const MCSectionXCOFF *MCSec = Csect.MCCsect; | 
|  | Csect.Address = alignTo(Address, MCSec->getAlignment()); | 
|  | Csect.Size = Layout.getSectionAddressSize(MCSec); | 
|  | Address = Csect.Address + Csect.Size; | 
|  | Csect.SymbolTableIndex = SymbolTableIndex; | 
|  | // 1 main and 1 auxiliary symbol table entry for the csect. | 
|  | SymbolTableIndex += 2; | 
|  | for (auto &Sym : Csect.Syms) { | 
|  | Sym.SymbolTableIndex = SymbolTableIndex; | 
|  | // 1 main and 1 auxiliary symbol table entry for each contained symbol | 
|  | SymbolTableIndex += 2; | 
|  | } | 
|  | } | 
|  | Address = alignTo(Address, DefaultSectionAlign); | 
|  |  | 
|  | // The first csect of a section can be aligned by adjusting the virtual | 
|  | // address of its containing section instead of writing zeroes into the | 
|  | // object file. | 
|  | Text.Address = ProgramCodeCsects.front().Address; | 
|  |  | 
|  | Text.Size = Address - Text.Address; | 
|  | } | 
|  |  | 
|  | // Data section Second. TODO | 
|  |  | 
|  | // BSS Section third. | 
|  | if (!BSSCsects.empty()) { | 
|  | Sections.push_back(&BSS); | 
|  | BSS.Index = SectionIndex++; | 
|  | for (auto &Csect : BSSCsects) { | 
|  | const MCSectionXCOFF *MCSec = Csect.MCCsect; | 
|  | Csect.Address = alignTo(Address, MCSec->getAlignment()); | 
|  | Csect.Size = Layout.getSectionAddressSize(MCSec); | 
|  | Address = Csect.Address + Csect.Size; | 
|  | Csect.SymbolTableIndex = SymbolTableIndex; | 
|  | // 1 main and 1 auxiliary symbol table entry for the csect. | 
|  | SymbolTableIndex += 2; | 
|  |  | 
|  | assert(Csect.Syms.size() == 1 && | 
|  | "csect in the BSS can only contain a single symbol."); | 
|  | Csect.Syms[0].SymbolTableIndex = Csect.SymbolTableIndex; | 
|  | } | 
|  | // Pad out Address to the default alignment. This is to match how the system | 
|  | // assembler handles the .bss section. Its size is always a multiple of 4. | 
|  | Address = alignTo(Address, DefaultSectionAlign); | 
|  |  | 
|  | BSS.Address = BSSCsects.front().Address; | 
|  | BSS.Size = Address - BSS.Address; | 
|  | } | 
|  |  | 
|  | SymbolTableEntryCount = SymbolTableIndex; | 
|  |  | 
|  | // Calculate the RawPointer value for each section. | 
|  | uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() + | 
|  | Sections.size() * sizeof(XCOFF::SectionHeader32); | 
|  | for (auto *Sec : Sections) { | 
|  | if (!Sec->IsVirtual) { | 
|  | Sec->FileOffsetToData = RawPointer; | 
|  | RawPointer += Sec->Size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // TODO Add in Relocation storage to the RawPointer Calculation. | 
|  | // TODO What to align the SymbolTable to? | 
|  | // TODO Error check that the number of symbol table entries fits in 32-bits | 
|  | // signed ... | 
|  | if (SymbolTableEntryCount) | 
|  | SymbolTableOffset = RawPointer; | 
|  | } | 
|  |  | 
|  | // Takes the log base 2 of the alignment and shifts the result into the 5 most | 
|  | // significant bits of a byte, then or's in the csect type into the least | 
|  | // significant 3 bits. | 
|  | uint8_t getEncodedType(const MCSectionXCOFF *Sec) { | 
|  | unsigned Align = Sec->getAlignment(); | 
|  | assert(isPowerOf2_32(Align) && "Alignment must be a power of 2."); | 
|  | unsigned Log2Align = Log2_32(Align); | 
|  | // Result is a number in the range [0, 31] which fits in the 5 least | 
|  | // significant bits. Shift this value into the 5 most significant bits, and | 
|  | // bitwise-or in the csect type. | 
|  | uint8_t EncodedAlign = Log2Align << 3; | 
|  | return EncodedAlign | Sec->getCSectType(); | 
|  | } | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | std::unique_ptr<MCObjectWriter> | 
|  | llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, | 
|  | raw_pwrite_stream &OS) { | 
|  | return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS); | 
|  | } |