[llvm] r369454 - Adds support for writing the .bss section for XCOFF object files.

Sean Fertile via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 20 15:03:19 PDT 2019


Author: sfertile
Date: Tue Aug 20 15:03:18 2019
New Revision: 369454

URL: http://llvm.org/viewvc/llvm-project?rev=369454&view=rev
Log:
Adds support for writing the .bss section for XCOFF object files.

Adds Wrapper classes for MCSymbol and MCSection into the XCOFF target
object writer. Also adds a class to represent the top-level sections, which we
materialize in the ObjectWriter.

executePostLayoutBinding will map all csects into the appropriate
container depending on its storage mapping class, and map all symbols
into their containing csect. Once all symbols have been processed we
- Assign addresses and symbol table indices.
- Calaculte section sizes.
- Build the section header table.
- Assign the sections raw-pointer value for non-virtual sections.

Since the .bss section is virtual, writing the header table is enough to
add support. Writing of a sections raw data, or of any relocations is
not included in this patch.

Testing is done by dumping the section header table, but it needs to be
extended to include dumping the symbol table once readobj support for
dumping auxiallary entries lands.

Differential Revision: https://reviews.llvm.org/D65159

Modified:
    llvm/trunk/include/llvm/BinaryFormat/XCOFF.h
    llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
    llvm/trunk/include/llvm/MC/MCContext.h
    llvm/trunk/include/llvm/MC/MCSectionXCOFF.h
    llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h
    llvm/trunk/include/llvm/MC/StringTableBuilder.h
    llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/trunk/lib/MC/MCContext.cpp
    llvm/trunk/lib/MC/MCObjectFileInfo.cpp
    llvm/trunk/lib/MC/MCXCOFFStreamer.cpp
    llvm/trunk/lib/MC/StringTableBuilder.cpp
    llvm/trunk/lib/MC/XCOFFObjectWriter.cpp
    llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp
    llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll

Modified: llvm/trunk/include/llvm/BinaryFormat/XCOFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/XCOFF.h?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/XCOFF.h (original)
+++ llvm/trunk/include/llvm/BinaryFormat/XCOFF.h Tue Aug 20 15:03:18 2019
@@ -147,6 +147,29 @@ enum SymbolType {
   XTY_CM = 3  ///< Common csect definition. For uninitialized storage.
 };
 
+struct FileHeader32 {
+  uint16_t Magic;
+  uint16_t NumberOfSections;
+  int32_t TimeStamp;
+  uint32_t SymbolTableFileOffset;
+  int32_t NumberOfSymbolTableEntries;
+  uint16_t AuxiliaryHeaderSize;
+  uint16_t Flags;
+};
+
+struct SectionHeader32 {
+  char Name[XCOFF::NameSize];
+  uint32_t PhysicalAddress;
+  uint32_t VirtualAddress;
+  uint32_t Size;
+  uint32_t FileOffsetToData;
+  uint32_t FileOffsetToRelocations;
+  uint32_t FileOffsetToLineNumbers;
+  uint16_t NumberOfRelocations;
+  uint16_t NumberOfLineNumbers;
+  int32_t Flags;
+};
+
 } // end namespace XCOFF
 } // end namespace llvm
 

Modified: llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h (original)
+++ llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h Tue Aug 20 15:03:18 2019
@@ -14,6 +14,7 @@
 #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H
 #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H
 
+#include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/Target/TargetLoweringObjectFile.h"
@@ -230,6 +231,8 @@ public:
 
   MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
                                     const TargetMachine &TM) const override;
+
+  static XCOFF::StorageClass getStorageClassForGlobal(const GlobalObject *GO);
 };
 
 } // end namespace llvm

Modified: llvm/trunk/include/llvm/MC/MCContext.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCContext.h?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCContext.h (original)
+++ llvm/trunk/include/llvm/MC/MCContext.h Tue Aug 20 15:03:18 2019
@@ -508,7 +508,9 @@ namespace llvm {
 
     MCSectionXCOFF *getXCOFFSection(StringRef Section,
                                     XCOFF::StorageMappingClass MappingClass,
-                                    XCOFF::SymbolType CSectType, SectionKind K,
+                                    XCOFF::SymbolType CSectType,
+                                    XCOFF::StorageClass StorageClass,
+                                    SectionKind K,
                                     const char *BeginSymName = nullptr);
 
     // Create and save a copy of STI and return a reference to the copy.

Modified: llvm/trunk/include/llvm/MC/MCSectionXCOFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSectionXCOFF.h?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCSectionXCOFF.h (original)
+++ llvm/trunk/include/llvm/MC/MCSectionXCOFF.h Tue Aug 20 15:03:18 2019
@@ -37,11 +37,13 @@ class MCSectionXCOFF final : public MCSe
   StringRef Name;
   XCOFF::StorageMappingClass MappingClass;
   XCOFF::SymbolType Type;
+  XCOFF::StorageClass StorageClass;
 
   MCSectionXCOFF(StringRef Section, XCOFF::StorageMappingClass SMC,
-                 XCOFF::SymbolType ST, SectionKind K, MCSymbol *Begin)
+                 XCOFF::SymbolType ST, XCOFF::StorageClass SC, SectionKind K,
+                 MCSymbol *Begin)
       : MCSection(SV_XCOFF, K, Begin), Name(Section), MappingClass(SMC),
-        Type(ST) {
+        Type(ST), StorageClass(SC) {
     assert((ST == XCOFF::XTY_SD || ST == XCOFF::XTY_CM) &&
            "Invalid or unhandled type for csect.");
   }

Modified: llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h (original)
+++ llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h Tue Aug 20 15:03:18 2019
@@ -8,6 +8,7 @@
 #ifndef LLVM_MC_MCSYMBOLXCOFF_H
 #define LLVM_MC_MCSYMBOLXCOFF_H
 
+#include "llvm/ADT/Optional.h"
 #include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/MC/MCSymbol.h"
 
@@ -19,6 +20,21 @@ public:
       : MCSymbol(SymbolKindXCOFF, Name, isTemporary) {}
 
   static bool classof(const MCSymbol *S) { return S->isXCOFF(); }
+
+  void setStorageClass(XCOFF::StorageClass SC) {
+    assert((!StorageClass.hasValue() || StorageClass.getValue() == SC) &&
+           "Redefining StorageClass of XCOFF MCSymbol.");
+    StorageClass = SC;
+  };
+
+  XCOFF::StorageClass getStorageClass() const {
+    assert(StorageClass.hasValue() &&
+           "StorageClass not set on XCOFF MCSymbol.");
+    return StorageClass.getValue();
+  }
+
+private:
+  Optional<XCOFF::StorageClass> StorageClass;
 };
 
 } // end namespace llvm

Modified: llvm/trunk/include/llvm/MC/StringTableBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/StringTableBuilder.h?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/StringTableBuilder.h (original)
+++ llvm/trunk/include/llvm/MC/StringTableBuilder.h Tue Aug 20 15:03:18 2019
@@ -22,7 +22,7 @@ class raw_ostream;
 /// Utility for building string tables with deduplicated suffixes.
 class StringTableBuilder {
 public:
-  enum Kind { ELF, WinCOFF, MachO, RAW, DWARF };
+  enum Kind { ELF, WinCOFF, MachO, RAW, DWARF, XCOFF };
 
 private:
   DenseMap<CachedHashStringRef, size_t> StringIndexMap;

Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (original)
+++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Tue Aug 20 15:03:18 2019
@@ -1840,9 +1840,11 @@ MCSection *TargetLoweringObjectFileXCOFF
   if (Kind.isBSSLocal() || Kind.isCommon()) {
     SmallString<128> Name;
     getNameWithPrefix(Name, GO, TM);
+    XCOFF::StorageClass SC =
+        TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO);
     return getContext().getXCOFFSection(
         Name, Kind.isBSSLocal() ? XCOFF::XMC_BS : XCOFF::XMC_RW, XCOFF::XTY_CM,
-        Kind, /* BeginSymbolName */ nullptr);
+        SC, Kind, /* BeginSymbolName */ nullptr);
   }
 
   if (Kind.isText())
@@ -1879,3 +1881,19 @@ const MCExpr *TargetLoweringObjectFileXC
     const TargetMachine &TM) const {
   report_fatal_error("XCOFF not yet implemented.");
 }
+
+XCOFF::StorageClass TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(
+    const GlobalObject *GO) {
+  switch (GO->getLinkage()) {
+  case GlobalValue::InternalLinkage:
+    return XCOFF::C_HIDEXT;
+  case GlobalValue::ExternalLinkage:
+  case GlobalValue::CommonLinkage:
+    return XCOFF::C_EXT;
+  case GlobalValue::ExternalWeakLinkage:
+    return XCOFF::C_WEAKEXT;
+  default:
+    report_fatal_error(
+        "Unhandled linkage when mapping linkage to StorageClass.");
+  }
+}

Modified: llvm/trunk/lib/MC/MCContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCContext.cpp?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCContext.cpp (original)
+++ llvm/trunk/lib/MC/MCContext.cpp Tue Aug 20 15:03:18 2019
@@ -538,6 +538,7 @@ MCSectionWasm *MCContext::getWasmSection
 MCSectionXCOFF *MCContext::getXCOFFSection(StringRef Section,
                                            XCOFF::StorageMappingClass SMC,
                                            XCOFF::SymbolType Type,
+                                           XCOFF::StorageClass SC,
                                            SectionKind Kind,
                                            const char *BeginSymName) {
   // Do the lookup. If we have a hit, return it.
@@ -555,7 +556,7 @@ MCSectionXCOFF *MCContext::getXCOFFSecti
     Begin = createTempSymbol(BeginSymName, false);
 
   MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate())
-      MCSectionXCOFF(CachedName, SMC, Type, Kind, Begin);
+      MCSectionXCOFF(CachedName, SMC, Type, SC, Kind, Begin);
   Entry.second = Result;
 
   auto *F = new MCDataFragment();

Modified: llvm/trunk/lib/MC/MCObjectFileInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCObjectFileInfo.cpp?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCObjectFileInfo.cpp (original)
+++ llvm/trunk/lib/MC/MCObjectFileInfo.cpp Tue Aug 20 15:03:18 2019
@@ -767,9 +767,9 @@ void MCObjectFileInfo::initXCOFFMCObject
   // get placed into this csect. The choice of csect name is not a property of
   // the ABI or object file format. For example, the XL compiler uses an unnamed
   // csect for program code.
-  TextSection =
-      Ctx->getXCOFFSection(".text", XCOFF::StorageMappingClass::XMC_PR,
-                           XCOFF::XTY_SD, SectionKind::getText());
+  TextSection = Ctx->getXCOFFSection(
+      ".text", XCOFF::StorageMappingClass::XMC_PR, XCOFF::XTY_SD,
+      XCOFF::C_HIDEXT, SectionKind::getText());
 }
 
 void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC,

Modified: llvm/trunk/lib/MC/MCXCOFFStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCXCOFFStreamer.cpp?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCXCOFFStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCXCOFFStreamer.cpp Tue Aug 20 15:03:18 2019
@@ -14,6 +14,7 @@
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSymbolXCOFF.h"
 #include "llvm/Support/TargetRegistry.h"
 
 using namespace llvm;
@@ -32,7 +33,20 @@ bool MCXCOFFStreamer::EmitSymbolAttribut
 
 void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                        unsigned ByteAlignment) {
-  report_fatal_error("Emiting common symbols not implemented for XCOFF.");
+  getAssembler().registerSymbol(*Symbol);
+  Symbol->setExternal(cast<MCSymbolXCOFF>(Symbol)->getStorageClass() !=
+                      XCOFF::C_HIDEXT);
+  Symbol->setCommon(Size, ByteAlignment);
+
+  // Need to add this symbol to the current Fragment which will belong to the
+  // containing CSECT.
+  auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
+  assert(F && "Expected a valid section with a fragment set.");
+  Symbol->setFragment(F);
+
+  // Emit the alignment and storage for the variable to the section.
+  EmitValueToAlignment(ByteAlignment);
+  EmitZeros(Size);
 }
 
 void MCXCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,

Modified: llvm/trunk/lib/MC/StringTableBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/StringTableBuilder.cpp?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/lib/MC/StringTableBuilder.cpp (original)
+++ llvm/trunk/lib/MC/StringTableBuilder.cpp Tue Aug 20 15:03:18 2019
@@ -38,6 +38,7 @@ void StringTableBuilder::initSize() {
     // Start the table with a NUL byte.
     Size = 1;
     break;
+  case XCOFF:
   case WinCOFF:
     // Make room to write the table size later.
     Size = 4;
@@ -67,9 +68,12 @@ void StringTableBuilder::write(uint8_t *
     if (!Data.empty())
       memcpy(Buf + P.second, Data.data(), Data.size());
   }
-  if (K != WinCOFF)
-    return;
-  support::endian::write32le(Buf, Size);
+  // The COFF formats store the size of the string table in the first 4 bytes.
+  // For Windows, the format is little-endian; for AIX, it is big-endian.
+  if (K == WinCOFF)
+    support::endian::write32le(Buf, Size);
+  else if (K == XCOFF)
+    support::endian::write32be(Buf, Size);
 }
 
 // Returns the character at Pos from end of a string.

Modified: llvm/trunk/lib/MC/XCOFFObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/XCOFFObjectWriter.cpp?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/lib/MC/XCOFFObjectWriter.cpp (original)
+++ llvm/trunk/lib/MC/XCOFFObjectWriter.cpp Tue Aug 20 15:03:18 2019
@@ -10,18 +10,139 @@
 //
 //===----------------------------------------------------------------------===//
 
+#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(); }
+  bool nameInStringTable() const {
+    return MCSym->getName().size() > XCOFF::NameSize;
+  }
+
+  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;
+
+  ControlSection(const MCSectionXCOFF *MCSec)
+      : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1) {}
+};
+
+// 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;
+
+  uint16_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 ControlSections = 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;
+
+  // ControlSections. 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.
+  ControlSections ProgramCodeCsects;
+  ControlSections BSSCsects;
+
+  uint32_t SymbolTableEntryCount = 0;
+  uint32_t SymbolTableOffset = 0;
+
+  virtual void reset() override;
 
   void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
 
@@ -30,6 +151,32 @@ class XCOFFObjectWriter : public MCObjec
 
   uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
 
+  void writeFileHeader();
+  void writeSectionHeaderTable();
+  void writeSymbolTable();
+
+  // 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 llvm::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);
@@ -37,11 +184,87 @@ public:
 
 XCOFFObjectWriter::XCOFFObjectWriter(
     std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
-    : W(OS, support::big), TargetObjectWriter(std::move(MOTW)) {}
+    : 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(
+    llvm::MCAssembler &Asm, const llvm::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 MCSectionXCOFF *MCSec = dyn_cast<const MCSectionXCOFF>(&S);
+    assert(WrapperMap.find(MCSec) == WrapperMap.end() &&
+           "Cannot add a csect twice.");
+
+    switch (MCSec->getMappingClass()) {
+    case XCOFF::XMC_PR:
+      assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
+             "Only an initialized csect can contain program code.");
+      // TODO FIXME Handle .text section csects.
+      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.");
+    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.
+    MCSectionXCOFF *ContainingCsect =
+        dyn_cast<MCSectionXCOFF>(XSym->getFragment(false)->getParent());
+    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.
+    const Symbol &WrapperSym = WrapperMap[ContainingCsect]->Syms.back();
+    if (WrapperSym.nameInStringTable()) {
+      Strings.add(WrapperSym.getName());
+    }
+  }
 
-void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &,
-                                                 const MCAsmLayout &) {
-  // TODO Implement once we have sections and symbols to handle.
+  Strings.finalize();
+  assignAddressesAndIndices(Layout);
 }
 
 void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &,
@@ -62,27 +285,193 @@ uint64_t XCOFFObjectWriter::writeObject(
 
   uint64_t StartOffset = W.OS.tell();
 
-  // TODO FIXME Assign section numbers/finalize sections.
+  writeFileHeader();
+  writeSectionHeaderTable();
+  // TODO writeSections();
+  // TODO writeRelocations();
 
   // TODO FIXME Finalize symbols.
+  writeSymbolTable();
+  // Write the string table.
+  Strings.write(W.OS);
 
+  return W.OS.tell() - StartOffset;
+}
+
+void XCOFFObjectWriter::writeFileHeader() {
   // Magic.
   W.write<uint16_t>(0x01df);
   // Number of sections.
-  W.write<uint16_t>(0);
+  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>(0);
+  W.write<uint32_t>(SymbolTableOffset);
   // Number of entries in the symbol table.
-  W.write<int32_t>(0);
+  W.write<int32_t>(SymbolTableEntryCount);
   // Size of the optional header.
   W.write<uint16_t>(0);
   // Flags.
   W.write<uint16_t>(0);
+}
 
-  return W.OS.tell() - StartOffset;
+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() {
+  assert((ProgramCodeCsects.size() == 1 &&
+          ProgramCodeCsects.back().Syms.size() == 0) &&
+         ".text csects not handled yet.");
+
+  // 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 &Sec : BSSCsects) {
+    assert(Sec.Syms.size() == 1 &&
+           "Uninitialized csect cannot contain more then 1 symbol.");
+    Symbol &Sym = Sec.Syms.back();
+
+    // Write the symbol's name.
+    if (Sym.nameInStringTable()) {
+      W.write<int32_t>(0);
+      W.write<uint32_t>(Strings.getOffset(Sym.getName()));
+    } else {
+      char Name[XCOFF::NameSize];
+      std::strncpy(Name, Sym.getName().data(), XCOFF::NameSize);
+      ArrayRef<char> NameRef(Name, XCOFF::NameSize);
+      W.write(NameRef);
+    }
+
+    W.write<uint32_t>(Sec.Address);
+    W.write<int16_t>(BSS.Index);
+    // 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 symbols visibility is default?
+    W.write<uint16_t>(0);
+
+    W.write<uint8_t>(Sym.getStorageClass());
+
+    // Always 1 aux entry for now.
+    W.write<uint8_t>(1);
+
+    W.write<uint32_t>(Sec.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(Sec.MCCsect));
+    // Storage mapping class.
+    W.write<uint8_t>(Sec.MCCsect->getMappingClass());
+    // Reserved (x_stab).
+    W.write<uint32_t>(0);
+    // Reserved (x_snstab).
+    W.write<uint16_t>(0);
+  }
+}
+
+void XCOFFObjectWriter::assignAddressesAndIndices(
+    const llvm::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.
+  uint16_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. TODO
+  // Data section Second. TODO
+
+  // BSS Section third.
+  if (!BSSCsects.empty()) {
+    Sections.push_back(&BSS);
+    BSS.Index = SectionIndex++;
+    assert(alignTo(Address, DefaultSectionAlign) == Address &&
+           "Improperly aligned address for section.");
+    uint32_t StartAddress = Address;
+    for (auto &Csect : BSSCsects) {
+      const MCSectionXCOFF *MCSec = Csect.MCCsect;
+      Address = alignTo(Address, MCSec->getAlignment());
+      Csect.Address = Address;
+      Address += Layout.getSectionAddressSize(MCSec);
+      Csect.SymbolTableIndex = SymbolTableIndex;
+      // 1 main and 1 auxiliary symbol table entry for the csect.
+      SymbolTableIndex += 2;
+      Csect.Size = Layout.getSectionAddressSize(MCSec);
+
+      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.Size = Address - StartAddress;
+  }
+
+  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.");
+  assert((Sec->getCSectType() <= 0x07u) && "csect type exceeds 3 bits.");
+  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

Modified: llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp Tue Aug 20 15:03:18 2019
@@ -1667,8 +1667,10 @@ void PPCAIXAsmPrinter::EmitGlobalVariabl
       getObjFileLowering().SectionForGlobal(GV, GVKind, TM));
   OutStreamer->SwitchSection(CSect);
 
-  // Create the symbol and emit it.
+  // Create the symbol, set its storage class, and emit it.
   MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(getSymbol(GV));
+  XSym->setStorageClass(
+      TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV));
   const DataLayout &DL = GV->getParent()->getDataLayout();
   unsigned Align =
       GV->getAlignment() ? GV->getAlignment() : DL.getPreferredAlignment(GV);

Modified: llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll?rev=369454&r1=369453&r2=369454&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll (original)
+++ llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll Tue Aug 20 15:03:18 2019
@@ -1,5 +1,14 @@
 ; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s
 
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
+; RUN: llvm-readobj --section-headers --file-header %t.o | \
+; RUN: FileCheck --check-prefix=OBJ %s
+
+; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t.o 2>&1 \
+; RUN: < %s | FileCheck --check-prefix=XCOFF64 %s
+
+; XCOFF64: LLVM ERROR: 64-bit XCOFF object files are not supported yet.
+
 @a = common global i32 0, align 4
 @b = common global i64 0, align 8
 @c = common global i16 0, align 2
@@ -9,7 +18,7 @@
 
 @over_aligned = common local_unnamed_addr global double 0.000000e+00, align 32
 
- at array = common local_unnamed_addr global [32 x i8] zeroinitializer, align 1
+ at array = common local_unnamed_addr global [33 x i8] zeroinitializer, align 1
 
 ; CHECK:      .csect .text[PR]
 ; CHECK-NEXT:  .file
@@ -19,4 +28,33 @@
 ; CHECK-NEXT: .comm   d,8,3
 ; CHECK-NEXT: .comm   f,4,2
 ; CHECK-NEXT: .comm   over_aligned,8,5
-; CHECK-NEXT: .comm   array,32,0
+; CHECK-NEXT: .comm   array,33,0
+
+; OBJ:      File: {{.*}}aix-xcoff-common.ll.tmp.o
+; OBJ-NEXT: Format: aixcoff-rs6000
+; OBJ-NEXT: Arch: powerpc
+; OBJ-NEXT: AddressSize: 32bit
+; OBJ-NEXT: FileHeader {
+; OBJ-NEXT:   Magic: 0x1DF
+; OBJ-NEXT:   NumberOfSections: 1
+; OBJ-NEXT:   TimeStamp:
+; OBJ-NEXT:   SymbolTableOffset: 0x3C
+; OBJ-NEXT:   SymbolTableEntries: 14
+; OBJ-NEXT:   OptionalHeaderSize: 0x0
+; OBJ-NEXT:   Flags: 0x0
+; OBJ-NEXT: }
+; OBJ-NEXT: Sections [
+; OBJ-NEXT:   Section {
+; OBJ-NEXT:     Index: 1
+; OBJ-NEXT:     Name: .bss
+; OBJ-NEXT:     PhysicalAddress: 0x0
+; OBJ-NEXT:     VirtualAddress: 0x0
+; OBJ-NEXT:     Size: 0x6C
+; OBJ-NEXT:     RawDataOffset: 0x0
+; OBJ-NEXT:     RelocationPointer: 0x0
+; OBJ-NEXT:     LineNumberPointer: 0x0
+; OBJ-NEXT:     NumberOfRelocations: 0
+; OBJ-NEXT:     NumberOfLineNumbers: 0
+; OBJ-NEXT:     Type: STYP_BSS (0x80)
+; OBJ-NEXT:   }
+; OBJ-NEXT: ]




More information about the llvm-commits mailing list