XCOFFObjectWriter.cpp 32 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
//===-- 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/MCAsmBackend.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCFixupKindInfo.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/EndianStream.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;
constexpr int16_t MaxSectionIndex = INT16_MAX;

// Packs the csect's alignment and type into a byte.
uint8_t getEncodedType(const MCSectionXCOFF *);

struct XCOFFRelocation {
  uint32_t SymbolTableIndex;
  uint32_t FixupOffsetInCsect;
  uint8_t SignAndSize;
  uint8_t Type;
};

// Wrapper around an MCSymbolXCOFF.
struct Symbol {
  const MCSymbolXCOFF *const MCSym;
  uint32_t SymbolTableIndex;

  XCOFF::StorageClass getStorageClass() const {
    return MCSym->getStorageClass();
  }
  StringRef getSymbolTableName() const { return MCSym->getSymbolTableName(); }
  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;
  SmallVector<XCOFFRelocation, 1> Relocations;
  StringRef getSymbolTableName() const { return MCCsect->getSymbolTableName(); }
  ControlSection(const MCSectionXCOFF *MCSec)
      : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {}
};

// 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>;
using CsectGroups = std::deque<CsectGroup *>;

// 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;

  // XCOFF has special section numbers for symbols:
  // -2 Specifies N_DEBUG, a special symbolic debugging symbol.
  // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not
  // relocatable.
  //  0 Specifies N_UNDEF, an undefined external symbol.
  // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that
  // hasn't been initialized.
  static constexpr int16_t UninitializedIndex =
      XCOFF::ReservedSectionNum::N_DEBUG - 1;

  CsectGroups Groups;

  void reset() {
    Address = 0;
    Size = 0;
    FileOffsetToData = 0;
    FileOffsetToRelocations = 0;
    RelocationCount = 0;
    Index = UninitializedIndex;
    // Clear any csects we have stored.
    for (auto *Group : Groups)
      Group->clear();
  }

  Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual,
          CsectGroups Groups)
      : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0),
        RelocationCount(0), Flags(Flags), Index(UninitializedIndex),
        IsVirtual(IsVirtual), Groups(Groups) {
    strncpy(Name, N, XCOFF::NameSize);
  }
};

class XCOFFObjectWriter : public MCObjectWriter {

  uint32_t SymbolTableEntryCount = 0;
  uint32_t SymbolTableOffset = 0;
  uint16_t SectionCount = 0;
  uint32_t RelocationEntryOffset = 0;

  support::endian::Writer W;
  std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
  StringTableBuilder Strings;

  // Maps the MCSection representation to its corresponding ControlSection
  // wrapper. Needed for finding the ControlSection to insert an MCSymbol into
  // from its containing MCSectionXCOFF.
  DenseMap<const MCSectionXCOFF *, ControlSection *> SectionMap;

  // Maps the MCSymbol representation to its corrresponding symbol table index.
  // Needed for relocation.
  DenseMap<const MCSymbol *, uint32_t> SymbolIndexMap;

  // 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 UndefinedCsects;
  CsectGroup ProgramCodeCsects;
  CsectGroup ReadOnlyCsects;
  CsectGroup DataCsects;
  CsectGroup FuncDSCsects;
  CsectGroup TOCCsects;
  CsectGroup BSSCsects;

  // The Predefined sections.
  Section Text;
  Section Data;
  Section BSS;

  // All the XCOFF sections, in the order they will appear in the section header
  // table.
  std::array<Section *const, 3> Sections{{&Text, &Data, &BSS}};

  CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec);

  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);
  void writeRelocations();
  void writeRelocation(XCOFFRelocation Reloc, const ControlSection &CSection);

  // 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 &);
  void finalizeSectionInfo();

  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,
           CsectGroups{&ProgramCodeCsects, &ReadOnlyCsects}),
      Data(".data", XCOFF::STYP_DATA, /* IsVirtual */ false,
           CsectGroups{&DataCsects, &FuncDSCsects, &TOCCsects}),
      BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true,
          CsectGroups{&BSSCsects}) {}

void XCOFFObjectWriter::reset() {
  // Clear the mappings we created.
  SymbolIndexMap.clear();
  SectionMap.clear();

  UndefinedCsects.clear();
  // Reset any sections we have written to, and empty the section header table.
  for (auto *Sec : Sections)
    Sec->reset();

  // Reset states in XCOFFObjectWriter.
  SymbolTableEntryCount = 0;
  SymbolTableOffset = 0;
  SectionCount = 0;
  RelocationEntryOffset = 0;
  Strings.clear();

  MCObjectWriter::reset();
}

CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) {
  switch (MCSec->getMappingClass()) {
  case XCOFF::XMC_PR:
    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
           "Only an initialized csect can contain program code.");
    return ProgramCodeCsects;
  case XCOFF::XMC_RO:
    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
           "Only an initialized csect can contain read only data.");
    return ReadOnlyCsects;
  case XCOFF::XMC_RW:
    if (XCOFF::XTY_CM == MCSec->getCSectType())
      return BSSCsects;

    if (XCOFF::XTY_SD == MCSec->getCSectType())
      return DataCsects;

    report_fatal_error("Unhandled mapping of read-write csect to section.");
  case XCOFF::XMC_DS:
    return FuncDSCsects;
  case XCOFF::XMC_BS:
    assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
           "Mapping invalid csect. CSECT with bss storage class must be "
           "common type.");
    return BSSCsects;
  case XCOFF::XMC_TC0:
    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
           "Only an initialized csect can contain TOC-base.");
    assert(TOCCsects.empty() &&
           "We should have only one TOC-base, and it should be the first csect "
           "in this CsectGroup.");
    return TOCCsects;
  case XCOFF::XMC_TC:
  case XCOFF::XMC_TE:
    assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
           "Only an initialized csect can contain TC entry.");
    assert(!TOCCsects.empty() &&
           "We should at least have a TOC-base in this CsectGroup.");
    return TOCCsects;
  default:
    report_fatal_error("Unhandled mapping of csect to section.");
  }
}

static MCSectionXCOFF *getContainingCsect(const MCSymbolXCOFF *XSym) {
  if (XSym->isDefined())
    return cast<MCSectionXCOFF>(XSym->getFragment()->getParent());
  return XSym->getRepresentedCsect();
}

void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
                                                 const MCAsmLayout &Layout) {
  if (TargetObjectWriter->is64Bit())
    report_fatal_error("64-bit XCOFF object files are not supported yet.");

  for (const auto &S : Asm) {
    const auto *MCSec = cast<const MCSectionXCOFF>(&S);
    assert(SectionMap.find(MCSec) == SectionMap.end() &&
           "Cannot add a csect twice.");
    assert(XCOFF::XTY_ER != MCSec->getCSectType() &&
           "An undefined csect should not get registered.");

    // If the name does not fit in the storage provided in the symbol table
    // entry, add it to the string table.
    if (nameShouldBeInStringTable(MCSec->getSymbolTableName()))
      Strings.add(MCSec->getSymbolTableName());

    CsectGroup &Group = getCsectGroup(MCSec);
    Group.emplace_back(MCSec);
    SectionMap[MCSec] = &Group.back();
  }

  for (const MCSymbol &S : Asm.symbols()) {
    // Nothing to do for temporary symbols.
    if (S.isTemporary())
      continue;

    const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S);
    const MCSectionXCOFF *ContainingCsect = getContainingCsect(XSym);

    if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) {
      // Handle undefined symbol.
      UndefinedCsects.emplace_back(ContainingCsect);
      SectionMap[ContainingCsect] = &UndefinedCsects.back();
      if (nameShouldBeInStringTable(ContainingCsect->getSymbolTableName()))
        Strings.add(ContainingCsect->getSymbolTableName());
      continue;
    }

    // If the symbol is the csect itself, we don't need to put the symbol
    // into csect's Syms.
    if (XSym == ContainingCsect->getQualNameSymbol())
      continue;

    // Only put a label into the symbol table when it is an external label.
    if (!XSym->isExternal())
      continue;

    assert(SectionMap.find(ContainingCsect) != SectionMap.end() &&
           "Expected containing csect to exist in map");
    // Lookup the containing csect and add the symbol to it.
    SectionMap[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->getSymbolTableName()))
      Strings.add(XSym->getSymbolTableName());
  }

  Strings.finalize();
  assignAddressesAndIndices(Layout);
}

void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
                                         const MCAsmLayout &Layout,
                                         const MCFragment *Fragment,
                                         const MCFixup &Fixup, MCValue Target,
                                         uint64_t &FixedValue) {
  auto getIndex = [this](const MCSymbol *Sym,
                         const MCSectionXCOFF *ContainingCsect) {
    // If we could not find the symbol directly in SymbolIndexMap, this symbol
    // could either be a temporary symbol or an undefined symbol. In this case,
    // we would need to have the relocation reference its csect instead.
    return SymbolIndexMap.find(Sym) != SymbolIndexMap.end()
               ? SymbolIndexMap[Sym]
               : SymbolIndexMap[ContainingCsect->getQualNameSymbol()];
  };

  auto getVirtualAddress = [this,
                            &Layout](const MCSymbol *Sym,
                                     const MCSectionXCOFF *ContainingCsect) {
    // If Sym is a csect, return csect's address.
    // If Sym is a label, return csect's address + label's offset from the csect.
    return SectionMap[ContainingCsect]->Address +
           (Sym->isDefined() ? Layout.getSymbolOffset(*Sym) : 0);
  };

  const MCSymbol *const SymA = &Target.getSymA()->getSymbol();

  MCAsmBackend &Backend = Asm.getBackend();
  bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
                 MCFixupKindInfo::FKF_IsPCRel;

  uint8_t Type;
  uint8_t SignAndSize;
  std::tie(Type, SignAndSize) =
      TargetObjectWriter->getRelocTypeAndSignSize(Target, Fixup, IsPCRel);

  const MCSectionXCOFF *SymASec = getContainingCsect(cast<MCSymbolXCOFF>(SymA));
  assert(SectionMap.find(SymASec) != SectionMap.end() &&
         "Expected containing csect to exist in map.");

  const uint32_t Index = getIndex(SymA, SymASec);
  if (Type == XCOFF::RelocationType::R_POS)
    // The FixedValue should be symbol's virtual address in this object file
    // plus any constant value that we might get.
    FixedValue = getVirtualAddress(SymA, SymASec) + Target.getConstant();
  else if (Type == XCOFF::RelocationType::R_TOC ||
           Type == XCOFF::RelocationType::R_TOCL) {
    // The FixedValue should be the TOC entry offset from the TOC-base plus any
    // constant offset value.
    const int64_t TOCEntryOffset = SectionMap[SymASec]->Address -
                                   TOCCsects.front().Address +
                                   Target.getConstant();
    if (Type == XCOFF::RelocationType::R_TOC && !isInt<16>(TOCEntryOffset))
      report_fatal_error("TOCEntryOffset overflows in small code model mode");

    FixedValue = TOCEntryOffset;
  }

  assert(
      (TargetObjectWriter->is64Bit() ||
       Fixup.getOffset() <= UINT32_MAX - Layout.getFragmentOffset(Fragment)) &&
      "Fragment offset + fixup offset is overflowed in 32-bit mode.");
  uint32_t FixupOffsetInCsect =
      Layout.getFragmentOffset(Fragment) + Fixup.getOffset();

  XCOFFRelocation Reloc = {Index, FixupOffsetInCsect, SignAndSize, Type};
  MCSectionXCOFF *RelocationSec = cast<MCSectionXCOFF>(Fragment->getParent());
  assert(SectionMap.find(RelocationSec) != SectionMap.end() &&
         "Expected containing csect to exist in map.");
  SectionMap[RelocationSec]->Relocations.push_back(Reloc);

  if (!Target.getSymB())
    return;

  const MCSymbol *const SymB = &Target.getSymB()->getSymbol();
  if (SymA == SymB)
    report_fatal_error("relocation for opposite term is not yet supported");

  const MCSectionXCOFF *SymBSec = getContainingCsect(cast<MCSymbolXCOFF>(SymB));
  assert(SectionMap.find(SymBSec) != SectionMap.end() &&
         "Expected containing csect to exist in map.");
  if (SymASec == SymBSec)
    report_fatal_error(
        "relocation for paired relocatable term is not yet supported");

  assert(Type == XCOFF::RelocationType::R_POS &&
         "SymA must be R_POS here if it's not opposite term or paired "
         "relocatable term.");
  const uint32_t IndexB = getIndex(SymB, SymBSec);
  // SymB must be R_NEG here, given the general form of Target(MCValue) is
  // "SymbolA - SymbolB + imm64".
  const uint8_t TypeB = XCOFF::RelocationType::R_NEG;
  XCOFFRelocation RelocB = {IndexB, FixupOffsetInCsect, SignAndSize, TypeB};
  SectionMap[RelocationSec]->Relocations.push_back(RelocB);
  // We already folded "SymbolA + imm64" above when Type is R_POS for SymbolA,
  // now we just need to fold "- SymbolB" here.
  FixedValue -= getVirtualAddress(SymB, SymBSec);
}

void XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
                                      const MCAsmLayout &Layout) {
  uint32_t CurrentAddressLocation = 0;
  for (const auto *Section : Sections) {
    // Nothing to write for this Section.
    if (Section->Index == Section::UninitializedIndex || Section->IsVirtual)
      continue;

    // There could be a gap (without corresponding zero padding) between
    // sections.
    assert(CurrentAddressLocation <= Section->Address &&
           "CurrentAddressLocation should be less than or equal to section "
           "address.");

    CurrentAddressLocation = Section->Address;

    for (const auto *Group : Section->Groups) {
      for (const auto &Csect : *Group) {
        if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation)
          W.OS.write_zeros(PaddingSize);
        if (Csect.Size)
          Asm.writeSectionData(W.OS, Csect.MCCsect, Layout);
        CurrentAddressLocation = Csect.Address + Csect.Size;
      }
    }

    // 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 =
            Section->Address + Section->Size - CurrentAddressLocation) {
      W.OS.write_zeros(PaddingSize);
      CurrentAddressLocation += 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.");

  finalizeSectionInfo();
  uint64_t StartOffset = W.OS.tell();

  writeFileHeader();
  writeSectionHeaderTable();
  writeSections(Asm, Layout);
  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+1];
    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.getSymbolTableName());
  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.getSymbolTableName());
  // 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>(SectionCount);
  // 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) {
    // Nothing to write for this Section.
    if (Sec->Index == Section::UninitializedIndex)
      continue;

    // 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);
    W.write<uint32_t>(Sec->FileOffsetToRelocations);

    // Line number pointer. Not supported yet.
    W.write<uint32_t>(0);

    W.write<uint16_t>(Sec->RelocationCount);

    // Line number counts. Not supported yet.
    W.write<uint16_t>(0);

    W.write<int32_t>(Sec->Flags);
  }
}

void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc,
                                        const ControlSection &CSection) {
  W.write<uint32_t>(CSection.Address + Reloc.FixupOffsetInCsect);
  W.write<uint32_t>(Reloc.SymbolTableIndex);
  W.write<uint8_t>(Reloc.SignAndSize);
  W.write<uint8_t>(Reloc.Type);
}

void XCOFFObjectWriter::writeRelocations() {
  for (const auto *Section : Sections) {
    if (Section->Index == Section::UninitializedIndex)
      // Nothing to write for this Section.
      continue;

    for (const auto *Group : Section->Groups) {
      if (Group->empty())
        continue;

      for (const auto &Csect : *Group) {
        for (const auto Reloc : Csect.Relocations)
          writeRelocation(Reloc, Csect);
      }
    }
  }
}

void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
  for (const auto &Csect : UndefinedCsects) {
    writeSymbolTableEntryForControlSection(
        Csect, XCOFF::ReservedSectionNum::N_UNDEF, Csect.MCCsect->getStorageClass());
  }

  for (const auto *Section : Sections) {
    if (Section->Index == Section::UninitializedIndex)
      // Nothing to write for this Section.
      continue;

    for (const auto *Group : Section->Groups) {
      if (Group->empty())
        continue;

      const int16_t SectionIndex = Section->Index;
      for (const auto &Csect : *Group) {
        // Write out the control section first and then each symbol in it.
        writeSymbolTableEntryForControlSection(
            Csect, SectionIndex, Csect.MCCsect->getStorageClass());

        for (const auto &Sym : Csect.Syms)
          writeSymbolTableEntryForCsectMemberLabel(
              Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym)));
      }
    }
  }
}

void XCOFFObjectWriter::finalizeSectionInfo() {
  for (auto *Section : Sections) {
    if (Section->Index == Section::UninitializedIndex)
      // Nothing to record for this Section.
      continue;

    for (const auto *Group : Section->Groups) {
      if (Group->empty())
        continue;

      for (auto &Csect : *Group) {
        const size_t CsectRelocCount = Csect.Relocations.size();
        if (CsectRelocCount >= XCOFF::RelocOverflow ||
            Section->RelocationCount >= XCOFF::RelocOverflow - CsectRelocCount)
          report_fatal_error(
              "relocation entries overflowed; overflow section is "
              "not implemented yet");

        Section->RelocationCount += CsectRelocCount;
      }
    }
  }

  // Calculate the file offset to the relocation entries.
  uint64_t RawPointer = RelocationEntryOffset;
  for (auto Sec : Sections) {
    if (Sec->Index == Section::UninitializedIndex || !Sec->RelocationCount)
      continue;

    Sec->FileOffsetToRelocations = RawPointer;
    const uint32_t RelocationSizeInSec =
        Sec->RelocationCount * XCOFF::RelocationSerializationSize32;
    RawPointer += RelocationSizeInSec;
    if (RawPointer > UINT32_MAX)
      report_fatal_error("Relocation data overflowed this object file.");
  }

  // TODO Error check that the number of symbol table entries fits in 32-bits
  // signed ...
  if (SymbolTableEntryCount)
    SymbolTableOffset = RawPointer;
}

void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
  // 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;

  // Calculate indices for undefined symbols.
  for (auto &Csect : UndefinedCsects) {
    Csect.Size = 0;
    Csect.Address = 0;
    Csect.SymbolTableIndex = SymbolTableIndex;
    SymbolIndexMap[Csect.MCCsect->getQualNameSymbol()] = Csect.SymbolTableIndex;
    // 1 main and 1 auxiliary symbol table entry for each contained symbol.
    SymbolTableIndex += 2;
  }

  // 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.
  int32_t SectionIndex = 1;

  for (auto *Section : Sections) {
    const bool IsEmpty =
        llvm::all_of(Section->Groups,
                     [](const CsectGroup *Group) { return Group->empty(); });
    if (IsEmpty)
      continue;

    if (SectionIndex > MaxSectionIndex)
      report_fatal_error("Section index overflow!");
    Section->Index = SectionIndex++;
    SectionCount++;

    bool SectionAddressSet = false;
    for (auto *Group : Section->Groups) {
      if (Group->empty())
        continue;

      for (auto &Csect : *Group) {
        const MCSectionXCOFF *MCSec = Csect.MCCsect;
        Csect.Address = alignTo(Address, MCSec->getAlignment());
        Csect.Size = Layout.getSectionAddressSize(MCSec);
        Address = Csect.Address + Csect.Size;
        Csect.SymbolTableIndex = SymbolTableIndex;
        SymbolIndexMap[MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex;
        // 1 main and 1 auxiliary symbol table entry for the csect.
        SymbolTableIndex += 2;

        for (auto &Sym : Csect.Syms) {
          Sym.SymbolTableIndex = SymbolTableIndex;
          SymbolIndexMap[Sym.MCSym] = Sym.SymbolTableIndex;
          // 1 main and 1 auxiliary symbol table entry for each contained
          // symbol.
          SymbolTableIndex += 2;
        }
      }

      if (!SectionAddressSet) {
        Section->Address = Group->front().Address;
        SectionAddressSet = true;
      }
    }

    // Make sure the address of the next section aligned to
    // DefaultSectionAlign.
    Address = alignTo(Address, DefaultSectionAlign);
    Section->Size = Address - Section->Address;
  }

  SymbolTableEntryCount = SymbolTableIndex;

  // Calculate the RawPointer value for each section.
  uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
                        SectionCount * sizeof(XCOFF::SectionHeader32);
  for (auto *Sec : Sections) {
    if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual)
      continue;

    Sec->FileOffsetToData = RawPointer;
    RawPointer += Sec->Size;
    if (RawPointer > UINT32_MAX)
      report_fatal_error("Section raw data overflowed this object file.");
  }

  RelocationEntryOffset = 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);
}