]> granicus.if.org Git - llvm/commitdiff
Adds support for writing the .bss section for XCOFF object files.
authorSean Fertile <sfertile@ca.ibm.com>
Tue, 20 Aug 2019 22:03:18 +0000 (22:03 +0000)
committerSean Fertile <sfertile@ca.ibm.com>
Tue, 20 Aug 2019 22:03:18 +0000 (22:03 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369454 91177308-0d34-0410-b5e6-96231b3b80d8

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

index e6d50501dc663d769360190a9124e09e8fac5f8a..a72d4a0b43435cd026c173e46ab84114959ddbb5 100644 (file)
@@ -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
 
index 3b9afba114a285627efea7c11d2eaf58b651c551..93f5baaac66059fdf57a09917db2758c62af100f 100644 (file)
@@ -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
index 69e3128e1944532784c4f1e955728ed6adb6a0b8..b925f32188832be10097d2b826561e4a3533e61f 100644 (file)
@@ -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.
index fe486f3d84bfc89f43c646cebe7b4d8bdf1cdafe..9e6a5196c9cad167c8d9327a29a8e409c1e121e9 100644 (file)
@@ -37,11 +37,13 @@ class MCSectionXCOFF final : public MCSection {
   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.");
   }
index 0a1fe14751388e46dd79509b66b264e46d69fe47..087cf5d0feba5363b1cf46095dd89d5ec20ad7a7 100644 (file)
@@ -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
index c83eca4e512d743c1595a03d285a4ef40e1b0380..c8d4c3bbc262b7cda5d4b411d13d981acea2820c 100644 (file)
@@ -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;
index 9c1eee0f8fc800d7dfa5e2a38c7c34d848e5cbbb..7abc86dfde72a6043e491b2b5e2f4bf6738e09eb 100644 (file)
@@ -1840,9 +1840,11 @@ MCSection *TargetLoweringObjectFileXCOFF::SelectSectionForGlobal(
   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 *TargetLoweringObjectFileXCOFF::lowerRelativeReference(
     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.");
+  }
+}
index 6975ab3af532767e1d044e5f3e8c211fad350ba5..a69ee19e1a1aeeb47bf6263379d97140f3784a83 100644 (file)
@@ -538,6 +538,7 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind Kind,
 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::getXCOFFSection(StringRef Section,
     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();
index 6dc0e38e8e84c66e6f69c96243921120ba0a11ea..d59453aa1cae1e7bb9c6d2cb6febc813ea3ad659 100644 (file)
@@ -767,9 +767,9 @@ void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) {
   // 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,
index 960791910c5992bee0d085367e83dee058f12d2e..5880c3d814a23d757e99ed18cd960c262cba3766 100644 (file)
@@ -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::EmitSymbolAttribute(MCSymbol *Symbol,
 
 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,
index cb3db8e2268c068a424a49a405e560a9ff6df975..c9c88ec58432c98f9465762b636a013515d43edc 100644 (file)
@@ -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 *Buf) const {
     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.
index 8f67c927f81d44e80ee9e95780ea16e79f374d41..1feec0e6d0bfa467d441262411c0aba46fe3d43d 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
+#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 MCObjectWriter {
 
   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;
 
-void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &,
-                                                 const MCAsmLayout &) {
-  // TODO Implement once we have sections and symbols to handle.
+  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());
+    }
+  }
+
+  Strings.finalize();
+  assignAddressesAndIndices(Layout);
 }
 
 void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &,
@@ -62,27 +285,193 @@ uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &) {
 
   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
index 71d4b18b0255809aa6b934ad3aac7e28f430fc50..39641879cc18ffa2434ce2c8a07878af34d76ec7 100644 (file)
@@ -1667,8 +1667,10 @@ void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
       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);
index 3aea2239805acf56a28d74f966819ea8db3bfb05..df07b6039665cb8db3e944bfa45cccf760a8a62a 100644 (file)
@@ -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
 
-@array = common local_unnamed_addr global [32 x i8] zeroinitializer, align 1
+@array = common local_unnamed_addr global [33 x i8] zeroinitializer, align 1
 
 ; CHECK:      .csect .text[PR]
 ; CHECK-NEXT:  .file
 ; 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: ]