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