[llvm] [z/OS][GOFF] Implement support for writing ESD + TXT records by the GOFFObjectWriter (PR #85851)

Neumann Hon via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 6 15:48:00 PDT 2024


https://github.com/Everybody0523 updated https://github.com/llvm/llvm-project/pull/85851

>From 7a6bf0c7e36288229367477b656a5c867be18997 Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Tue, 2 Apr 2024 17:59:30 -0400
Subject: [PATCH 01/10] Adding GOFFWriter (sans relocations). * Got rid of
 "alignment" field on MCSymbolGOFF * No more checking for 'main'

---
 llvm/include/llvm/BinaryFormat/GOFF.h         |  36 +-
 llvm/include/llvm/CodeGen/AsmPrinter.h        |   2 +-
 .../CodeGen/TargetLoweringObjectFileImpl.h    |   2 +
 llvm/include/llvm/MC/MCContext.h              |  33 +-
 llvm/include/llvm/MC/MCGOFFStreamer.h         |  11 +-
 llvm/include/llvm/MC/MCSectionGOFF.h          |  42 +-
 llvm/include/llvm/MC/MCSymbolGOFF.h           |  40 +
 .../CodeGen/TargetLoweringObjectFileImpl.cpp  |  30 +-
 llvm/lib/MC/GOFFObjectWriter.cpp              | 831 +++++++++++++++++-
 llvm/lib/MC/MCContext.cpp                     |  30 +-
 llvm/lib/MC/MCGOFFStreamer.cpp                |  76 ++
 llvm/lib/MC/MCObjectFileInfo.cpp              |  20 +-
 .../SystemZ/MCTargetDesc/SystemZMCExpr.cpp    |   4 +
 .../SystemZ/MCTargetDesc/SystemZMCExpr.h      |   2 +
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  65 +-
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |   3 +
 llvm/test/MC/GOFF/basic-goff-64.ll            | 252 ++++++
 llvm/test/MC/GOFF/empty-goff.s                |  39 +-
 18 files changed, 1458 insertions(+), 60 deletions(-)
 create mode 100644 llvm/test/MC/GOFF/basic-goff-64.ll

diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h
index 443bcfc9479a8b..9b4c17dee7576a 100644
--- a/llvm/include/llvm/BinaryFormat/GOFF.h
+++ b/llvm/include/llvm/BinaryFormat/GOFF.h
@@ -29,6 +29,8 @@ constexpr uint8_t RecordLength = 80;
 constexpr uint8_t RecordPrefixLength = 3;
 constexpr uint8_t PayloadLength = 77;
 constexpr uint8_t RecordContentLength = RecordLength - RecordPrefixLength;
+constexpr uint8_t ESDMetadataLength = 69;
+constexpr uint8_t TXTMetadataLength = 21;
 
 /// \brief Maximum data length before starting a new card for RLD and TXT data.
 ///
@@ -65,12 +67,7 @@ enum ESDNameSpaceId : uint8_t {
   ESD_NS_Parts = 3
 };
 
-enum ESDReserveQwords : uint8_t {
-  ESD_RQ_0 = 0,
-  ESD_RQ_1 = 1,
-  ESD_RQ_2 = 2,
-  ESD_RQ_3 = 3
-};
+enum ESDReserveQwords : uint8_t { ESD_RQ_0 = 0, ESD_RQ_1 = 1 };
 
 enum ESDAmode : uint8_t {
   ESD_AMODE_None = 0,
@@ -157,6 +154,12 @@ enum ESDAlignment : uint8_t {
   ESD_ALIGN_4Kpage = 12,
 };
 
+enum TXTRecordStyle : uint8_t {
+  TXT_RS_Byte = 0,
+  TXT_RS_Structured = 1,
+  TXT_RS_Unstructured = 2,
+};
+
 enum ENDEntryPointRequest : uint8_t {
   END_EPR_None = 0,
   END_EPR_EsdidOffset = 1,
@@ -166,9 +169,30 @@ enum ENDEntryPointRequest : uint8_t {
 
 // \brief Subsections of the primary C_CODE section in the object file.
 enum SubsectionKind : uint8_t {
+  SK_ReadOnly = 1,
   SK_PPA1 = 2,
   SK_PPA2 = 4,
 };
+
+// \brief Type of sections (properly - classes or modules) in the object file.
+enum GOFFSectionType : uint8_t {
+  /// Code - This section belongs to the the Code CSECT.
+  Code,
+
+  /// Static - This section belongs to the Static CSECT.
+  Static,
+
+  /// PPA2Offset - This section contains the offset to the PPA2.
+  /// Note: This is NOT the PPA2 section itself, which should
+  /// reside within the Code CSECT.
+  PPA2Offset,
+
+  /// B_IDRL -
+  B_IDRL,
+
+  /// Other - All other sections.
+  Other,
+};
 } // end namespace GOFF
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index a7fbf4aeb74494..c697a4911558ae 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -912,4 +912,4 @@ class AsmPrinter : public MachineFunctionPass {
 
 } // end namespace llvm
 
-#endif // LLVM_CODEGEN_ASMPRINTER_H
+#endif // LLVM_CODEGEN_ASMPRINTER_H
\ No newline at end of file
diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index 8eef45ce565deb..64631779161593 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -314,6 +314,8 @@ class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile {
                                       const TargetMachine &TM) const override;
   MCSection *getSectionForLSDA(const Function &F, const MCSymbol &FnSym,
                                const TargetMachine &TM) const override;
+  MCSymbol *getTargetSymbol(const GlobalValue *GV,
+                            const TargetMachine &TM) const override;
 };
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index ef9833cdf2b070..9135c7bd44c512 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -16,6 +16,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/MC/MCAsmMacro.h"
 #include "llvm/MC/MCDwarf.h"
@@ -299,6 +300,24 @@ class MCContext {
     }
   };
 
+  struct GOFFSectionKey {
+    std::string SectionName;
+    GOFF::GOFFSectionType SectionType;
+    bool HasParentSection;
+
+    GOFFSectionKey(StringRef SectionName, GOFF::GOFFSectionType SectionType,
+                   bool HasParentSection)
+        : SectionName(SectionName), SectionType(SectionType),
+          HasParentSection(HasParentSection) {}
+
+    bool operator<(const GOFFSectionKey &Other) const {
+      if (!HasParentSection && SectionType != GOFF::GOFFSectionType::Other) {
+        return SectionType < Other.SectionType;
+      }
+      return SectionName < Other.SectionName;
+    }
+  };
+
   struct WasmSectionKey {
     std::string SectionName;
     StringRef GroupName;
@@ -352,7 +371,7 @@ class MCContext {
   StringMap<MCSectionMachO *> MachOUniquingMap;
   std::map<ELFSectionKey, MCSectionELF *> ELFUniquingMap;
   std::map<COFFSectionKey, MCSectionCOFF *> COFFUniquingMap;
-  std::map<std::string, MCSectionGOFF *> GOFFUniquingMap;
+  std::map<GOFFSectionKey, MCSectionGOFF *> GOFFUniquingMap;
   std::map<WasmSectionKey, MCSectionWasm *> WasmUniquingMap;
   std::map<XCOFFSectionKey, MCSectionXCOFF *> XCOFFUniquingMap;
   StringMap<MCSectionDXContainer *> DXCUniquingMap;
@@ -633,8 +652,16 @@ class MCContext {
                                                    unsigned Flags,
                                                    unsigned EntrySize);
 
-  MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
-                                MCSection *Parent, const MCExpr *SubsectionId);
+  MCSectionGOFF *getGOFFLSDASection(StringRef Section, SectionKind Kind);
+
+  MCSectionGOFF *
+  getGOFFSection(StringRef Section, SectionKind Kind,
+                 MCSection *Parent = nullptr,
+                 const MCExpr *SubsectionId = nullptr,
+                 GOFF::GOFFSectionType SectionType = GOFF::Other,
+                 GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented,
+                 GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial,
+                 bool isRooted = false);
 
   MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
                                 SectionKind Kind, StringRef COMDATSymName,
diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h
index 2345509b161da5..52cde0632483a0 100644
--- a/llvm/include/llvm/MC/MCGOFFStreamer.h
+++ b/llvm/include/llvm/MC/MCGOFFStreamer.h
@@ -24,12 +24,15 @@ class MCGOFFStreamer : public MCObjectStreamer {
 
   ~MCGOFFStreamer() override;
 
-  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
-    return false;
-  }
+  // state management
+  void initSections(bool NoExecStack, const MCSubtargetInfo &STI) override;
+
+  void switchSection(MCSection *Section,
+                     const MCExpr *Subsection = nullptr) override;
+  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
   void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                         Align ByteAlignment) override {}
-  void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override {}
+  void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override;
   void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
                     uint64_t Size = 0, Align ByteAlignment = Align(1),
                     SMLoc Loc = SMLoc()) override {}
diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index d866329461ceae..2c0860dadabe11 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -10,6 +10,13 @@
 /// This file declares the MCSectionGOFF class, which contains all of the
 /// necessary machine code sections for the GOFF file format.
 ///
+/// GOFF doesn't truly have sections in the way object file formats on Unix
+/// such as ELF does, so MCSectionGOFF (more or less) represents a Class in
+/// GOFF. A GOFF Class is defined by a tuple of ESD symbols; specifically a SD
+/// symbol, an ED symbol, and PR or LD symbols. One of these symbols (PR or ED)
+/// must be the owner of a TXT record, which contains the actual contents of
+/// this Class.
+///
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_MC_MCSECTIONGOFF_H
@@ -24,14 +31,38 @@ namespace llvm {
 class MCExpr;
 
 class MCSectionGOFF final : public MCSection {
-private:
   MCSection *Parent;
   const MCExpr *SubsectionId;
+  GOFF::GOFFSectionType Type = GOFF::Other;
+  GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented;
+  GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial;
+
+  /// IsRooted - true iff the SD symbol used to define the GOFF Class this
+  /// MCSectionGOFF represents is the "root" SD symbol.
+  bool IsRooted = false;
 
   friend class MCContext;
   MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub)
       : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub) {}
 
+  MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
+                GOFF::ESDTextStyle TextStyle,
+                GOFF::ESDLoadingBehavior LoadBehavior, bool IsRooted)
+      : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub),
+        TextStyle(TextStyle), LoadBehavior(LoadBehavior), IsRooted(IsRooted) {}
+
+  MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
+                GOFF::GOFFSectionType Type)
+      : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub),
+        Type(Type) {
+    if (Type == GOFF::GOFFSectionType::PPA2Offset) {
+      TextStyle = GOFF::ESD_TS_ByteOriented;
+    } else if (Type == GOFF::GOFFSectionType::B_IDRL) {
+      TextStyle = GOFF::ESD_TS_Structured;
+      LoadBehavior = GOFF::ESD_LB_NoLoad;
+    }
+  }
+
 public:
   void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
                             raw_ostream &OS,
@@ -43,6 +74,15 @@ class MCSectionGOFF final : public MCSection {
 
   bool isVirtualSection() const override { return false; }
 
+  bool isCode() const { return Type == GOFF::Code; }
+  bool isStatic() const { return Type == GOFF::Static; }
+  bool isPPA2Offset() const { return Type == GOFF::PPA2Offset; }
+  bool isB_IDRL() const { return Type == GOFF::B_IDRL; }
+
+  GOFF::ESDTextStyle getTextStyle() const { return TextStyle; }
+  GOFF::ESDLoadingBehavior getLoadBehavior() const { return LoadBehavior; }
+  bool getRooted() const { return IsRooted; }
+
   MCSection *getParent() const { return Parent; }
   const MCExpr *getSubsectionId() const { return SubsectionId; }
 
diff --git a/llvm/include/llvm/MC/MCSymbolGOFF.h b/llvm/include/llvm/MC/MCSymbolGOFF.h
index cc4e2bbe246e2d..77588797259f0b 100644
--- a/llvm/include/llvm/MC/MCSymbolGOFF.h
+++ b/llvm/include/llvm/MC/MCSymbolGOFF.h
@@ -18,10 +18,50 @@
 namespace llvm {
 
 class MCSymbolGOFF : public MCSymbol {
+  enum SymbolFlags : uint16_t {
+    SF_NoRent = 0x01,    // Symbol is no-reentrant.
+    SF_Alias = 0x02,     // Symbol is alias.
+    SF_Hidden = 0x04,    // Symbol is hidden, aka not exported.
+    SF_Weak = 0x08,      // Symbol is weak.
+    SF_OSLinkage = 0x10, // Symbol uses OS linkage.
+  };
+
+  // Shift value for GOFF::ESDExecutable. 3 possible values. 2 bits.
+  static constexpr uint8_t GOFF_Executable_Shift = 6;
+  static constexpr uint8_t GOFF_Executable_Bitmask = 0x03;
+
 public:
   MCSymbolGOFF(const StringMapEntry<bool> *Name, bool IsTemporary)
       : MCSymbol(SymbolKindGOFF, Name, IsTemporary) {}
   static bool classof(const MCSymbol *S) { return S->isGOFF(); }
+
+  void setOSLinkage(bool Value = true) const {
+    modifyFlags(Value ? SF_OSLinkage : 0, SF_OSLinkage);
+  }
+  bool isOSLinkage() const { return getFlags() & SF_OSLinkage; }
+
+  void setExecutable(GOFF::ESDExecutable Value) const {
+    modifyFlags(Value << GOFF_Executable_Shift,
+                GOFF_Executable_Bitmask << GOFF_Executable_Shift);
+  }
+  GOFF::ESDExecutable getExecutable() const {
+    return static_cast<GOFF::ESDExecutable>(
+        (getFlags() >> GOFF_Executable_Shift) & GOFF_Executable_Bitmask);
+  }
+
+  void setHidden(bool Value = true) {
+    modifyFlags(Value ? SF_Hidden : 0, SF_Hidden);
+  }
+  bool isHidden() const { return getFlags() & SF_Hidden; }
+  bool isExported() const { return !isHidden(); }
+
+  void setWeak(bool Value = true) { modifyFlags(Value ? SF_Weak : 0, SF_Weak); }
+  bool isWeak() const { return getFlags() & SF_Weak; }
+
+  void setAlias(bool Value = true) {
+    modifyFlags(Value ? SF_Alias : 0, SF_Alias);
+  }
+  bool isAlias() const { return getFlags() & SF_Alias; }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 15b59421a0f44a..5b5497a33814bc 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -54,6 +54,7 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCSymbolGOFF.h"
 #include "llvm/MC/MCValue.h"
 #include "llvm/MC/SectionKind.h"
 #include "llvm/ProfileData/InstrProf.h"
@@ -2737,16 +2738,37 @@ MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal(
 MCSection *TargetLoweringObjectFileGOFF::getSectionForLSDA(
     const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const {
   std::string Name = ".gcc_exception_table." + F.getName().str();
-  return getContext().getGOFFSection(Name, SectionKind::getData(), nullptr,
-                                     nullptr);
+  return getContext().getGOFFLSDASection(Name, SectionKind::getData());
 }
 
 MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
   auto *Symbol = TM.getSymbol(GO);
+  if (Kind.isData())
+    return getContext().getGOFFSection(Symbol->getName(),
+                                       SectionKind::getData());
+
   if (Kind.isBSS())
-    return getContext().getGOFFSection(Symbol->getName(), SectionKind::getBSS(),
-                                       nullptr, nullptr);
+    return getContext().getGOFFSection(Symbol->getName(),
+                                       SectionKind::getBSS());
 
   return getContext().getObjectFileInfo()->getTextSection();
 }
+
+MCSymbol *
+TargetLoweringObjectFileGOFF::getTargetSymbol(const GlobalValue *GV,
+                                              const TargetMachine &TM) const {
+  // Set alignment.
+  if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV)) {
+    if (!GVar->hasInitializer() && GVar->getValueType()->isSized()) {
+      SmallString<128> NameStr;
+      getNameWithPrefix(NameStr, GV, TM); 
+      MCSymbolGOFF *Sym =
+          static_cast<MCSymbolGOFF *>(getContext().getOrCreateSymbol(NameStr));
+      auto Alignment = GVar->getParent()->getDataLayout().getPreferredAlign(GVar);
+      auto Size = GVar->getParent()->getDataLayout().getTypeSizeInBits(GVar->getValueType());
+      Sym->declareCommon(Size, Alignment, true);  
+    }
+  }
+  return nullptr;
+}
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index addeb6db959693..d5a164b3c3fb67 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -13,8 +13,13 @@
 #include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/MC/MCAsmLayout.h"
 #include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCGOFFObjectWriter.h"
+#include "llvm/MC/MCSectionGOFF.h"
+#include "llvm/MC/MCSymbolGOFF.h"
 #include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ConvertEBCDIC.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Path.h"
@@ -217,13 +222,115 @@ void GOFFOstream::write_impl(const char *Ptr, size_t Size) {
   }
 }
 
+/// \brief Wrapper class for symbols used exclusively for the symbol table in a
+/// GOFF file.
+class GOFFSymbol {
+public:
+  std::string Name;
+  uint32_t EsdId;
+  uint32_t ParentEsdId;
+  const MCSymbolGOFF *MCSym;
+  GOFF::ESDSymbolType SymbolType;
+
+  GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_NormalName;
+  GOFF::ESDAmode Amode = GOFF::ESD_AMODE_64;
+  GOFF::ESDRmode Rmode = GOFF::ESD_RMODE_64;
+  GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
+  GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
+  GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Byte;
+  GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented;
+  GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate;
+  GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial;
+  GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
+  GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong;
+  GOFF::ESDReserveQwords ReservedQwords = GOFF::ESD_RQ_0;
+
+  uint32_t SortKey = 0;
+  uint32_t SectionLength = 0;
+  uint32_t ADAEsdId = 0;
+  bool Indirect = false;
+  bool ForceRent = false;
+  bool Renamable = false;
+  bool ReadOnly = false;
+  uint32_t EASectionEsdId = 0;
+  uint32_t EASectionOffset = 0;
+
+  GOFFSymbol(StringRef Name, GOFF::ESDSymbolType Type, uint32_t EsdID,
+             uint32_t ParentEsdID)
+      : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
+        MCSym(nullptr), SymbolType(Type) {}
+  GOFFSymbol() {}
+
+  bool isForceRent() const { return ForceRent; }
+  bool isReadOnly() const { return ReadOnly; }
+  bool isRemovable() const { return false; }
+  bool isExecutable() const { return Executable == GOFF::ESD_EXE_CODE; }
+  bool isExecUnspecified() const {
+    return Executable == GOFF::ESD_EXE_Unspecified;
+  }
+  bool isWeakRef() const { return BindingStrength == GOFF::ESD_BST_Weak; }
+  bool isExternal() const {
+    return (BindingScope == GOFF::ESD_BSC_Library) ||
+           (BindingScope == GOFF::ESD_BSC_ImportExport);
+  }
+
+  static GOFF::ESDAlignment setGOFFAlignment(Align A) {
+    // The GOFF alignment is encoded as log_2 value.
+    GOFF::ESDAlignment Alignment;
+    uint8_t Log = Log2(A);
+    if (Log <= GOFF::ESD_ALIGN_4Kpage)
+      Alignment = static_cast<GOFF::ESDAlignment>(Log);
+    else
+      llvm_unreachable("Unsupported alignment");
+    return Alignment;
+  }
+};
+
+/// \brief Wrapper class for sections used exclusively for representing sections
+/// of the GOFF output that have actual bytes.  This could be a ED or a PR.
+/// Relocations will always have a P-pointer to the ESDID of one of these.
+struct GOFFSection {
+  uint32_t PEsdId;
+  uint32_t REsdId;
+  uint32_t SDEsdId;
+  const MCSectionGOFF *MC;
+
+  GOFFSection(uint32_t PEsdId, uint32_t REsdId, uint32_t SDEsdId)
+      : PEsdId(PEsdId), REsdId(REsdId), SDEsdId(SDEsdId), MC(nullptr) {}
+  GOFFSection(uint32_t PEsdId, uint32_t REsdId, uint32_t SDEsdId,
+              const MCSectionGOFF *MC)
+      : PEsdId(PEsdId), REsdId(REsdId), SDEsdId(SDEsdId), MC(MC) {}
+};
+
+// An MCSymbol may map to up to two GOFF Symbols. The first is the
+// "true" underlying symbol, the second one represents any indirect
+// references to that symbol.
 class GOFFObjectWriter : public MCObjectWriter {
+  typedef DenseMap<MCSymbol const *, uint32_t> SymbolMapType;
+  typedef DenseMap<MCSection const *, GOFFSection> SectionMapType;
+
   // The target specific GOFF writer instance.
   std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
 
+  /// Lookup table for MCSymbols to the ESD IDs of the associated
+  /// GOFF Symbol.
+  SymbolMapType SymbolMap;
+
+  /// Lookup table for MCSections to GOFFSections.  Needed to determine
+  /// SymbolType on GOFFSymbols that reside in GOFFSections.
+  SectionMapType SectionMap;
+
   // The stream used to write the GOFF records.
   GOFFOstream OS;
 
+  uint32_t EsdCounter = 1;
+
+  // The "root" SD node. This should have ESDID = 1
+  GOFFSymbol RootSD;
+  uint32_t ADAPREsdId;
+  uint32_t EntryEDEsdId;
+  uint32_t CodeLDEsdId;
+
 public:
   GOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
                    raw_pwrite_stream &OS)
@@ -231,20 +338,341 @@ class GOFFObjectWriter : public MCObjectWriter {
 
   ~GOFFObjectWriter() override {}
 
+private:
   // Write GOFF records.
   void writeHeader();
+
+  void writeSymbol(const GOFFSymbol &Symbol, const MCAsmLayout &Layout);
+
+  void writeADAandCodeSectionSymbols(MCAssembler &Asm,
+                                     const MCAsmLayout &Layout);
+  // Write out all ESD Symbols that own a section. GOFF doesn't have
+  // "sections" in the way other object file formats like ELF do; instead
+  // a GOFF section is defined as a triple of ESD Symbols (SD, ED, PR/LD).
+  // The PR/LD symbol should own a TXT record that contains the actual
+  // data of the section.
+  void writeSectionSymbols(MCAssembler &Asm, const MCAsmLayout &Layout);
+
+  void writeText(const MCSectionGOFF *MCSec, uint32_t EsdId, bool IsStructured,
+                 MCAssembler &Asm, const MCAsmLayout &Layout);
+
   void writeEnd();
 
+public:
   // Implementation of the MCObjectWriter interface.
   void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
                         const MCFragment *Fragment, const MCFixup &Fixup,
                         MCValue Target, uint64_t &FixedValue) override {}
   void executePostLayoutBinding(MCAssembler &Asm,
-                                const MCAsmLayout &Layout) override {}
+                                const MCAsmLayout &Layout) override;
   uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
+
+private:
+  GOFFSymbol createGOFFSymbol(StringRef Name, GOFF::ESDSymbolType Type,
+                              uint32_t ParentEsdId);
+  GOFFSymbol createSDSymbol(StringRef Name);
+  GOFFSymbol
+  createEDSymbol(StringRef Name, uint32_t ParentEsdId,
+                 GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Doubleword);
+  GOFFSymbol
+  createEDSymbol(StringRef Name, uint32_t ParentEsdId, uint32_t SectionLength,
+                 GOFF::ESDExecutable Executable, bool ForceRent,
+                 GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Doubleword);
+  GOFFSymbol createEDSymbol(
+      StringRef Name, uint32_t ParentEsdId, uint32_t SectionLength,
+      GOFF::ESDExecutable Executable, GOFF::ESDBindingScope BindingScope,
+      GOFF::ESDNameSpaceId NameSpaceId,
+      GOFF::ESDBindingAlgorithm BindingAlgorithm, bool ReadOnly,
+      GOFF::ESDTextStyle TextStyle, GOFF::ESDLoadingBehavior LoadBehavior,
+      GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Doubleword);
+  GOFFSymbol createLDSymbol(StringRef Name, uint32_t ParentEsdId);
+  GOFFSymbol createERSymbol(StringRef Name, uint32_t ParentEsdId,
+                            const MCSymbolGOFF *Source = nullptr);
+  GOFFSymbol createPRSymbol(StringRef Name, uint32_t ParentEsdId);
+  GOFFSymbol
+  createPRSymbol(StringRef Name, uint32_t ParentEsdId,
+                 GOFF::ESDNameSpaceId NameSpaceType,
+                 GOFF::ESDExecutable Executable, GOFF::ESDAlignment Alignment,
+                 GOFF::ESDBindingScope BindingScope, uint32_t SectionLength,
+                 GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial,
+                 GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink);
+  GOFFSymbol createWSASymbol(uint32_t ParentEsdId, bool ReserveQWords = false);
+
+  // Define the root SD node as well as the symbols that make up the
+  // ADA section.
+  void defineRootSD(MCAssembler &Asm, const MCAsmLayout &Layout);
+  void writeSymbolDefinedInModule(const MCSymbolGOFF &Symbol, MCAssembler &Asm,
+                                  const MCAsmLayout &Layout);
+  void writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol, MCAssembler &Asm,
+                                   const MCAsmLayout &Layout);
 };
 } // end anonymous namespace
 
+GOFFSymbol GOFFObjectWriter::createGOFFSymbol(StringRef Name,
+                                              GOFF::ESDSymbolType Type,
+                                              uint32_t ParentEsdId) {
+  return GOFFSymbol(Name, Type, EsdCounter++, ParentEsdId);
+}
+
+GOFFSymbol GOFFObjectWriter::createSDSymbol(StringRef Name) {
+  return createGOFFSymbol(Name, GOFF::ESD_ST_SectionDefinition, 0);
+}
+
+GOFFSymbol GOFFObjectWriter::createEDSymbol(StringRef Name,
+                                            uint32_t ParentEsdId,
+                                            GOFF::ESDAlignment Alignment) {
+  GOFFSymbol ED =
+      createGOFFSymbol(Name, GOFF::ESD_ST_ElementDefinition, ParentEsdId);
+
+  ED.Alignment = Alignment;
+  return ED;
+}
+
+GOFFSymbol GOFFObjectWriter::createEDSymbol(StringRef Name,
+                                            uint32_t ParentEsdId,
+                                            uint32_t SectionLength,
+                                            GOFF::ESDExecutable Executable,
+                                            bool ForceRent,
+                                            GOFF::ESDAlignment Alignment) {
+  GOFFSymbol ED =
+      createGOFFSymbol(Name, GOFF::ESD_ST_ElementDefinition, ParentEsdId);
+  ED.SectionLength = 0;
+  ED.Executable = Executable;
+  ED.ForceRent = ForceRent;
+  ED.Alignment = Alignment;
+  return ED;
+}
+
+GOFFSymbol GOFFObjectWriter::createEDSymbol(
+    StringRef Name, uint32_t ParentEsdId, uint32_t SectionLength,
+    GOFF::ESDExecutable Executable, GOFF::ESDBindingScope BindingScope,
+    GOFF::ESDNameSpaceId NameSpaceId,
+    GOFF::ESDBindingAlgorithm BindingAlgorithm, bool ReadOnly,
+    GOFF::ESDTextStyle TextStyle, GOFF::ESDLoadingBehavior LoadBehavior,
+    GOFF::ESDAlignment Alignment) {
+  GOFFSymbol ED =
+      createGOFFSymbol(Name, GOFF::ESD_ST_ElementDefinition, ParentEsdId);
+  ED.SectionLength = 0;
+  ED.Executable = Executable;
+  ED.BindingScope = BindingScope;
+  ED.NameSpace = NameSpaceId;
+  ED.BindAlgorithm = BindingAlgorithm;
+  ED.ReadOnly = ReadOnly;
+  ED.TextStyle = TextStyle;
+  ED.LoadBehavior = LoadBehavior;
+  ED.Alignment = Alignment;
+  return ED;
+}
+
+GOFFSymbol GOFFObjectWriter::createLDSymbol(StringRef Name,
+                                            uint32_t ParentEsdId) {
+  return createGOFFSymbol(Name, GOFF::ESD_ST_LabelDefinition, ParentEsdId);
+}
+
+GOFFSymbol GOFFObjectWriter::createERSymbol(StringRef Name,
+                                            uint32_t ParentEsdId,
+                                            const MCSymbolGOFF *Source) {
+  GOFFSymbol ER =
+      createGOFFSymbol(Name, GOFF::ESD_ST_ExternalReference, ParentEsdId);
+
+  if (Source) {
+    ER.Linkage = Source->isOSLinkage() ? GOFF::ESDLinkageType::ESD_LT_OS
+                                       : GOFF::ESDLinkageType::ESD_LT_XPLink;
+    ER.Executable = Source->getExecutable();
+    ER.BindingScope = Source->isExternal()
+                          ? GOFF::ESDBindingScope::ESD_BSC_Library
+                          : GOFF::ESDBindingScope::ESD_BSC_Section;
+    ER.BindingStrength = Source->isWeak()
+                             ? GOFF::ESDBindingStrength::ESD_BST_Weak
+                             : GOFF::ESDBindingStrength::ESD_BST_Strong;
+  }
+
+  return ER;
+}
+
+GOFFSymbol GOFFObjectWriter::createPRSymbol(StringRef Name,
+                                            uint32_t ParentEsdId) {
+  return createGOFFSymbol(Name, GOFF::ESD_ST_PartReference, ParentEsdId);
+}
+
+GOFFSymbol GOFFObjectWriter::createPRSymbol(
+    StringRef Name, uint32_t ParentEsdId, GOFF::ESDNameSpaceId NameSpaceType,
+    GOFF::ESDExecutable Executable, GOFF::ESDAlignment Alignment,
+    GOFF::ESDBindingScope BindingScope, uint32_t SectionLength,
+    GOFF::ESDLoadingBehavior LoadBehavior, GOFF::ESDLinkageType Linkage) {
+  GOFFSymbol PR =
+      createGOFFSymbol(Name, GOFF::ESD_ST_PartReference, ParentEsdId);
+  PR.NameSpace = NameSpaceType;
+  PR.Executable = Executable;
+  PR.Alignment = Alignment;
+  PR.BindingScope = BindingScope;
+  PR.SectionLength = SectionLength;
+  PR.LoadBehavior = LoadBehavior;
+  PR.Linkage = Linkage;
+  return PR;
+}
+
+GOFFSymbol GOFFObjectWriter::createWSASymbol(uint32_t ParentEsdId,
+                                             bool ReserveQwords) {
+  const char *WSAClassName = "C_WSA64";
+  GOFFSymbol WSA = createEDSymbol(WSAClassName, ParentEsdId);
+
+  WSA.Executable = GOFF::ESD_EXE_DATA;
+  WSA.TextStyle = GOFF::ESD_TS_ByteOriented;
+  WSA.BindAlgorithm = GOFF::ESD_BA_Merge;
+  WSA.Alignment = GOFF::ESD_ALIGN_Quadword;
+  WSA.LoadBehavior = GOFF::ESD_LB_Deferred;
+  WSA.NameSpace = GOFF::ESD_NS_Parts;
+  WSA.SectionLength = 0;
+  WSA.ReservedQwords = ReserveQwords ? GOFF::ESD_RQ_1 : GOFF::ESD_RQ_0;
+
+  return WSA;
+}
+
+static uint32_t getADASectionLength(MCAssembler &Asm,
+                                    const MCAsmLayout &Layout) {
+  uint32_t SecLen = 0;
+  for (const MCSection &MCSec : Asm) {
+    auto &GSec = cast<MCSectionGOFF>(MCSec);
+    if (GSec.isStatic()) {
+      SecLen = Layout.getSectionAddressSize(&MCSec);
+    }
+  }
+
+  // The ADA section is not allowed to be zero-length. We also want to
+  // avoid odd alignments, so we use 2 bytes.
+  return std::max(SecLen, 2u);
+}
+
+void GOFFObjectWriter::defineRootSD(MCAssembler &Asm,
+                                    const MCAsmLayout &Layout) {
+  StringRef FileName = "";
+  if (!Asm.getFileNames().empty())
+    FileName = sys::path::stem((*(Asm.getFileNames().begin())).first);
+  RootSD = createSDSymbol(FileName.str().append("#C"));
+  RootSD.BindingScope = GOFF::ESD_BSC_Section;
+  RootSD.Executable = GOFF::ESD_EXE_CODE;
+}
+
+void GOFFObjectWriter::writeSymbolDefinedInModule(const MCSymbolGOFF &Symbol,
+                                                  MCAssembler &Asm,
+                                                  const MCAsmLayout &Layout) {
+  MCSection &Section = Symbol.getSection();
+  SectionKind Kind = Section.getKind();
+  auto &Sec = cast<MCSectionGOFF>(Section);
+
+  StringRef SymbolName = Symbol.getName();
+  // If it's a text section, then create a label for it.
+  if (Kind.isText()) {
+    auto &GSection = SectionMap.at(&Sec);
+    GOFFSymbol LD = createLDSymbol(SymbolName, GSection.PEsdId);
+    LD.BindingStrength = Symbol.isWeak()
+                             ? GOFF::ESDBindingStrength::ESD_BST_Weak
+                             : GOFF::ESDBindingStrength::ESD_BST_Strong;
+
+    // If we don't know if it is code or data, assume it is code.
+    LD.Executable = Symbol.getExecutable();
+    if (LD.isExecUnspecified())
+      LD.Executable = GOFF::ESD_EXE_CODE;
+
+    // Determine the binding scope. Please note that the combination
+    // !isExternal && isExported makes no sense.
+    LD.BindingScope =
+        Symbol.isExternal()
+            ? (Symbol.isExported() ? GOFF::ESD_BSC_ImportExport
+                                   : (LD.isExecutable() ? GOFF::ESD_BSC_Library
+                                                        : GOFF::ESD_BSC_Module))
+            : GOFF::ESD_BSC_Section;
+
+    LD.ADAEsdId = ADAPREsdId;
+
+    LD.MCSym = &Symbol;
+    SymbolMap.insert(std::make_pair(&Symbol, LD.EsdId));
+    writeSymbol(LD, Layout);
+  } else if ((Kind.isBSS() || Kind.isData() || Kind.isThreadData()) && Symbol.isAlias()) {
+    // Alias to variable at the object file level.
+    // Not supported in RENT mode.
+    llvm_unreachable("Alias to rent variable is unsupported");
+  } else if (Kind.isBSS() || Kind.isData() || Kind.isThreadData()) {
+    std::string SectionName = Section.getName().str();
+    GOFFSymbol SD = createSDSymbol(SectionName);
+    auto BindingScope = Symbol.isExternal()
+                            ? (Symbol.isExported() ? GOFF::ESD_BSC_ImportExport
+                                                   : GOFF::ESD_BSC_Library)
+                            : GOFF::ESD_BSC_Section;
+    if (!Symbol.isExternal())
+      SD.BindingScope = GOFF::ESD_BSC_Section;
+
+    GOFFSymbol ED = createWSASymbol(SD.EsdId);
+    uint32_t PRSectionLen = Layout.getSectionAddressSize(&Section)
+                                ? Layout.getSectionAddressSize(&Section)
+                                : 0;
+    GOFFSymbol PR = createPRSymbol(
+        SectionName, ED.EsdId, GOFF::ESD_NS_Parts, GOFF::ESD_EXE_DATA,
+        GOFFSymbol::setGOFFAlignment(Section.getAlign()), BindingScope,
+        PRSectionLen);
+    ED.Alignment =
+        std::max(static_cast<GOFF::ESDAlignment>(Log2(Section.getAlign())),
+                 GOFF::ESD_ALIGN_Quadword);
+
+    writeSymbol(SD, Layout);
+    writeSymbol(ED, Layout);
+    writeSymbol(PR, Layout);
+
+    SymbolMap.insert(std::make_pair(&Symbol, PR.EsdId));
+    GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
+    SectionMap.insert(std::make_pair(&Section, GoffSec));
+  } else
+    llvm_unreachable("Unhandled section kind for Symbol");
+}
+
+void GOFFObjectWriter::writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol,
+                                                   MCAssembler &Asm,
+                                                   const MCAsmLayout &Layout) {
+  GOFFSymbol SD = RootSD;
+
+  GOFF::ESDExecutable Exec = Symbol.getExecutable();
+
+  GOFFSymbol GSym;
+  uint32_t GSymEsdId = 0;
+  switch (Exec) {
+  case GOFF::ESD_EXE_CODE:
+  case GOFF::ESD_EXE_Unspecified: {
+    GOFFSymbol ER = createERSymbol(Symbol.getName(), SD.EsdId, &Symbol);
+    ER.BindingScope = GOFF::ESD_BSC_ImportExport;
+    GSym = ER;
+    GSymEsdId = ER.EsdId;
+    break;
+  }
+  case GOFF::ESD_EXE_DATA: {
+    auto SymbAlign = Symbol.getCommonAlignment().valueOrOne();
+    GOFFSymbol ED = createWSASymbol(SD.EsdId);
+    writeSymbol(ED, Layout);
+    GOFFSymbol PR =
+        createPRSymbol(Symbol.getName(), ED.EsdId, GOFF::ESD_NS_Parts,
+                       GOFF::ESD_EXE_Unspecified,
+                       GOFFSymbol::setGOFFAlignment(SymbAlign),
+                       GOFF::ESD_BSC_ImportExport, 0);
+    GSym = PR;
+    GSymEsdId = PR.EsdId;
+    break;
+  }
+  }
+
+  GSym.BindingScope =
+      Symbol.isExported() ? GOFF::ESD_BSC_ImportExport : GOFF::ESD_BSC_Library;
+
+  SymbolMap.insert(std::make_pair(&Symbol, GSymEsdId));
+  writeSymbol(GSym, Layout);
+}
+
+void GOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+                                                const MCAsmLayout &Layout) {
+  LLVM_DEBUG(dbgs() << "Entering " << __FUNCTION__ << "\n");
+
+  defineRootSD(Asm, Layout);
+}
+
 void GOFFObjectWriter::writeHeader() {
   OS.newRecord(GOFF::RT_HDR, /*Size=*/57);
   OS.write_zeros(1);       // Reserved
@@ -259,6 +687,381 @@ void GOFFObjectWriter::writeHeader() {
   OS.write_zeros(6);       // Reserved
 }
 
+void GOFFObjectWriter::writeSymbol(const GOFFSymbol &Symbol,
+                                   const MCAsmLayout &Layout) {
+  uint32_t Offset = 0;
+  uint32_t Length = 0;
+  GOFF::ESDNameSpaceId NameSpaceId = GOFF::ESD_NS_ProgramManagementBinder;
+  Flags SymbolFlags;
+  uint8_t FillByteValue = 0;
+
+  Flags BehavAttrs[10] = {};
+  auto setAmode = [&BehavAttrs](GOFF::ESDAmode Amode) {
+    BehavAttrs[0].set(0, 8, Amode);
+  };
+  auto setRmode = [&BehavAttrs](GOFF::ESDRmode Rmode) {
+    BehavAttrs[1].set(0, 8, Rmode);
+  };
+  auto setTextStyle = [&BehavAttrs](GOFF::ESDTextStyle Style) {
+    BehavAttrs[2].set(0, 4, Style);
+  };
+  auto setBindingAlgorithm =
+      [&BehavAttrs](GOFF::ESDBindingAlgorithm Algorithm) {
+        BehavAttrs[2].set(4, 4, Algorithm);
+      };
+  auto setTaskingBehavior =
+      [&BehavAttrs](GOFF::ESDTaskingBehavior TaskingBehavior) {
+        BehavAttrs[3].set(0, 3, TaskingBehavior);
+      };
+  auto setReadOnly = [&BehavAttrs](bool ReadOnly) {
+    BehavAttrs[3].set(4, 1, ReadOnly);
+  };
+  auto setExecutable = [&BehavAttrs](GOFF::ESDExecutable Executable) {
+    BehavAttrs[3].set(5, 3, Executable);
+  };
+  auto setDuplicateSeverity =
+      [&BehavAttrs](GOFF::ESDDuplicateSymbolSeverity DSS) {
+        BehavAttrs[4].set(2, 2, DSS);
+      };
+  auto setBindingStrength = [&BehavAttrs](GOFF::ESDBindingStrength Strength) {
+    BehavAttrs[4].set(4, 4, Strength);
+  };
+  auto setLoadingBehavior = [&BehavAttrs](GOFF::ESDLoadingBehavior Behavior) {
+    BehavAttrs[5].set(0, 2, Behavior);
+  };
+  auto setIndirectReference = [&BehavAttrs](bool Indirect) {
+    uint8_t Value = Indirect ? 1 : 0;
+    BehavAttrs[5].set(3, 1, Value);
+  };
+  auto setBindingScope = [&BehavAttrs](GOFF::ESDBindingScope Scope) {
+    BehavAttrs[5].set(4, 4, Scope);
+  };
+  auto setLinkageType = [&BehavAttrs](GOFF::ESDLinkageType Type) {
+    BehavAttrs[6].set(2, 1, Type);
+  };
+  auto setAlignment = [&BehavAttrs](GOFF::ESDAlignment Alignment) {
+    BehavAttrs[6].set(3, 5, Alignment);
+  };
+
+  uint32_t AdaEsdId = 0;
+  uint32_t SortPriority = 0;
+
+  switch (Symbol.SymbolType) {
+  case GOFF::ESD_ST_SectionDefinition: {
+    if (Symbol.isExecutable()) // Unspecified otherwise
+      setTaskingBehavior(GOFF::ESD_TA_Rent);
+    if (Symbol.BindingScope == GOFF::ESD_BSC_Section)
+      setBindingScope(Symbol.BindingScope);
+  } break;
+  case GOFF::ESD_ST_ElementDefinition: {
+    SymbolFlags.set(3, 1, Symbol.isRemovable()); // Removable
+    if (Symbol.isExecutable()) {
+      setExecutable(GOFF::ESD_EXE_CODE);
+      setReadOnly(true);
+    } else {
+      if (Symbol.isExecUnspecified())
+        setExecutable(GOFF::ESD_EXE_Unspecified);
+      else
+        setExecutable(GOFF::ESD_EXE_DATA);
+
+      if (Symbol.isForceRent() || Symbol.isReadOnly())
+        setReadOnly(true);
+    }
+    Offset = 0; // TODO ED and SD are 1-1 for now
+    setAlignment(Symbol.Alignment);
+    SymbolFlags.set(0, 1, 1); // Fill-Byte Value Presence Flag
+    FillByteValue = 0;
+    SymbolFlags.set(1, 1, 0); // Mangled Flag TODO ?
+    setAmode(Symbol.Amode);
+    setRmode(Symbol.Rmode);
+    setTextStyle(Symbol.TextStyle);
+    setBindingAlgorithm(Symbol.BindAlgorithm);
+    setLoadingBehavior(Symbol.LoadBehavior);
+    SymbolFlags.set(5, 3, GOFF::ESD_RQ_0); // Reserved Qwords
+    NameSpaceId = Symbol.NameSpace;
+    Length = Symbol.SectionLength;
+    break;
+  }
+  case GOFF::ESD_ST_LabelDefinition: {
+    if (Symbol.isExecutable())
+      setExecutable(GOFF::ESD_EXE_CODE);
+    else
+      setExecutable(GOFF::ESD_EXE_DATA);
+    setBindingStrength(Symbol.BindingStrength);
+    setLinkageType(Symbol.Linkage);
+    SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable;
+    setAmode(Symbol.Amode);
+    NameSpaceId = Symbol.NameSpace;
+    setBindingScope(Symbol.BindingScope);
+    AdaEsdId = Symbol.ADAEsdId;
+
+    // Only symbol that doesn't have an MC is the SectionLabelSymbol which
+    // implicitly has 0 offset into the parent SD!
+    if (auto *MCSym = Symbol.MCSym) {
+      uint64_t Ofs = Layout.getSymbolOffset(*MCSym);
+      // We only have signed 32bits of offset!
+      assert(Ofs < (((uint64_t)1) << 31) && "ESD offset out of range.");
+      Offset = static_cast<uint32_t>(Ofs);
+    }
+    break;
+  }
+  case GOFF::ESD_ST_ExternalReference: {
+    setExecutable(Symbol.isExecutable() ? GOFF::ESD_EXE_CODE
+                                        : GOFF::ESD_EXE_DATA);
+    setBindingStrength(Symbol.BindingStrength);
+    setLinkageType(Symbol.Linkage);
+    SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable;
+    setIndirectReference(Symbol.Indirect);
+    Offset = 0; // ERs don't do offsets
+    NameSpaceId = Symbol.NameSpace;
+    setBindingScope(Symbol.BindingScope);
+    setAmode(Symbol.Amode);
+    break;
+  }
+  case GOFF::ESD_ST_PartReference: {
+    setExecutable(Symbol.isExecutable() ? GOFF::ESD_EXE_CODE
+                                        : GOFF::ESD_EXE_DATA);
+    NameSpaceId = Symbol.NameSpace;
+    setAlignment(Symbol.Alignment);
+    setAmode(Symbol.Amode);
+    setLinkageType(Symbol.Linkage);
+    setBindingScope(Symbol.BindingScope);
+    SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable;
+    setDuplicateSeverity(Symbol.isWeakRef() ? GOFF::ESD_DSS_NoWarning
+                                            : GOFF::ESD_DSS_Warning);
+    setIndirectReference(Symbol.Indirect);
+    setReadOnly(Symbol.ReadOnly);
+    SortPriority = Symbol.SortKey;
+
+    Length = Symbol.SectionLength;
+    break;
+  }
+  } // End switch
+
+  SmallString<256> Res;
+  ConverterEBCDIC::convertToEBCDIC(Symbol.Name, Res);
+  StringRef Name = Res.str();
+
+  // Assert here since this number is technically signed but we need uint for
+  // writing to records.
+  assert(Name.size() < GOFF::MaxDataLength &&
+         "Symbol max name length exceeded");
+  uint16_t NameLength = Name.size();
+
+  OS.newRecord(GOFF::RT_ESD, GOFF::ESDMetadataLength + NameLength);
+  OS.writebe<uint8_t>(Symbol.SymbolType);       // Symbol Type
+  OS.writebe<uint32_t>(Symbol.EsdId);           // ESDID
+  OS.writebe<uint32_t>(Symbol.ParentEsdId);     // Parent or Owning ESDID
+  OS.writebe<uint32_t>(0);                      // Reserved
+  OS.writebe<uint32_t>(Offset);                 // Offset or Address
+  OS.writebe<uint32_t>(0);                      // Reserved
+  OS.writebe<uint32_t>(Length);                 // Length
+  OS.writebe<uint32_t>(Symbol.EASectionEsdId);  // Extended Attribute ESDID
+  OS.writebe<uint32_t>(Symbol.EASectionOffset); // Extended Attribute Offset
+  OS.writebe<uint32_t>(0);                      // Reserved
+  OS.writebe<uint8_t>(NameSpaceId);             // Name Space ID
+  OS.writebe<uint8_t>(SymbolFlags);             // Flags
+  OS.writebe<uint8_t>(FillByteValue);           // Fill-Byte Value
+  OS.writebe<uint8_t>(0);                       // Reserved
+  OS.writebe<uint32_t>(AdaEsdId);               // ADA ESDID
+  OS.writebe<uint32_t>(SortPriority);           // Sort Priority
+  OS.writebe<uint64_t>(0);                      // Reserved
+  for (auto F : BehavAttrs)
+    OS.writebe<uint8_t>(F);          // Behavioral Attributes
+  OS.writebe<uint16_t>(NameLength);  // Name Length
+  OS.write(Name.data(), NameLength); // Name
+}
+
+void GOFFObjectWriter::writeADAandCodeSectionSymbols(
+    MCAssembler &Asm, const MCAsmLayout &Layout) {
+  // Write ESD Records for ADA Section
+  GOFFSymbol ADAED = createWSASymbol(RootSD.EsdId, true);
+  StringRef FileName = "";
+  if (!Asm.getFileNames().empty())
+    FileName = sys::path::stem((*(Asm.getFileNames().begin())).first);
+
+  GOFFSymbol ADA;
+  ADA = createPRSymbol(FileName.str().append("#S"), ADAED.EsdId,
+                       GOFF::ESD_NS_Parts, GOFF::ESD_EXE_DATA,
+                       GOFF::ESD_ALIGN_Quadword, GOFF::ESD_BSC_Section,
+                       getADASectionLength(Asm, Layout));
+  writeSymbol(ADAED, Layout);
+  writeSymbol(ADA, Layout);
+  ADAPREsdId = ADA.EsdId;
+
+  // Write ESD Records for Code Section
+  GOFFSymbol ED =
+      createEDSymbol("C_CODE64", RootSD.EsdId, 0, GOFF::ESD_EXE_CODE, true);
+
+  for (const MCSection &MCSec : Asm) {
+    auto &GSec = cast<MCSectionGOFF>(MCSec);
+    if (GSec.isCode()) {
+      if (!ED.SectionLength)
+        ED.SectionLength = Layout.getSectionAddressSize(&MCSec);
+    }
+  }
+
+  GOFFSymbol LD = createLDSymbol(RootSD.Name, ED.EsdId);
+  LD.Executable = GOFF::ESD_EXE_CODE;
+  if (RootSD.BindingScope == GOFF::ESD_BSC_Section)
+    LD.BindingScope = GOFF::ESD_BSC_Section;
+  else
+    LD.BindingScope = GOFF::ESD_BSC_Library;
+
+  LD.ADAEsdId = ADAPREsdId;
+
+  EntryEDEsdId = ED.EsdId;
+  CodeLDEsdId = LD.EsdId;
+  writeSymbol(ED, Layout);
+  writeSymbol(LD, Layout);
+}
+
+void GOFFObjectWriter::writeSectionSymbols(MCAssembler &Asm,
+                                           const MCAsmLayout &Layout) {
+  for (MCSection &S : Asm) {
+    auto &Section = cast<MCSectionGOFF>(S);
+    SectionKind Kind = Section.getKind();
+
+    if (Section.isCode()) {
+      // The only text section is the code section and the relevant ESD Records
+      // are already created. All we need to do is populate the SectionMap.
+      uint32_t RootSDEsdId = RootSD.EsdId;
+
+      GOFFSection GoffSec = GOFFSection(EntryEDEsdId, CodeLDEsdId, RootSDEsdId);
+      SectionMap.insert(std::make_pair(&Section, GoffSec));
+    } else if (Section.getName().starts_with(".lsda")) {
+      GOFFSymbol SD = RootSD;
+
+      const char *WSAClassName = "C_WSA64";
+      GOFFSymbol ED = createEDSymbol(
+          WSAClassName, SD.EsdId, 0, GOFF::ESD_EXE_DATA,
+          GOFF::ESD_BSC_Unspecified, GOFF::ESD_NS_Parts, GOFF::ESD_BA_Merge,
+          /*ReadOnly*/ false, GOFF::ESD_TS_Unstructured, GOFF::ESD_LB_Initial);
+      GOFFSymbol PR = createPRSymbol(
+          Section.getName(), ED.EsdId, GOFF::ESD_NS_Parts,
+          GOFF::ESD_EXE_Unspecified, GOFF::ESD_ALIGN_Fullword,
+          GOFF::ESD_BSC_Section, Layout.getSectionAddressSize(&Section),
+          GOFF::ESD_LB_Deferred);
+
+      writeSymbol(ED, Layout);
+      writeSymbol(PR, Layout);
+
+      GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
+      SectionMap.insert(std::make_pair(&Section, GoffSec));
+    } else if (Section.isPPA2Offset()) {
+      StringRef EDSectionName = "C_@@QPPA2";
+      StringRef PRSectionName = ".&ppa2";
+      GOFFSymbol SD = RootSD;
+      GOFFSymbol ED = createEDSymbol(
+          EDSectionName, SD.EsdId, 0, GOFF::ESD_EXE_DATA,
+          GOFF::ESD_BSC_Unspecified, GOFF::ESD_NS_Parts, GOFF::ESD_BA_Merge,
+          /*ReadOnly*/ true, GOFF::ESD_TS_ByteOriented, GOFF::ESD_LB_Initial);
+      GOFFSymbol PR =
+          createPRSymbol(PRSectionName, ED.EsdId, GOFF::ESD_NS_Parts,
+                         GOFF::ESD_EXE_Unspecified, GOFF::ESD_ALIGN_Doubleword,
+                         GOFF::ESD_BSC_Section, Layout.getSectionAddressSize(&Section),
+                         GOFF::ESD_LB_Initial, GOFF::ESD_LT_OS);
+      writeSymbol(ED, Layout);
+      writeSymbol(PR, Layout);
+
+      GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
+      SectionMap.insert(std::make_pair(&Section, GoffSec));
+    } else if (Section.isB_IDRL()) {
+      GOFFSymbol SD = RootSD;
+      GOFFSymbol ED = createEDSymbol(
+          "B_IDRL", SD.EsdId, Layout.getSectionAddressSize(&Section),
+          GOFF::ESD_EXE_Unspecified, GOFF::ESD_BSC_Module,
+          GOFF::ESD_NS_NormalName, GOFF::ESD_BA_Concatenate,
+          /*ReadOnly*/ true, GOFF::ESD_TS_Structured, GOFF::ESD_LB_NoLoad);
+      writeSymbol(ED, Layout);
+
+      GOFFSection GoffSec = GOFFSection(ED.EsdId, 0, 0);
+      SectionMap.insert(std::make_pair(&Section, GoffSec));
+    } else if (Section.isStatic()) {
+      GOFFSection GoffSec = GOFFSection(ADAPREsdId, ADAPREsdId, RootSD.EsdId);
+      SectionMap.insert(std::make_pair(&Section, GoffSec));
+    } else if (Kind.isBSS() || Kind.isData() || Kind.isThreadData()) {
+      // We handle this with the symbol definition, so there is no need to do
+      // anything here.
+    } else {
+      llvm_unreachable("Unhandled section kind");
+    }
+  }
+}
+
+namespace {
+/// Adapter stream to write a text section.
+class TextStream : public raw_ostream {
+  /// The underlying GOFFOstream.
+  GOFFOstream &OS;
+
+  /// The buffer size is the maximum number of bytes in a TXT section.
+  static constexpr size_t BufferSize = GOFF::MaxDataLength;
+
+  /// Static allocated buffer for the stream, used by the raw_ostream class. The
+  /// buffer is sized to hold the payload of a logical TXT record.
+  char Buffer[BufferSize];
+
+  /// The offset for the next TXT record. This is equal to the number of bytes
+  /// written.
+  size_t Offset;
+
+  /// The Esdid of the GOFF section.
+  const uint32_t EsdId;
+
+  /// The record style.
+  const GOFF::TXTRecordStyle RecordStyle;
+
+  /// See raw_ostream::write_impl.
+  void write_impl(const char *Ptr, size_t Size) override;
+
+  uint64_t current_pos() const override { return Offset; }
+
+public:
+  explicit TextStream(GOFFOstream &OS, uint32_t EsdId,
+                      GOFF::TXTRecordStyle RecordStyle)
+      : OS(OS), Offset(0), EsdId(EsdId), RecordStyle(RecordStyle) {
+    SetBuffer(Buffer, sizeof(Buffer));
+  }
+
+  ~TextStream() { flush(); }
+};
+
+void TextStream::write_impl(const char *Ptr, size_t Size) {
+  size_t WrittenLength = 0;
+
+  // We only have signed 32bits of offset.
+  if (Offset + Size > std::numeric_limits<int32_t>::max())
+    report_fatal_error("TXT section too large");
+
+  while (WrittenLength < Size) {
+    size_t ToWriteLength =
+        std::min(Size - WrittenLength, size_t(GOFF::MaxDataLength));
+
+    OS.newRecord(GOFF::RT_TXT, GOFF::TXTMetadataLength + ToWriteLength);
+    OS.writebe<uint8_t>(Flags(4, 4, RecordStyle));       // Text Record Style
+    OS.writebe<uint32_t>(EsdId);                         // Element ESDID
+    OS.writebe<uint32_t>(0);                             // Reserved
+    OS.writebe<uint32_t>(static_cast<uint32_t>(Offset)); // Offset
+    OS.writebe<uint32_t>(0);                      // Text Field True Length
+    OS.writebe<uint16_t>(0);                      // Text Encoding
+    OS.writebe<uint16_t>(ToWriteLength);          // Data Length
+    OS.write(Ptr + WrittenLength, ToWriteLength); // Data
+
+    WrittenLength += ToWriteLength;
+    Offset += ToWriteLength;
+  }
+}
+} // namespace
+
+void GOFFObjectWriter::writeText(const MCSectionGOFF *MCSec, uint32_t EsdId,
+                                 bool IsStructured, MCAssembler &Asm,
+                                 const MCAsmLayout &Layout) {
+  TextStream S(OS, EsdId,
+               IsStructured ? GOFF::TXT_RS_Structured : GOFF::TXT_RS_Byte);
+  Asm.writeSectionData(S, MCSec, Layout);
+}
+
 void GOFFObjectWriter::writeEnd() {
   uint8_t F = GOFF::END_EPR_None;
   uint8_t AMODE = 0;
@@ -283,6 +1086,32 @@ uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
   uint64_t StartOffset = OS.tell();
 
   writeHeader();
+  writeSymbol(RootSD, Layout);
+
+  writeADAandCodeSectionSymbols(Asm, Layout);
+  writeSectionSymbols(Asm, Layout);
+
+  // Process all MCSymbols and generate the ESD Record(s) for them.
+  // Symbols that are aliases of other symbols need to be processed
+  // at the end, after the symbols they alias are processed.
+  for (const MCSymbol &MCSym : Asm.symbols()) {
+    if (!MCSym.isTemporary()) {
+      auto &Symbol = cast<MCSymbolGOFF>(MCSym);
+      if (Symbol.isDefined())
+        writeSymbolDefinedInModule(Symbol, Asm, Layout);
+      else
+        writeSymbolDeclaredInModule(Symbol, Asm, Layout);
+    }
+  }
+
+  for (auto GSecIter = SectionMap.begin(); GSecIter != SectionMap.end();
+       GSecIter++) {
+    auto &MCGOFFSec = cast<MCSectionGOFF>(*(GSecIter->first));
+    GOFFSection &CurrGSec = GSecIter->second;
+    bool IsStructured = MCGOFFSec.getName().equals("B_IDRL");
+    writeText(&MCGOFFSec, CurrGSec.PEsdId, IsStructured, Asm, Layout);
+  }
+
   writeEnd();
 
   LLVM_DEBUG(dbgs() << "Wrote " << OS.logicalRecords() << " logical records.");
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 3aee96fdf57fc2..14d604ec705936 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -651,19 +651,33 @@ MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
                                       : std::nullopt;
 }
 
-MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
-                                         MCSection *Parent,
-                                         const MCExpr *SubsectionId) {
+MCSectionGOFF *MCContext::getGOFFLSDASection(StringRef Section,
+                                             SectionKind Kind) {
+  return getGOFFSection(Section, Kind, nullptr, nullptr, GOFF::GOFFSectionType::Other,
+                        GOFF::ESD_TS_Unstructured, GOFF::ESD_LB_Deferred, true);
+}
+
+MCSectionGOFF *MCContext::getGOFFSection(
+    StringRef Section, SectionKind Kind, MCSection *Parent,
+    const MCExpr *SubsectionId, GOFF::GOFFSectionType SectionType,
+    GOFF::ESDTextStyle TextStyle, GOFF::ESDLoadingBehavior LoadBehavior,
+    bool isRooted) {
   // Do the lookup. If we don't have a hit, return a new section.
-  auto IterBool =
-      GOFFUniquingMap.insert(std::make_pair(Section.str(), nullptr));
+  auto IterBool = GOFFUniquingMap.insert(std::make_pair(
+      GOFFSectionKey{Section.str(), GOFF::GOFFSectionType::Other, false},
+      nullptr));
   auto Iter = IterBool.first;
   if (!IterBool.second)
     return Iter->second;
 
-  StringRef CachedName = Iter->first;
-  MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate())
-      MCSectionGOFF(CachedName, Kind, Parent, SubsectionId);
+  StringRef CachedName = Iter->first.SectionName;
+  MCSectionGOFF *GOFFSection;
+  if (SectionType != GOFF::GOFFSectionType::Other)
+    GOFFSection = new (GOFFAllocator.Allocate())
+        MCSectionGOFF(CachedName, Kind, Parent, SubsectionId, SectionType);
+  else
+    GOFFSection = new (GOFFAllocator.Allocate())
+        MCSectionGOFF(CachedName, Kind, Parent, SubsectionId);
   Iter->second = GOFFSection;
 
   return GOFFSection;
diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp
index 58d13c9f378853..bc9a30c52c15f8 100644
--- a/llvm/lib/MC/MCGOFFStreamer.cpp
+++ b/llvm/lib/MC/MCGOFFStreamer.cpp
@@ -12,10 +12,18 @@
 
 #include "llvm/MC/MCGOFFStreamer.h"
 #include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionGOFF.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolGOFF.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Casting.h"
+
+#define DEBUG_TYPE "goff-streamer"
 
 using namespace llvm;
 
@@ -32,3 +40,71 @@ MCStreamer *llvm::createGOFFStreamer(MCContext &Context,
     S->getAssembler().setRelaxAll(true);
   return S;
 }
+
+void MCGOFFStreamer::initSections(bool NoExecStack,
+                                  const MCSubtargetInfo &STI) {
+  MCContext &Ctx = getContext();
+  if (NoExecStack)
+    switchSection(Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx));
+  else
+    switchSection(Ctx.getObjectFileInfo()->getTextSection());
+}
+
+void MCGOFFStreamer::switchSection(MCSection *S, const MCExpr *Subsection) {
+  auto Section = cast<MCSectionGOFF>(S);
+  MCSection *Parent = Section->getParent();
+
+  if (Parent) {
+    const MCExpr *Subsection = Section->getSubsectionId();
+    assert(Subsection && "No subsection associated with child section");
+    this->MCObjectStreamer::switchSection(Parent, Subsection);
+    return;
+  }
+
+  this->MCObjectStreamer::switchSection(Section, Subsection);
+}
+
+bool MCGOFFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
+  auto *Symbol = cast<MCSymbolGOFF>(S);
+
+  getAssembler().registerSymbol(*Symbol);
+
+  switch (Attribute) {
+  case MCSA_Global:
+    Symbol->setExternal(true);
+    break;
+  case MCSA_Local:
+    Symbol->setExternal(false);
+    break;
+  case MCSA_Hidden:
+    Symbol->setHidden(true);
+    break;
+  default:
+    return false;
+  }
+  return true;
+}
+
+void MCGOFFStreamer::emitInstToData(const MCInst &Inst,
+                                    const MCSubtargetInfo &STI) {
+  LLVM_DEBUG(dbgs() << "Entering " << __PRETTY_FUNCTION__ << "\n");
+  LLVM_DEBUG(dbgs() << "Inst: " << Inst << "\n");
+
+  MCAssembler &Assembler = getAssembler();
+  SmallVector<MCFixup, 4> Fixups;
+  SmallString<256> Code;
+  Assembler.getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
+
+  // Bundling is not currently supported.
+  assert(!Assembler.isBundlingEnabled() && "Do not handle bundling yet");
+
+  MCDataFragment *DF = getOrCreateDataFragment();
+
+  // Add the fixups and data.
+  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+    Fixups[I].setOffset(Fixups[I].getOffset() + DF->getContents().size());
+    DF->getFixups().push_back(Fixups[I]);
+  }
+  DF->setHasInstructions(STI);
+  DF->getContents().append(Code.begin(), Code.end());
+}
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 1f8f8ec5572759..7cbdf9610a5f61 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -544,25 +544,29 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
 }
 
 void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
-  TextSection =
-      Ctx->getGOFFSection(".text", SectionKind::getText(), nullptr, nullptr);
+  TextSection = Ctx->getGOFFSection(".text", SectionKind::getText(), nullptr,
+                                    nullptr, GOFF::GOFFSectionType::Code);
   BSSSection =
       Ctx->getGOFFSection(".bss", SectionKind::getBSS(), nullptr, nullptr);
+  ReadOnlySection =
+      Ctx->getGOFFSection(".rodata", SectionKind::getReadOnly(), TextSection,
+                          MCConstantExpr::create(GOFF::SK_ReadOnly, *Ctx));
   PPA1Section =
       Ctx->getGOFFSection(".ppa1", SectionKind::getMetadata(), TextSection,
                           MCConstantExpr::create(GOFF::SK_PPA1, *Ctx));
   PPA2Section =
       Ctx->getGOFFSection(".ppa2", SectionKind::getMetadata(), TextSection,
-                          MCConstantExpr::create(GOFF::SK_PPA2, *Ctx));
+                          MCConstantExpr::create(GOFF::SK_PPA2, *Ctx),
+                          GOFF::GOFFSectionType::PPA2Offset);
 
   PPA2ListSection =
       Ctx->getGOFFSection(".ppa2list", SectionKind::getData(),
-                          nullptr, nullptr);
+                          nullptr, nullptr, GOFF::GOFFSectionType::PPA2Offset);
 
-  ADASection =
-      Ctx->getGOFFSection(".ada", SectionKind::getData(), nullptr, nullptr);
-  IDRLSection =
-      Ctx->getGOFFSection("B_IDRL", SectionKind::getData(), nullptr, nullptr);
+  ADASection = Ctx->getGOFFSection(".ada", SectionKind::getText(), nullptr,
+                                   nullptr, GOFF::GOFFSectionType::Static);
+  IDRLSection = Ctx->getGOFFSection("B_IDRL", SectionKind::getData(), nullptr,
+                                    nullptr, GOFF::GOFFSectionType::B_IDRL);
 }
 
 void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
index 647cf765c6a3ea..89a69d8140b8f3 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
@@ -17,6 +17,10 @@ const SystemZMCExpr *SystemZMCExpr::create(VariantKind Kind, const MCExpr *Expr,
   return new (Ctx) SystemZMCExpr(Kind, Expr);
 }
 
+const SystemZMCExpr *SystemZMCExpr::create(const MCExpr *Expr, MCContext &Ctx) {
+  return create(VK_SystemZ_None, Expr, Ctx);
+}
+
 StringRef SystemZMCExpr::getVariantKindName() const {
   switch (static_cast<uint32_t>(getKind())) {
   case VK_SystemZ_None:
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
index 62e61091a14c64..b1372cafdd6f02 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
@@ -36,6 +36,8 @@ class SystemZMCExpr : public MCTargetExpr {
   static const SystemZMCExpr *create(VariantKind Kind, const MCExpr *Expr,
                                      MCContext &Ctx);
 
+  static const SystemZMCExpr *create(const MCExpr *Expr, MCContext &Ctx);
+
   /// getOpcode - Get the kind of this expression.
   VariantKind getKind() const { return Kind; }
 
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 5696ae117d69f0..f51057f7cba272 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -19,6 +19,7 @@
 #include "TargetInfo/SystemZTargetInfo.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 #include "llvm/IR/Mangler.h"
@@ -26,6 +27,7 @@
 #include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbolGOFF.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Chrono.h"
 #include "llvm/Support/ConvertEBCDIC.h"
@@ -985,12 +987,12 @@ void SystemZAsmPrinter::emitADASection() {
 
   const unsigned PointerSize = getDataLayout().getPointerSize();
   OutStreamer->switchSection(getObjFileLowering().getADASection());
-
+  OutStreamer->emitLabel(ADASym);
   unsigned EmittedBytes = 0;
   for (auto &Entry : ADATable.getTable()) {
-    const MCSymbol *Sym;
-    unsigned SlotKind;
-    std::tie(Sym, SlotKind) = Entry.first;
+    MCSymbolGOFF *Sym =
+        static_cast<MCSymbolGOFF *>(const_cast<MCSymbol *>(Entry.first.first));
+    unsigned SlotKind = Entry.first.second;
     unsigned Offset = Entry.second;
     assert(Offset == EmittedBytes && "Offset not as expected");
     (void)EmittedBytes;
@@ -1014,6 +1016,7 @@ void SystemZAsmPrinter::emitADASection() {
                                 MCSymbolRefExpr::create(Sym, OutContext),
                                 OutContext),
           PointerSize);
+      Sym->setExecutable(GOFF::ESD_EXE_CODE);
       EmittedBytes += PointerSize * 2;
       break;
     case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:
@@ -1023,6 +1026,7 @@ void SystemZAsmPrinter::emitADASection() {
                                 MCSymbolRefExpr::create(Sym, OutContext),
                                 OutContext),
           PointerSize);
+      Sym->setExecutable(GOFF::ESD_EXE_DATA);
       EmittedBytes += PointerSize;
       break;
     case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {
@@ -1420,9 +1424,56 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
                                       4);
 }
 
+void SystemZAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
+  if (TM.getTargetTriple().isOSzOS()) {
+    auto *Sym = cast<MCSymbolGOFF>(getSymbol(GV));
+    Sym->setExecutable(GOFF::ESD_EXE_DATA);
+  }
+
+  return AsmPrinter::emitGlobalVariable(GV);
+}
+
+const MCExpr *SystemZAsmPrinter::lowerConstant(const Constant *CV) {
+  const Triple &TargetTriple = TM.getTargetTriple();
+  if (TargetTriple.isOSzOS()) {
+    const GlobalAlias *GA = dyn_cast<GlobalAlias>(CV);
+    const Function *FV = dyn_cast<Function>(CV);
+    bool IsFunc = FV || (GA && isa<Function>(GA->getAliaseeObject()));
+    MCSymbolGOFF *Sym = nullptr;
+
+    if (auto GValue = dyn_cast<GlobalValue>(CV))
+      Sym = cast<MCSymbolGOFF>(getSymbol(GValue));
+    // TODO: Is it necessary to assert if CV is of type GlobalIFunc?
+
+    if (IsFunc) {
+      if (Sym) {
+      Sym->setExecutable(GOFF::ESD_EXE_CODE);
+        if (Sym->isExternal())
+          return SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,
+                                      MCSymbolRefExpr::create(Sym, OutContext),
+                                      OutContext);
+        // Trigger creation of function descriptor in ADA for internal
+        // functions.
+        unsigned Disp = ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
+        return MCBinaryExpr::createAdd(
+            SystemZMCExpr::create(MCSymbolRefExpr::create(ADASym, OutContext),
+                                  OutContext),
+            MCConstantExpr::create(Disp, OutContext), OutContext);
+      } else {
+        Sym->setExecutable(GOFF::ESD_EXE_DATA);
+        return MCSymbolRefExpr::create(Sym, OutContext);
+      }
+    }
+  }
+
+  return AsmPrinter::lowerConstant(CV);
+}
+
 void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
-  if (TM.getTargetTriple().isOSzOS())
+  if (TM.getTargetTriple().isOSzOS()) {
+    ADASym = OutContext.createTempSymbol("ada_sec_start");
     emitPPA2(M);
+  }
   AsmPrinter::emitStartOfAsmFile(M);
 }
 
@@ -1433,6 +1484,10 @@ void SystemZAsmPrinter::emitPPA2(Module &M) {
   // Make CELQSTRT symbol.
   const char *StartSymbolName = "CELQSTRT";
   MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName);
+  auto *GStartSym = static_cast<MCSymbolGOFF *>(CELQSTRT);
+  GStartSym->setExecutable(GOFF::ESD_EXE_CODE);
+  GStartSym->setOSLinkage();
+  GStartSym->setExternal(true);
 
   // Create symbol and assign to class field for use in PPA1.
   PPA2Sym = OutContext.createTempSymbol("PPA2", false);
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 303cce1a1b6581..d648656dcb62cf 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -28,6 +28,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   MCSymbol *CurrentFnPPA1Sym;     // PPA1 Symbol.
   MCSymbol *CurrentFnEPMarkerSym; // Entry Point Marker.
   MCSymbol *PPA2Sym;
+  MCSymbol *ADASym;
 
   SystemZTargetStreamer *getTargetStreamer() {
     MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
@@ -117,6 +118,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   }
   void emitFunctionEntryLabel() override;
   void emitFunctionBodyEnd() override;
+  void emitGlobalVariable(const GlobalVariable *GV) override;
+  const MCExpr *lowerConstant(const Constant *CV) override;
   void emitStartOfAsmFile(Module &M) override;
 
 private:
diff --git a/llvm/test/MC/GOFF/basic-goff-64.ll b/llvm/test/MC/GOFF/basic-goff-64.ll
new file mode 100644
index 00000000000000..d8b71cfb2ad1d6
--- /dev/null
+++ b/llvm/test/MC/GOFF/basic-goff-64.ll
@@ -0,0 +1,252 @@
+; RUN: llc %s -mtriple s390x-ibm-zos -filetype=obj -o - | od -v -Ax -tx1 | FileCheck --ignore-case %s
+; REQUIRES: systemz-registered-target
+
+ at x = global i32 0, align 4
+ at y = internal global i32 1, align 4
+ at z = external global i32, align 4
+
+; Function Attrs: noinline nounwind optnone
+define hidden void @foo() {
+entry:
+  store i32 8200, ptr @x, align 4
+  %0 = load i32, ptr @x, align 4
+  store i32 2, ptr @y, align 4
+  store i32 100, ptr @z, align 4
+  call void @bar(i32 noundef signext %0)
+  ret void
+}
+
+declare void @bar(i32 noundef signext)
+
+; Records for basic-goff-64#C
+; Requires a continuation record due to the name's length. ESD items
+; with names of length greater than 8 require continuation records.
+; Byte 1 of the first record for this ESD entry is 0x01 to indicate
+; that this record is continued, and byte 2 of the second record
+; to indicate that this is the final continuation record.
+; Byte 3 of first record for this ESD entry is 0x00 to indicate
+; SD (Section Definition).
+; This is the "root" SD Node.
+; CHECK: 000050 03 01 00 00 00 00 00 01 00 00 00 00 00 00 00 00
+; CHECK: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60
+; CHECK: 000090 00 01 00 00 00 00 00 0f 82 81 a2 89 83 60 87 96
+; CHECK: 0000a0 03 02 00 86 86 60 f6 f4 7b c3 00 00 00 00 00 00
+; CHECK: 0000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+
+; The next two logical records represent the ADA.
+; Record for C_WSA64.
+; Byte 3 is 0x01 to indicate ED (Element Definition).
+; This represents the writable static area.
+; CHECK: 0000f0 03 00 00 01 00 00 00 02 00 00 00 01 00 00 00 00
+; CHECK: 000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000110 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 000120 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 000130 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; Records for basic-goff-64#S
+; Requires a continuation record.
+; Byte 3 is 0x03 to indicate PR (Part Reference).
+; This represents the ADA (associated data area). 
+; CHECK: 000140 03 01 00 03 00 00 00 03 00 00 00 02 00 00 00 00
+; CHECK: 000150 00 00 00 00 00 00 00 00 00 00 00 28 00 00 00 00
+; CHECK: 000160 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 000170 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 000180 10 01 24 00 00 00 00 0f 82 81 a2 89 83 60 87 96
+; CHECK: 000190 03 02 00 86 86 60 f6 f4 7b e2 00 00 00 00 00 00
+; CHECK: 0001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+
+; The next two logical records represent the code section. Source
+; code and affiliated metadata (such as the PPA1 and PPA2 sections)
+; reside here.
+; Record for C_CODE64.
+; Byte 3 is 0x01 to indicate ED (Element Definition).
+; CHECK: 0001e0 03 00 00 01 00 00 00 04 00 00 00 01 00 00 00 00
+; CHECK: 0001f0 00 00 00 00 00 00 00 00 00 00 00 ac 00 00 00 00
+; CHECK: 000200 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00
+; CHECK: 000210 00 00 00 00 00 00 00 00 00 00 00 00 04 04 00 0a
+; CHECK: 000220 00 00 03 00 00 00 00 08 c3 6d c3 d6 c4 c5 f6 f4
+
+; Records for basic-goff-64#C. Note that names for ESD entries
+; need not be unique.
+; Byte 3 is 0x02 to indicate LD (Label Definition).
+; CHECK: 000230 03 01 00 02 00 00 00 05 00 00 00 04 00 00 00 00
+; CHECK: 000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000250 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 03
+; CHECK: 000260 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK: 000270 00 01 20 00 00 00 00 0f 82 81 a2 89 83 60 87 96
+; CHECK: 000280 03 02 00 86 86 60 f6 f4 7b c3 00 00 00 00 00 00
+; CHECK: 000290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+
+; Records for the C_@@QPPA2 section, which contains the offset
+; to the PPA2. 
+; CHECK: 0002d0 03 01 00 01 00 00 00 06 00 00 00 01 00 00 00 00
+; CHECK: 0002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002f0 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 000300 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 09
+; CHECK: 000310 00 00 03 00 00 00 00 09 c3 6d 7c 7c d8 d7 d7 c1
+; CHECK: 000320 03 02 00 f2 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000370 03 00 00 03 00 00 00 07 00 00 00 06 00 00 00 00
+; CHECK: 000380 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00
+; CHECK: 000390 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 0003a0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 0003b0 10 01 03 00 00 00 00 06 4b 50 97 97 81 f2 00 00
+
+
+; Record for function foo().
+; Byte 3 is 0x02 to indicate LD.
+; This record is owned by ESD entry with ID 4, which is 
+; C_CODE64. That is in turn owned by ESD entry with ID 1,
+; which is C_WSA64, which is owned by Section Definition
+; basic-goff-64#C. All functions in GOFF defined in the
+; compilation unit are defined in this manner.
+; Byte 63 is 0x02 = 0b00000010. Bits 5-7 indicate that
+; this record is executable, since it contains code. Note
+; that Bits 5-7 should be 001 if it is not executable and
+; 000 if executability is not specified.
+; Byte 65 is 0x03 = 0b00000011. Bits 4-7 indicate the
+; binding scope, which is library scope. This means 
+; that symbol is NOT available fo dynamic binding. However,
+; it is still available for static linking. This is due to the
+; hidden attribute on the function definition.
+; Note that the symbol name is written beginning in byte
+; 72. 0x86 0x96 0x96 spell `foo` in EBCDIC encoding.
+; CHECK: 03 00 00 02 00 00 00 0a 00 00 00 04 00 00 00 00
+; CHECK: 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 03
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK: 00 03 20 00 00 00 00 03 86 96 96 00 00 00 00 00
+
+; Record for Section Definition for global variable x.
+; Note that all initialized global variables require their
+; own section definition. This includes functions defined in
+; this module. Note that bytes 4-7 indicate that ESDID is 9.
+; Byte 3 is 0x00 to indicate SD.
+; CHECK: 03 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 01 a7 00 00 00 00 00 00 00
+
+; Record for C_WSA64 belonging to Section for global variable x.
+; Byte 3 is 0x01 to indicate ED.
+; Bytes 8-11 indicate that Parent ESDID is 9.
+; CHECK: 03 00 00 01 00 00 00 0c 00 00 00 0b 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; Record for PR of global variable x.
+; Byte 3 is 0x03 to indicate PR.
+; Bytes 8-11 indicate that Parent ESDID is A, the above
+; C_WSA64.
+; Byte 65 is 0x04 = 0b00000100. Bits 4-7 indicate the
+; binding scope, which is Import-Export scope. This means 
+; that symbol is available for dynamic binding.
+; Byte 66 is 0x20 = 0b00100000. Bits 1-2 indicate the linkage.
+; In this case 0b01 indicates XPLINK.
+; CHECK: 03 00 00 03 00 00 00 0d 00 00 00 0c 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 10 04 20 00 00 00 00 01 a7 00 00 00 00 00 00 00
+
+; Global variable y works much like x, but with a few
+; differences:
+; y is explicitly listed as internal, so its binding scope is
+; set to B'0001 (Section Scope). This is true for the SD record
+; as well as the PR record.
+; CHECK: 03 00 00 00 00 00 00 0e 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 01 00 00 00 00 00 01 a8 00 00 00 00 00 00 00
+; CHECK: 03 00 00 01 00 00 00 0f 00 00 00 0e 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+; CHECK: 03 00 00 03 00 00 00 10 00 00 00 0f 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 10 01 20 00 00 00 00 01 a8 00 00 00 00 00 00 00
+
+
+; Record for C_WSA64. Child of section basic-goff-64#C
+; and contains an extern global variable. (z)
+; CHECK: 03 00 00 01 00 00 00 11 00 00 00 01 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 00 40 00 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+
+; Record for external global variable z. This is NOT
+; initialized in this compilation unit and so unlike
+; global variable x, it lacks its own section definition.
+; Byte 3 is 0x03 to indicate PR.
+; Bytes 8-11 indicate that parent ESDID is 0d, which is
+; above C_WSA64.
+; Byte 65 is 0x04 = 0b00000100. Bits 4-7 indicate the
+; binding scope, which is Import-Export scope. This is
+; required because it is imported (not defined in this
+; module.
+; CHECK: 03 00 00 03 00 00 00 12 00 00 00 11 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 10 04 20 00 00 00 00 01 a9 00 00 00 00 00 00 00
+
+
+; Record for externally defined function bar().
+; Byte 3 is 0x04 to indicate External Reference (ErWx).
+; Bytes 8-11 indicate that parent ESDID is 01, the section
+; definition for this module. (basic-goff-64#C). 
+; Byte 65 indicates that the binding scope is Import-Export
+; Scope, since the definition may be something we dynamically
+; link against.
+; CHECK: 03 00 00 04 00 00 00 13 00 00 00 01 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK: 00 04 20 00 00 00 00 03 82 81 99 00 00 00 00 00
+
+
+; TXT Records:
+
+; TXT Record corresponding to global variable y.
+; Bytes 4-7 indicate that the owning ESD has ID 0x10. This is the
+; PR for global variable x.
+; Byte 22-23 contain the data length, which is 4, as expected for
+; an i32 type.
+; CHECK-DAG: 03 10 00 00 00 00 00 10 00 00 00 00 00 00 00 00
+
+; TXT Record corresponding to global variable x.
+; CHECK-DAG: 03 10 00 00 00 00 00 0d 00 00 00 00 00 00 00 00
+
+; TXT Record corresponding to the C_CODE64 Section.
+; This contains the bodies of the function(s) that make up
+; a module.
+; CHECK-DAG: 03 11 00 00 00 00 00 04 00 00 00 00 00 00 00 00
+
+; TXT Record containing ADA.
+; CHECK-DAG: 03 10 00 00 00 00 00 03 00 00 00 00 00 00 00 00
diff --git a/llvm/test/MC/GOFF/empty-goff.s b/llvm/test/MC/GOFF/empty-goff.s
index f6d402863d71c8..48f50581335483 100644
--- a/llvm/test/MC/GOFF/empty-goff.s
+++ b/llvm/test/MC/GOFF/empty-goff.s
@@ -2,23 +2,24 @@
 * RUN:   od -Ax -tx1 -v | FileCheck --ignore-case %s
 * REQUIRES: systemz-registered-target
 
-* Header record:
-*  03 is prefix byte
-*  f. is header type
-*  .0 is version
-* The 1 at offset 51 is the architecture level.
-* CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* Header record:	
+*  03 is prefix byte	
+*  f. is header type	
+*  .0 is version	
+* The 1 at offset 51 is the architecture level.	
+* CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+
+** End record:	
+**  03 is prefix byte	
+**  4. is header type	
+**  .0 is version	
+* CHECK: 0001e0 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 0001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
+* CHECK: 000220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00	
 
-* End record:
-*  03 is prefix byte
-*  4. is header type
-*  .0 is version
-* CHECK: 000050 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

>From 262f21a29e11f8eef7628fbfb649af881dd8e949 Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Thu, 4 Apr 2024 15:22:53 -0400
Subject: [PATCH 02/10] cleanup setting of symbol attributes

---
 llvm/include/llvm/MC/MCDirectives.h           |  2 ++
 llvm/lib/MC/MCAsmStreamer.cpp                 |  1 +
 llvm/lib/MC/MCELFStreamer.cpp                 |  1 +
 llvm/lib/MC/MCGOFFStreamer.cpp                | 14 ++++++++
 llvm/lib/MC/MCMachOStreamer.cpp               |  1 +
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 34 +++++++++++--------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  2 +-
 7 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/MC/MCDirectives.h b/llvm/include/llvm/MC/MCDirectives.h
index fcab56ff0a740f..2e1acfe808536f 100644
--- a/llvm/include/llvm/MC/MCDirectives.h
+++ b/llvm/include/llvm/MC/MCDirectives.h
@@ -48,6 +48,8 @@ enum MCSymbolAttr {
   MCSA_WeakDefAutoPrivate,      ///< .weak_def_can_be_hidden (MachO)
   MCSA_WeakAntiDep,             ///< .weak_anti_dep (COFF)
   MCSA_Memtag,                  ///< .memtag (ELF)
+
+  MCSA_ZOS_OS_Linkage,
 };
 
 enum MCAssemblerFlag {
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 3dc70a40158929..f5c5a29f0355a0 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -768,6 +768,7 @@ bool MCAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol,
     // Assemblers currently do not support a .cold directive.
   case MCSA_Exported:
     // Non-AIX assemblers currently do not support exported visibility.
+  case MCSA_ZOS_OS_Linkage: 
     return false;
   case MCSA_Memtag:
     OS << "\t.memtag\t";
diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp
index e541090769e9e5..9ec6fba79a83eb 100644
--- a/llvm/lib/MC/MCELFStreamer.cpp
+++ b/llvm/lib/MC/MCELFStreamer.cpp
@@ -217,6 +217,7 @@ bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
   case MCSA_IndirectSymbol:
   case MCSA_Exported:
   case MCSA_WeakAntiDep:
+  case MCSA_ZOS_OS_Linkage:
     return false;
 
   case MCSA_NoDeadStrip:
diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp
index bc9a30c52c15f8..f5f8f1af7c8f46 100644
--- a/llvm/lib/MC/MCGOFFStreamer.cpp
+++ b/llvm/lib/MC/MCGOFFStreamer.cpp
@@ -79,6 +79,20 @@ bool MCGOFFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
   case MCSA_Hidden:
     Symbol->setHidden(true);
     break;
+  case MCSA_Weak:
+  case MCSA_WeakReference:
+    Symbol->setExternal(true);
+    Symbol->setWeak();
+    break;
+  case MCSA_ELF_TypeFunction:
+    Symbol->setExecutable(GOFF::ESD_EXE_CODE);
+    break;
+  case MCSA_ELF_TypeObject:
+    Symbol->setExecutable(GOFF::ESD_EXE_DATA);
+    break;
+  case MCSA_ZOS_OS_Linkage:
+    Symbol->setOSLinkage();
+    break;
   default:
     return false;
   }
diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp
index d7d343f15eaa61..9ca22d465be323 100644
--- a/llvm/lib/MC/MCMachOStreamer.cpp
+++ b/llvm/lib/MC/MCMachOStreamer.cpp
@@ -359,6 +359,7 @@ bool MCMachOStreamer::emitSymbolAttribute(MCSymbol *Sym,
   case MCSA_Exported:
   case MCSA_Memtag:
   case MCSA_WeakAntiDep:
+  case MCSA_ZOS_OS_Linkage:
     return false;
 
   case MCSA_Global:
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index f51057f7cba272..bc5e2ea3e1d31d 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1016,7 +1016,6 @@ void SystemZAsmPrinter::emitADASection() {
                                 MCSymbolRefExpr::create(Sym, OutContext),
                                 OutContext),
           PointerSize);
-      Sym->setExecutable(GOFF::ESD_EXE_CODE);
       EmittedBytes += PointerSize * 2;
       break;
     case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:
@@ -1026,7 +1025,6 @@ void SystemZAsmPrinter::emitADASection() {
                                 MCSymbolRefExpr::create(Sym, OutContext),
                                 OutContext),
           PointerSize);
-      Sym->setExecutable(GOFF::ESD_EXE_DATA);
       EmittedBytes += PointerSize;
       break;
     case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {
@@ -1424,15 +1422,6 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
                                       4);
 }
 
-void SystemZAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
-  if (TM.getTargetTriple().isOSzOS()) {
-    auto *Sym = cast<MCSymbolGOFF>(getSymbol(GV));
-    Sym->setExecutable(GOFF::ESD_EXE_DATA);
-  }
-
-  return AsmPrinter::emitGlobalVariable(GV);
-}
-
 const MCExpr *SystemZAsmPrinter::lowerConstant(const Constant *CV) {
   const Triple &TargetTriple = TM.getTargetTriple();
   if (TargetTriple.isOSzOS()) {
@@ -1447,7 +1436,6 @@ const MCExpr *SystemZAsmPrinter::lowerConstant(const Constant *CV) {
 
     if (IsFunc) {
       if (Sym) {
-      Sym->setExecutable(GOFF::ESD_EXE_CODE);
         if (Sym->isExternal())
           return SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,
                                       MCSymbolRefExpr::create(Sym, OutContext),
@@ -1460,7 +1448,6 @@ const MCExpr *SystemZAsmPrinter::lowerConstant(const Constant *CV) {
                                   OutContext),
             MCConstantExpr::create(Disp, OutContext), OutContext);
       } else {
-        Sym->setExecutable(GOFF::ESD_EXE_DATA);
         return MCSymbolRefExpr::create(Sym, OutContext);
       }
     }
@@ -1485,8 +1472,8 @@ void SystemZAsmPrinter::emitPPA2(Module &M) {
   const char *StartSymbolName = "CELQSTRT";
   MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName);
   auto *GStartSym = static_cast<MCSymbolGOFF *>(CELQSTRT);
-  GStartSym->setExecutable(GOFF::ESD_EXE_CODE);
-  GStartSym->setOSLinkage();
+  OutStreamer->emitSymbolAttribute(GStartSym, MCSA_ELF_TypeFunction);
+  OutStreamer->emitSymbolAttribute(GStartSym, MCSA_ZOS_OS_Linkage);
   GStartSym->setExternal(true);
 
   // Create symbol and assign to class field for use in PPA1.
@@ -1657,6 +1644,23 @@ void SystemZAsmPrinter::emitFunctionEntryLabel() {
   AsmPrinter::emitFunctionEntryLabel();
 }
 
+bool SystemZAsmPrinter::doFinalization(Module &M) {
+  if (TM.getTargetTriple().isOSzOS()) {
+    // Set symbol flags for all global objects.
+    // Global Variables are objects (data)...
+    for (const auto &G : M.globals()) {
+      MCSymbol *Sym = getSymbol(&G);
+      OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject);
+    }
+    // and Funtions are functions (executable).
+    for (const Function &F : M) {
+      MCSymbol *Sym = getSymbol(&F);
+      OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
+    }
+  }
+  return AsmPrinter::doFinalization(M);
+}
+
 // Force static initialization.
 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSystemZAsmPrinter() {
   RegisterAsmPrinter<SystemZAsmPrinter> X(getTheSystemZTarget());
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index d648656dcb62cf..52a4ec5f155ff2 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -118,9 +118,9 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   }
   void emitFunctionEntryLabel() override;
   void emitFunctionBodyEnd() override;
-  void emitGlobalVariable(const GlobalVariable *GV) override;
   const MCExpr *lowerConstant(const Constant *CV) override;
   void emitStartOfAsmFile(Module &M) override;
+  bool doFinalization(Module &M) override;
 
 private:
   void emitCallInformation(CallType CT);

>From 1ef6ea7aa68f358e2aa54e267054cf1549b92dc8 Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Thu, 4 Apr 2024 16:57:43 -0400
Subject: [PATCH 03/10] Fix a silly mistake in GOFFSectionKey + actually use
 the TXT Record Style. (why are these separate fields?)

---
 llvm/include/llvm/MC/MCContext.h |  2 +-
 llvm/lib/MC/GOFFObjectWriter.cpp | 22 +++++-----------------
 llvm/lib/MC/MCContext.cpp        |  2 +-
 3 files changed, 7 insertions(+), 19 deletions(-)

diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 9135c7bd44c512..54fc458c6ab084 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -311,7 +311,7 @@ class MCContext {
           HasParentSection(HasParentSection) {}
 
     bool operator<(const GOFFSectionKey &Other) const {
-      if (!HasParentSection && SectionType != GOFF::GOFFSectionType::Other) {
+      if (SectionType != Other.SectionType) {
         return SectionType < Other.SectionType;
       }
       return SectionName < Other.SectionName;
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index d5a164b3c3fb67..4d17179c68f7be 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -306,16 +306,11 @@ struct GOFFSection {
 // "true" underlying symbol, the second one represents any indirect
 // references to that symbol.
 class GOFFObjectWriter : public MCObjectWriter {
-  typedef DenseMap<MCSymbol const *, uint32_t> SymbolMapType;
   typedef DenseMap<MCSection const *, GOFFSection> SectionMapType;
 
   // The target specific GOFF writer instance.
   std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
 
-  /// Lookup table for MCSymbols to the ESD IDs of the associated
-  /// GOFF Symbol.
-  SymbolMapType SymbolMap;
-
   /// Lookup table for MCSections to GOFFSections.  Needed to determine
   /// SymbolType on GOFFSymbols that reside in GOFFSections.
   SectionMapType SectionMap;
@@ -353,7 +348,7 @@ class GOFFObjectWriter : public MCObjectWriter {
   // data of the section.
   void writeSectionSymbols(MCAssembler &Asm, const MCAsmLayout &Layout);
 
-  void writeText(const MCSectionGOFF *MCSec, uint32_t EsdId, bool IsStructured,
+  void writeText(const MCSectionGOFF *MCSec, uint32_t EsdId, GOFF::TXTRecordStyle RecordStyle,
                  MCAssembler &Asm, const MCAsmLayout &Layout);
 
   void writeEnd();
@@ -587,7 +582,6 @@ void GOFFObjectWriter::writeSymbolDefinedInModule(const MCSymbolGOFF &Symbol,
     LD.ADAEsdId = ADAPREsdId;
 
     LD.MCSym = &Symbol;
-    SymbolMap.insert(std::make_pair(&Symbol, LD.EsdId));
     writeSymbol(LD, Layout);
   } else if ((Kind.isBSS() || Kind.isData() || Kind.isThreadData()) && Symbol.isAlias()) {
     // Alias to variable at the object file level.
@@ -619,7 +613,6 @@ void GOFFObjectWriter::writeSymbolDefinedInModule(const MCSymbolGOFF &Symbol,
     writeSymbol(ED, Layout);
     writeSymbol(PR, Layout);
 
-    SymbolMap.insert(std::make_pair(&Symbol, PR.EsdId));
     GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
     SectionMap.insert(std::make_pair(&Section, GoffSec));
   } else
@@ -634,14 +627,12 @@ void GOFFObjectWriter::writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol,
   GOFF::ESDExecutable Exec = Symbol.getExecutable();
 
   GOFFSymbol GSym;
-  uint32_t GSymEsdId = 0;
   switch (Exec) {
   case GOFF::ESD_EXE_CODE:
   case GOFF::ESD_EXE_Unspecified: {
     GOFFSymbol ER = createERSymbol(Symbol.getName(), SD.EsdId, &Symbol);
     ER.BindingScope = GOFF::ESD_BSC_ImportExport;
     GSym = ER;
-    GSymEsdId = ER.EsdId;
     break;
   }
   case GOFF::ESD_EXE_DATA: {
@@ -654,7 +645,6 @@ void GOFFObjectWriter::writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol,
                        GOFFSymbol::setGOFFAlignment(SymbAlign),
                        GOFF::ESD_BSC_ImportExport, 0);
     GSym = PR;
-    GSymEsdId = PR.EsdId;
     break;
   }
   }
@@ -662,7 +652,6 @@ void GOFFObjectWriter::writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol,
   GSym.BindingScope =
       Symbol.isExported() ? GOFF::ESD_BSC_ImportExport : GOFF::ESD_BSC_Library;
 
-  SymbolMap.insert(std::make_pair(&Symbol, GSymEsdId));
   writeSymbol(GSym, Layout);
 }
 
@@ -1055,10 +1044,9 @@ void TextStream::write_impl(const char *Ptr, size_t Size) {
 } // namespace
 
 void GOFFObjectWriter::writeText(const MCSectionGOFF *MCSec, uint32_t EsdId,
-                                 bool IsStructured, MCAssembler &Asm,
+                                 GOFF::TXTRecordStyle RecordStyle, MCAssembler &Asm,
                                  const MCAsmLayout &Layout) {
-  TextStream S(OS, EsdId,
-               IsStructured ? GOFF::TXT_RS_Structured : GOFF::TXT_RS_Byte);
+  TextStream S(OS, EsdId, RecordStyle);
   Asm.writeSectionData(S, MCSec, Layout);
 }
 
@@ -1108,8 +1096,8 @@ uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
        GSecIter++) {
     auto &MCGOFFSec = cast<MCSectionGOFF>(*(GSecIter->first));
     GOFFSection &CurrGSec = GSecIter->second;
-    bool IsStructured = MCGOFFSec.getName().equals("B_IDRL");
-    writeText(&MCGOFFSec, CurrGSec.PEsdId, IsStructured, Asm, Layout);
+    auto TextStyle = static_cast<GOFF::TXTRecordStyle>(MCGOFFSec.getTextStyle());
+    writeText(&MCGOFFSec, CurrGSec.PEsdId, TextStyle, Asm, Layout);
   }
 
   writeEnd();
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 14d604ec705936..a2ff6be75008b5 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -664,7 +664,7 @@ MCSectionGOFF *MCContext::getGOFFSection(
     bool isRooted) {
   // Do the lookup. If we don't have a hit, return a new section.
   auto IterBool = GOFFUniquingMap.insert(std::make_pair(
-      GOFFSectionKey{Section.str(), GOFF::GOFFSectionType::Other, false},
+      GOFFSectionKey{Section.str(), SectionType, (Parent != nullptr)},
       nullptr));
   auto Iter = IterBool.first;
   if (!IterBool.second)

>From 89b4d42590aaa1ade463efe5eefc16eb9ed75fde Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Thu, 4 Apr 2024 17:03:13 -0400
Subject: [PATCH 04/10] Clang format

---
 .../CodeGen/TargetLoweringObjectFileImpl.cpp  | 10 +++---
 llvm/lib/MC/GOFFObjectWriter.cpp              | 34 ++++++++++---------
 llvm/lib/MC/MCAsmStreamer.cpp                 |  2 +-
 llvm/lib/MC/MCContext.cpp                     | 21 +++++++-----
 llvm/lib/MC/MCObjectFileInfo.cpp              |  4 +--
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  7 ++--
 6 files changed, 43 insertions(+), 35 deletions(-)

diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 5b5497a33814bc..b881d5241ac9ac 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2762,12 +2762,14 @@ TargetLoweringObjectFileGOFF::getTargetSymbol(const GlobalValue *GV,
   if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV)) {
     if (!GVar->hasInitializer() && GVar->getValueType()->isSized()) {
       SmallString<128> NameStr;
-      getNameWithPrefix(NameStr, GV, TM); 
+      getNameWithPrefix(NameStr, GV, TM);
       MCSymbolGOFF *Sym =
           static_cast<MCSymbolGOFF *>(getContext().getOrCreateSymbol(NameStr));
-      auto Alignment = GVar->getParent()->getDataLayout().getPreferredAlign(GVar);
-      auto Size = GVar->getParent()->getDataLayout().getTypeSizeInBits(GVar->getValueType());
-      Sym->declareCommon(Size, Alignment, true);  
+      auto Alignment =
+          GVar->getParent()->getDataLayout().getPreferredAlign(GVar);
+      auto Size = GVar->getParent()->getDataLayout().getTypeSizeInBits(
+          GVar->getValueType());
+      Sym->declareCommon(Size, Alignment, true);
     }
   }
   return nullptr;
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index 4d17179c68f7be..0c96cfde867c84 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -348,8 +348,9 @@ class GOFFObjectWriter : public MCObjectWriter {
   // data of the section.
   void writeSectionSymbols(MCAssembler &Asm, const MCAsmLayout &Layout);
 
-  void writeText(const MCSectionGOFF *MCSec, uint32_t EsdId, GOFF::TXTRecordStyle RecordStyle,
-                 MCAssembler &Asm, const MCAsmLayout &Layout);
+  void writeText(const MCSectionGOFF *MCSec, uint32_t EsdId,
+                 GOFF::TXTRecordStyle RecordStyle, MCAssembler &Asm,
+                 const MCAsmLayout &Layout);
 
   void writeEnd();
 
@@ -583,7 +584,8 @@ void GOFFObjectWriter::writeSymbolDefinedInModule(const MCSymbolGOFF &Symbol,
 
     LD.MCSym = &Symbol;
     writeSymbol(LD, Layout);
-  } else if ((Kind.isBSS() || Kind.isData() || Kind.isThreadData()) && Symbol.isAlias()) {
+  } else if ((Kind.isBSS() || Kind.isData() || Kind.isThreadData()) &&
+             Symbol.isAlias()) {
     // Alias to variable at the object file level.
     // Not supported in RENT mode.
     llvm_unreachable("Alias to rent variable is unsupported");
@@ -639,11 +641,10 @@ void GOFFObjectWriter::writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol,
     auto SymbAlign = Symbol.getCommonAlignment().valueOrOne();
     GOFFSymbol ED = createWSASymbol(SD.EsdId);
     writeSymbol(ED, Layout);
-    GOFFSymbol PR =
-        createPRSymbol(Symbol.getName(), ED.EsdId, GOFF::ESD_NS_Parts,
-                       GOFF::ESD_EXE_Unspecified,
-                       GOFFSymbol::setGOFFAlignment(SymbAlign),
-                       GOFF::ESD_BSC_ImportExport, 0);
+    GOFFSymbol PR = createPRSymbol(
+        Symbol.getName(), ED.EsdId, GOFF::ESD_NS_Parts,
+        GOFF::ESD_EXE_Unspecified, GOFFSymbol::setGOFFAlignment(SymbAlign),
+        GOFF::ESD_BSC_ImportExport, 0);
     GSym = PR;
     break;
   }
@@ -945,11 +946,11 @@ void GOFFObjectWriter::writeSectionSymbols(MCAssembler &Asm,
           EDSectionName, SD.EsdId, 0, GOFF::ESD_EXE_DATA,
           GOFF::ESD_BSC_Unspecified, GOFF::ESD_NS_Parts, GOFF::ESD_BA_Merge,
           /*ReadOnly*/ true, GOFF::ESD_TS_ByteOriented, GOFF::ESD_LB_Initial);
-      GOFFSymbol PR =
-          createPRSymbol(PRSectionName, ED.EsdId, GOFF::ESD_NS_Parts,
-                         GOFF::ESD_EXE_Unspecified, GOFF::ESD_ALIGN_Doubleword,
-                         GOFF::ESD_BSC_Section, Layout.getSectionAddressSize(&Section),
-                         GOFF::ESD_LB_Initial, GOFF::ESD_LT_OS);
+      GOFFSymbol PR = createPRSymbol(
+          PRSectionName, ED.EsdId, GOFF::ESD_NS_Parts,
+          GOFF::ESD_EXE_Unspecified, GOFF::ESD_ALIGN_Doubleword,
+          GOFF::ESD_BSC_Section, Layout.getSectionAddressSize(&Section),
+          GOFF::ESD_LB_Initial, GOFF::ESD_LT_OS);
       writeSymbol(ED, Layout);
       writeSymbol(PR, Layout);
 
@@ -1044,8 +1045,8 @@ void TextStream::write_impl(const char *Ptr, size_t Size) {
 } // namespace
 
 void GOFFObjectWriter::writeText(const MCSectionGOFF *MCSec, uint32_t EsdId,
-                                 GOFF::TXTRecordStyle RecordStyle, MCAssembler &Asm,
-                                 const MCAsmLayout &Layout) {
+                                 GOFF::TXTRecordStyle RecordStyle,
+                                 MCAssembler &Asm, const MCAsmLayout &Layout) {
   TextStream S(OS, EsdId, RecordStyle);
   Asm.writeSectionData(S, MCSec, Layout);
 }
@@ -1096,7 +1097,8 @@ uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
        GSecIter++) {
     auto &MCGOFFSec = cast<MCSectionGOFF>(*(GSecIter->first));
     GOFFSection &CurrGSec = GSecIter->second;
-    auto TextStyle = static_cast<GOFF::TXTRecordStyle>(MCGOFFSec.getTextStyle());
+    auto TextStyle =
+        static_cast<GOFF::TXTRecordStyle>(MCGOFFSec.getTextStyle());
     writeText(&MCGOFFSec, CurrGSec.PEsdId, TextStyle, Asm, Layout);
   }
 
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index f5c5a29f0355a0..d56becbefeb8f2 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -768,7 +768,7 @@ bool MCAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol,
     // Assemblers currently do not support a .cold directive.
   case MCSA_Exported:
     // Non-AIX assemblers currently do not support exported visibility.
-  case MCSA_ZOS_OS_Linkage: 
+  case MCSA_ZOS_OS_Linkage:
     return false;
   case MCSA_Memtag:
     OS << "\t.memtag\t";
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index a2ff6be75008b5..567adfab3dca2f 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -653,15 +653,18 @@ MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
 
 MCSectionGOFF *MCContext::getGOFFLSDASection(StringRef Section,
                                              SectionKind Kind) {
-  return getGOFFSection(Section, Kind, nullptr, nullptr, GOFF::GOFFSectionType::Other,
-                        GOFF::ESD_TS_Unstructured, GOFF::ESD_LB_Deferred, true);
-}
-
-MCSectionGOFF *MCContext::getGOFFSection(
-    StringRef Section, SectionKind Kind, MCSection *Parent,
-    const MCExpr *SubsectionId, GOFF::GOFFSectionType SectionType,
-    GOFF::ESDTextStyle TextStyle, GOFF::ESDLoadingBehavior LoadBehavior,
-    bool isRooted) {
+  return getGOFFSection(Section, Kind, nullptr, nullptr,
+                        GOFF::GOFFSectionType::Other, GOFF::ESD_TS_Unstructured,
+                        GOFF::ESD_LB_Deferred, true);
+}
+
+MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
+                                         MCSection *Parent,
+                                         const MCExpr *SubsectionId,
+                                         GOFF::GOFFSectionType SectionType,
+                                         GOFF::ESDTextStyle TextStyle,
+                                         GOFF::ESDLoadingBehavior LoadBehavior,
+                                         bool isRooted) {
   // Do the lookup. If we don't have a hit, return a new section.
   auto IterBool = GOFFUniquingMap.insert(std::make_pair(
       GOFFSectionKey{Section.str(), SectionType, (Parent != nullptr)},
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 7cbdf9610a5f61..f89b67e5b22984 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -560,8 +560,8 @@ void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
                           GOFF::GOFFSectionType::PPA2Offset);
 
   PPA2ListSection =
-      Ctx->getGOFFSection(".ppa2list", SectionKind::getData(),
-                          nullptr, nullptr, GOFF::GOFFSectionType::PPA2Offset);
+      Ctx->getGOFFSection(".ppa2list", SectionKind::getData(), nullptr, nullptr,
+                          GOFF::GOFFSectionType::PPA2Offset);
 
   ADASection = Ctx->getGOFFSection(".ada", SectionKind::getText(), nullptr,
                                    nullptr, GOFF::GOFFSectionType::Static);
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index bc5e2ea3e1d31d..cf0027ca1cf526 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1438,11 +1438,12 @@ const MCExpr *SystemZAsmPrinter::lowerConstant(const Constant *CV) {
       if (Sym) {
         if (Sym->isExternal())
           return SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,
-                                      MCSymbolRefExpr::create(Sym, OutContext),
-                                      OutContext);
+                                       MCSymbolRefExpr::create(Sym, OutContext),
+                                       OutContext);
         // Trigger creation of function descriptor in ADA for internal
         // functions.
-        unsigned Disp = ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
+        unsigned Disp =
+            ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
         return MCBinaryExpr::createAdd(
             SystemZMCExpr::create(MCSymbolRefExpr::create(ADASym, OutContext),
                                   OutContext),

>From 0f503b276711a529744d6660ecee2da52708e528 Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Thu, 4 Apr 2024 17:08:49 -0400
Subject: [PATCH 05/10] Remove dead section for lsda

---
 llvm/lib/MC/GOFFObjectWriter.cpp | 19 -------------------
 1 file changed, 19 deletions(-)

diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index 0c96cfde867c84..e5a75461eb21aa 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -919,25 +919,6 @@ void GOFFObjectWriter::writeSectionSymbols(MCAssembler &Asm,
 
       GOFFSection GoffSec = GOFFSection(EntryEDEsdId, CodeLDEsdId, RootSDEsdId);
       SectionMap.insert(std::make_pair(&Section, GoffSec));
-    } else if (Section.getName().starts_with(".lsda")) {
-      GOFFSymbol SD = RootSD;
-
-      const char *WSAClassName = "C_WSA64";
-      GOFFSymbol ED = createEDSymbol(
-          WSAClassName, SD.EsdId, 0, GOFF::ESD_EXE_DATA,
-          GOFF::ESD_BSC_Unspecified, GOFF::ESD_NS_Parts, GOFF::ESD_BA_Merge,
-          /*ReadOnly*/ false, GOFF::ESD_TS_Unstructured, GOFF::ESD_LB_Initial);
-      GOFFSymbol PR = createPRSymbol(
-          Section.getName(), ED.EsdId, GOFF::ESD_NS_Parts,
-          GOFF::ESD_EXE_Unspecified, GOFF::ESD_ALIGN_Fullword,
-          GOFF::ESD_BSC_Section, Layout.getSectionAddressSize(&Section),
-          GOFF::ESD_LB_Deferred);
-
-      writeSymbol(ED, Layout);
-      writeSymbol(PR, Layout);
-
-      GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
-      SectionMap.insert(std::make_pair(&Section, GoffSec));
     } else if (Section.isPPA2Offset()) {
       StringRef EDSectionName = "C_@@QPPA2";
       StringRef PRSectionName = ".&ppa2";

>From 9a2f175cf4aa458db29161a1858f735c515fa813 Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Fri, 5 Apr 2024 01:40:14 -0400
Subject: [PATCH 06/10] key

---
 llvm/include/llvm/MC/MCContext.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 54fc458c6ab084..6a1cf36dfb8d8f 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -311,10 +311,11 @@ class MCContext {
           HasParentSection(HasParentSection) {}
 
     bool operator<(const GOFFSectionKey &Other) const {
-      if (SectionType != Other.SectionType) {
-        return SectionType < Other.SectionType;
+      if (SectionType == GOFF::GOFFSectionType::Other
+          && SectionType == GOFF::GOFFSectionType::Other) {
+        return SectionName < Other.SectionName;
       }
-      return SectionName < Other.SectionName;
+      return SectionType < Other.SectionType;
     }
   };
 

>From 998eda0ff3e90c2953f9444b8698f86ab1d4a60d Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Fri, 5 Apr 2024 20:51:57 -0400
Subject: [PATCH 07/10] Exclude non-external linkage globals

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index cf0027ca1cf526..ca3a703cd64e20 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1650,13 +1650,17 @@ bool SystemZAsmPrinter::doFinalization(Module &M) {
     // Set symbol flags for all global objects.
     // Global Variables are objects (data)...
     for (const auto &G : M.globals()) {
-      MCSymbol *Sym = getSymbol(&G);
-      OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject);
+      if (!G.hasInternalLinkage()) {
+        MCSymbol *Sym = getSymbol(&G);
+        OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject);
+      }
     }
     // and Funtions are functions (executable).
     for (const Function &F : M) {
-      MCSymbol *Sym = getSymbol(&F);
-      OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
+      if (!F.hasInternalLinkage()) {
+        MCSymbol *Sym = getSymbol(&F);
+        OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
+      }
     }
   }
   return AsmPrinter::doFinalization(M);

>From 3178efcf3dc4d536f8df0e50161547a894e610ea Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Sat, 6 Apr 2024 01:21:58 -0400
Subject: [PATCH 08/10] Try and move out all section writing "business" logic
 out from the GOFFObjectWriter - part 1.

---
 llvm/include/llvm/MC/MCContext.h              |   9 ++
 llvm/include/llvm/MC/MCSectionGOFF.h          |  44 ++++++-
 .../CodeGen/TargetLoweringObjectFileImpl.cpp  |  27 +++--
 llvm/lib/MC/GOFFObjectWriter.cpp              | 111 +++++++++---------
 llvm/lib/MC/MCContext.cpp                     |  19 ++-
 5 files changed, 139 insertions(+), 71 deletions(-)

diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 6a1cf36dfb8d8f..cde047110a1deb 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -655,13 +655,22 @@ class MCContext {
 
   MCSectionGOFF *getGOFFLSDASection(StringRef Section, SectionKind Kind);
 
+  MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
+                                GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented,
+                                GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate,
+                                GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial,
+                                GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified,
+                                bool isRooted = false);
+
   MCSectionGOFF *
   getGOFFSection(StringRef Section, SectionKind Kind,
                  MCSection *Parent = nullptr,
                  const MCExpr *SubsectionId = nullptr,
                  GOFF::GOFFSectionType SectionType = GOFF::Other,
                  GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented,
+                 GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate,
                  GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial,
+                 GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified,
                  bool isRooted = false);
 
   MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index 2c0860dadabe11..77e677472e96cf 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -35,27 +35,37 @@ class MCSectionGOFF final : public MCSection {
   const MCExpr *SubsectionId;
   GOFF::GOFFSectionType Type = GOFF::Other;
   GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented;
+  GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate;
   GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial;
+  GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
 
-  /// IsRooted - true iff the SD symbol used to define the GOFF Class this
+  /// IsRooted - True iff the SD symbol used to define the GOFF Class this
   /// MCSectionGOFF represents is the "root" SD symbol.
   bool IsRooted = false;
 
+  /// TextOwnedByED - True if the ED Symbol in the GOFF Class this MCSectionGOFF
+  /// represents is the owner of TXT record. False if the TXT record is owned by
+  /// a LD or PR Symbol.
+  bool TextOwnedByED = false;
+
   friend class MCContext;
   MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub)
       : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub) {}
-
+  
   MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
-                GOFF::ESDTextStyle TextStyle,
-                GOFF::ESDLoadingBehavior LoadBehavior, bool IsRooted)
+                GOFF::ESDTextStyle TextStyle, GOFF::ESDBindingAlgorithm BindAlgorithm,
+                GOFF::ESDLoadingBehavior LoadBehavior, GOFF::ESDBindingScope BindingScope, bool IsRooted)
       : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub),
-        TextStyle(TextStyle), LoadBehavior(LoadBehavior), IsRooted(IsRooted) {}
+        TextStyle(TextStyle), BindAlgorithm(BindAlgorithm), LoadBehavior(LoadBehavior), BindingScope(BindingScope), IsRooted(IsRooted) {}
 
   MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
                 GOFF::GOFFSectionType Type)
       : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub),
         Type(Type) {
-    if (Type == GOFF::GOFFSectionType::PPA2Offset) {
+    if (Type == GOFF::GOFFSectionType::Code) {
+      IsRooted = true;
+    } else if (Type == GOFF::GOFFSectionType::Static) {
+    } else if (Type == GOFF::GOFFSectionType::PPA2Offset) {
       TextStyle = GOFF::ESD_TS_ByteOriented;
     } else if (Type == GOFF::GOFFSectionType::B_IDRL) {
       TextStyle = GOFF::ESD_TS_Structured;
@@ -80,13 +90,35 @@ class MCSectionGOFF final : public MCSection {
   bool isB_IDRL() const { return Type == GOFF::B_IDRL; }
 
   GOFF::ESDTextStyle getTextStyle() const { return TextStyle; }
+  GOFF::ESDBindingAlgorithm getBindingAlgorithm() const { return BindAlgorithm; }
   GOFF::ESDLoadingBehavior getLoadBehavior() const { return LoadBehavior; }
+  GOFF::ESDBindingScope getBindingScope() const { return BindingScope; }
   bool getRooted() const { return IsRooted; }
+  bool isTextOwnedByED() const { return TextOwnedByED; }
 
   MCSection *getParent() const { return Parent; }
   const MCExpr *getSubsectionId() const { return SubsectionId; }
 
   static bool classof(const MCSection *S) { return S->getVariant() == SV_GOFF; }
+
+  // Return the name of the External Definition (ED) used to represent this
+  // MCSectionGOFF in the object file.
+  std::string getExternalDefinitionName() const {
+    switch (Type)
+    {
+      case GOFF::GOFFSectionType::Code:
+        return "C_CODE64";
+      case GOFF::GOFFSectionType::Static:
+        return "C_WSA64";
+      case GOFF::GOFFSectionType::PPA2Offset:
+        return "C_QPPA2";
+      case GOFF::GOFFSectionType::B_IDRL:
+        return "B_IDRL";
+      case GOFF::GOFFSectionType::Other:
+        return "C_WSA64";
+    }
+    return "";
+  }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index b881d5241ac9ac..a6c176486364f3 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2738,20 +2738,29 @@ MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal(
 MCSection *TargetLoweringObjectFileGOFF::getSectionForLSDA(
     const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const {
   std::string Name = ".gcc_exception_table." + F.getName().str();
-  return getContext().getGOFFLSDASection(Name, SectionKind::getData());
+  return getContext().getGOFFLSDASection(Name, SectionKind::getData(),
+                                         GOFF::ESD_TS_ByteOriented,
+                                         GOFF::ESD_BA_Merge,
+                                         GOFF::ESD_LB_Deferred,
+                                         GOFF::ESD_BSC_Section,
+                                         true);
 }
 
 MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
   auto *Symbol = TM.getSymbol(GO);
-  if (Kind.isData())
-    return getContext().getGOFFSection(Symbol->getName(),
-                                       SectionKind::getData());
-
-  if (Kind.isBSS())
-    return getContext().getGOFFSection(Symbol->getName(),
-                                       SectionKind::getBSS());
-
+  if (Kind.isData() || Kind.isBSS()) {
+    auto BindingScope = Symbol.isExternal()
+                          ? (Symbol.isExported() ? GOFF::ESD_BSC_ImportExport
+                                                 : GOFF::ESD_BSC_Library)
+                          : GOFF::ESD_BSC_Section;
+    return getContext().getGOFFSection(Symbol->getName(), Kind,
+                                       GOFF::ESD_TS_ByteOriented,
+                                       GOFF::ESD_BA_Merge,
+                                       GOFF::ESD_LB_Deferred,
+                                       BindingScope,
+                                       false);
+  }
   return getContext().getObjectFileInfo()->getTextSection();
 }
 
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index e5a75461eb21aa..95207fb2151f99 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -341,12 +341,15 @@ class GOFFObjectWriter : public MCObjectWriter {
 
   void writeADAandCodeSectionSymbols(MCAssembler &Asm,
                                      const MCAsmLayout &Layout);
+
+  std::pair<GOFFSymbol, GOFFSymbol> getSDEDSymbolsForSection(const MCSectionGOFF& GSection, const MCAsmLayout Layout);
+
   // Write out all ESD Symbols that own a section. GOFF doesn't have
   // "sections" in the way other object file formats like ELF do; instead
   // a GOFF section is defined as a triple of ESD Symbols (SD, ED, PR/LD).
   // The PR/LD symbol should own a TXT record that contains the actual
   // data of the section.
-  void writeSectionSymbols(MCAssembler &Asm, const MCAsmLayout &Layout);
+  void writeSectionSymbols(const MCSectionGOFF &GSection, MCAssembler &Asm, const MCAsmLayout &Layout);
 
   void writeText(const MCSectionGOFF *MCSec, uint32_t EsdId,
                  GOFF::TXTRecordStyle RecordStyle, MCAssembler &Asm,
@@ -596,8 +599,6 @@ void GOFFObjectWriter::writeSymbolDefinedInModule(const MCSymbolGOFF &Symbol,
                             ? (Symbol.isExported() ? GOFF::ESD_BSC_ImportExport
                                                    : GOFF::ESD_BSC_Library)
                             : GOFF::ESD_BSC_Section;
-    if (!Symbol.isExternal())
-      SD.BindingScope = GOFF::ESD_BSC_Section;
 
     GOFFSymbol ED = createWSASymbol(SD.EsdId);
     uint32_t PRSectionLen = Layout.getSectionAddressSize(&Section)
@@ -906,57 +907,54 @@ void GOFFObjectWriter::writeADAandCodeSectionSymbols(
   writeSymbol(LD, Layout);
 }
 
-void GOFFObjectWriter::writeSectionSymbols(MCAssembler &Asm,
+std::pair<GOFFSymbol, GOFFSymbol> GOFFObjectWriter::getSDEDSymbolsForSection(const MCSectionGOFF& GSection, const MCAsmLayout Layout) {
+  GOFFSymbol SD = GSection.getRooted() ? RootSD : createSDSymbol(GSection.getName());
+
+  GOFFSymbol ED = createEDSymbol(GSection.getExternalDefinitionName(), SD.EsdId, Layout.getSectionAddressSize(&GSection),
+                                 GOFF::ESD_EXE_Unspecified, //TODO: No.
+                                 GSection.getBindingScope(),
+                                 GOFF::ESD_NS_ProgramManagementBinder, //TODO: Definitely fucking not.
+                                 GSection.getBindingAlgorithm(),
+                                 true, //TODO: No. (This is read only btw)
+                                 GSection.getTextStyle(),
+                                 GSection.getLoadBehavior()
+                                 );
+  return std::make_pair(SD, ED);
+}
+
+
+void GOFFObjectWriter::writeSectionSymbols(const MCSectionGOFF &GSection,
+                                           MCAssembler &Asm,
                                            const MCAsmLayout &Layout) {
-  for (MCSection &S : Asm) {
-    auto &Section = cast<MCSectionGOFF>(S);
-    SectionKind Kind = Section.getKind();
-
-    if (Section.isCode()) {
-      // The only text section is the code section and the relevant ESD Records
-      // are already created. All we need to do is populate the SectionMap.
-      uint32_t RootSDEsdId = RootSD.EsdId;
-
-      GOFFSection GoffSec = GOFFSection(EntryEDEsdId, CodeLDEsdId, RootSDEsdId);
-      SectionMap.insert(std::make_pair(&Section, GoffSec));
-    } else if (Section.isPPA2Offset()) {
-      StringRef EDSectionName = "C_@@QPPA2";
-      StringRef PRSectionName = ".&ppa2";
-      GOFFSymbol SD = RootSD;
-      GOFFSymbol ED = createEDSymbol(
-          EDSectionName, SD.EsdId, 0, GOFF::ESD_EXE_DATA,
-          GOFF::ESD_BSC_Unspecified, GOFF::ESD_NS_Parts, GOFF::ESD_BA_Merge,
-          /*ReadOnly*/ true, GOFF::ESD_TS_ByteOriented, GOFF::ESD_LB_Initial);
-      GOFFSymbol PR = createPRSymbol(
-          PRSectionName, ED.EsdId, GOFF::ESD_NS_Parts,
-          GOFF::ESD_EXE_Unspecified, GOFF::ESD_ALIGN_Doubleword,
-          GOFF::ESD_BSC_Section, Layout.getSectionAddressSize(&Section),
-          GOFF::ESD_LB_Initial, GOFF::ESD_LT_OS);
-      writeSymbol(ED, Layout);
-      writeSymbol(PR, Layout);
-
-      GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
-      SectionMap.insert(std::make_pair(&Section, GoffSec));
-    } else if (Section.isB_IDRL()) {
-      GOFFSymbol SD = RootSD;
-      GOFFSymbol ED = createEDSymbol(
-          "B_IDRL", SD.EsdId, Layout.getSectionAddressSize(&Section),
-          GOFF::ESD_EXE_Unspecified, GOFF::ESD_BSC_Module,
-          GOFF::ESD_NS_NormalName, GOFF::ESD_BA_Concatenate,
-          /*ReadOnly*/ true, GOFF::ESD_TS_Structured, GOFF::ESD_LB_NoLoad);
-      writeSymbol(ED, Layout);
-
-      GOFFSection GoffSec = GOFFSection(ED.EsdId, 0, 0);
-      SectionMap.insert(std::make_pair(&Section, GoffSec));
-    } else if (Section.isStatic()) {
-      GOFFSection GoffSec = GOFFSection(ADAPREsdId, ADAPREsdId, RootSD.EsdId);
-      SectionMap.insert(std::make_pair(&Section, GoffSec));
-    } else if (Kind.isBSS() || Kind.isData() || Kind.isThreadData()) {
-      // We handle this with the symbol definition, so there is no need to do
-      // anything here.
-    } else {
-      llvm_unreachable("Unhandled section kind");
-    }
+  bool UsesNewSDSymbol = !(GSection.getRooted());
+  auto SDEDSymbols = getSDEDSymbolsForSection(GSection, Layout);
+  if (UsesNewSDSymbol) {
+    writeSymbol(SDEDSymbols.first, Layout);
+  }
+  writeSymbol(SDEDSymbols.second, Layout);
+
+  if (GSection.isCode()) {
+    GOFFSymbol LD = createLDSymbol(RootSD.Name, SDEDSymbols.second.EsdId);
+    LD.BindingScope = GOFF::ESD_BSC_Section;
+    GOFFSection GoffSec = GOFFSection(LD.EsdId, SDEDSymbols.second.EsdId, SDEDSymbols.first.EsdId);
+    writeSymbol(LD, Layout);
+  } else if (!GSection.isTextOwnedByED()) {
+    MCSymbolGOFF *GSym = nullptr;
+    // TODO: Should be GSection.getTextOwnerName()
+    GOFFSymbol PR = createPRSymbol(GSection.getName(), SDEDSymbols.second.EsdId,
+                                   GOFF::ESD_NS_Parts,
+                                   GOFF::ESD_EXE_DATA,
+                                   GOFFSymbol::setGOFFAlignment(GSection.getAlign()),
+                                   GOFF::ESD_BSC_Section,
+                                   Layout.getSectionAddressSize(&GSection),
+                                   GSection.getLoadBehavior(),
+                                   GSym->isOSLinkage() ? GOFF::ESD_LT_OS : GOFF::ESD_LT_XPLink);
+    writeSymbol(PR, Layout);
+    GOFFSection GoffSec = GOFFSection(PR.EsdId, SDEDSymbols.second.EsdId, SDEDSymbols.first.EsdId);
+    SectionMap.insert(std::make_pair(&GSection, GoffSec));
+  } else {
+    GOFFSection GoffSec = GOFFSection(SDEDSymbols.second.EsdId, 0, SDEDSymbols.first.EsdId);
+    SectionMap.insert(std::make_pair(&GSection, GoffSec));
   }
 }
 
@@ -1058,8 +1056,15 @@ uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
   writeHeader();
   writeSymbol(RootSD, Layout);
 
+  /*
   writeADAandCodeSectionSymbols(Asm, Layout);
   writeSectionSymbols(Asm, Layout);
+  */
+  for (MCSection &S : Asm) {
+    auto &GSection = cast<MCSectionGOFF>(S);
+    if (!(GSection.isCode() || GSection.isStatic()))
+      writeSectionSymbols(GSection, Asm, Layout);
+  }
 
   // Process all MCSymbols and generate the ESD Record(s) for them.
   // Symbols that are aliases of other symbols need to be processed
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 567adfab3dca2f..5d82f88c3aca25 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -654,16 +654,29 @@ MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
 MCSectionGOFF *MCContext::getGOFFLSDASection(StringRef Section,
                                              SectionKind Kind) {
   return getGOFFSection(Section, Kind, nullptr, nullptr,
-                        GOFF::GOFFSectionType::Other, GOFF::ESD_TS_Unstructured,
-                        GOFF::ESD_LB_Deferred, true);
+                        GOFF::GOFFSectionType::Other, GOFF::ESD_TS_Unstructured, GOFF::ESD_BA_Merge,
+                        GOFF::ESD_LB_Deferred, GOFF::ESD_BSC_Section, true);
 }
 
+MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
+                                         GOFF::ESDTextStyle TextStyle,
+                                         GOFF::ESDBindingAlgorithm BindAlgorithm,
+                                         GOFF::ESDLoadingBehavior LoadBehavior,
+                                         GOFF::ESDBindingScope BindingScope,
+                                         bool isRooted) {
+  return getGOFFSection(Section, Kind, nullptr, nullptr, GOFF::GOFFSectionType::Other,
+  TextStyle, BindAlgorithm, LoadBehavior, BindingScope, isRooted);
+}
+
+
 MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
                                          MCSection *Parent,
                                          const MCExpr *SubsectionId,
                                          GOFF::GOFFSectionType SectionType,
                                          GOFF::ESDTextStyle TextStyle,
+                                         GOFF::ESDBindingAlgorithm BindAlgorithm,
                                          GOFF::ESDLoadingBehavior LoadBehavior,
+                                         GOFF::ESDBindingScope BindingScope,
                                          bool isRooted) {
   // Do the lookup. If we don't have a hit, return a new section.
   auto IterBool = GOFFUniquingMap.insert(std::make_pair(
@@ -680,7 +693,7 @@ MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
         MCSectionGOFF(CachedName, Kind, Parent, SubsectionId, SectionType);
   else
     GOFFSection = new (GOFFAllocator.Allocate())
-        MCSectionGOFF(CachedName, Kind, Parent, SubsectionId);
+        MCSectionGOFF(CachedName, Kind, Parent, SubsectionId, TextStyle, BindAlgorithm, LoadBehavior, BindingScope, isRooted);
   Iter->second = GOFFSection;
 
   return GOFFSection;

>From e6e738bfe74333ffb3151714a6a7bd19725b3b49 Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Sat, 6 Apr 2024 02:12:39 -0400
Subject: [PATCH 09/10] Added the symbol to the MCSectionGOFF. Now we might
 even be able to write the global variables out along with all other sections.
 Crazy.

---
 llvm/include/llvm/MC/MCContext.h              |  8 ++--
 llvm/include/llvm/MC/MCSectionGOFF.h          | 39 ++++++++++++++++++-
 .../CodeGen/TargetLoweringObjectFileImpl.cpp  |  8 ++--
 llvm/lib/MC/GOFFObjectWriter.cpp              | 17 ++++----
 llvm/lib/MC/MCContext.cpp                     | 16 ++------
 5 files changed, 58 insertions(+), 30 deletions(-)

diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index cde047110a1deb..00ea10ff1c70dc 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -62,6 +62,7 @@ class MCStreamer;
 class MCSubtargetInfo;
 class MCSymbol;
 class MCSymbolELF;
+class MCSymbolGOFF;
 class MCSymbolWasm;
 class MCSymbolXCOFF;
 class MCTargetOptions;
@@ -653,14 +654,13 @@ class MCContext {
                                                    unsigned Flags,
                                                    unsigned EntrySize);
 
-  MCSectionGOFF *getGOFFLSDASection(StringRef Section, SectionKind Kind);
-
   MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
                                 GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented,
                                 GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate,
                                 GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial,
                                 GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified,
-                                bool isRooted = false);
+                                bool isRooted = false,
+                                MCSymbolGOFF *TextOwner = nullptr);
 
   MCSectionGOFF *
   getGOFFSection(StringRef Section, SectionKind Kind,
@@ -671,7 +671,7 @@ class MCContext {
                  GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate,
                  GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial,
                  GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified,
-                 bool isRooted = false);
+                 bool isRooted = false, MCSymbolGOFF * TextOwner = nullptr);
 
   MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
                                 SectionKind Kind, StringRef COMDATSymName,
diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index 77e677472e96cf..716552c28cd6f7 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -24,6 +24,7 @@
 
 #include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSymbolGOFF.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace llvm {
@@ -48,15 +49,20 @@ class MCSectionGOFF final : public MCSection {
   /// a LD or PR Symbol.
   bool TextOwnedByED = false;
 
+  /// TextOwner - Valid if owned the text record containing the body of this section
+  /// is not owned by an ED Symbol. The MCSymbol that represents the part or label that
+  /// actually owns the TXT Record.
+  MCSymbolGOFF *TextOwner = nullptr;
+
   friend class MCContext;
   MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub)
       : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub) {}
   
   MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
                 GOFF::ESDTextStyle TextStyle, GOFF::ESDBindingAlgorithm BindAlgorithm,
-                GOFF::ESDLoadingBehavior LoadBehavior, GOFF::ESDBindingScope BindingScope, bool IsRooted)
+                GOFF::ESDLoadingBehavior LoadBehavior, GOFF::ESDBindingScope BindingScope, bool IsRooted, MCSymbolGOFF *TextOwner)
       : MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub),
-        TextStyle(TextStyle), BindAlgorithm(BindAlgorithm), LoadBehavior(LoadBehavior), BindingScope(BindingScope), IsRooted(IsRooted) {}
+        TextStyle(TextStyle), BindAlgorithm(BindAlgorithm), LoadBehavior(LoadBehavior), BindingScope(BindingScope), IsRooted(IsRooted), TextOwner(TextOwner) {}
 
   MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
                 GOFF::GOFFSectionType Type)
@@ -64,10 +70,17 @@ class MCSectionGOFF final : public MCSection {
         Type(Type) {
     if (Type == GOFF::GOFFSectionType::Code) {
       IsRooted = true;
+      TextOwnedByED = true;
     } else if (Type == GOFF::GOFFSectionType::Static) {
+      IsRooted = true;
+      TextOwnedByED = false;
     } else if (Type == GOFF::GOFFSectionType::PPA2Offset) {
+      IsRooted = true;
+      TextOwnedByED = false;
       TextStyle = GOFF::ESD_TS_ByteOriented;
     } else if (Type == GOFF::GOFFSectionType::B_IDRL) {
+      IsRooted = true;
+      TextOwnedByED = true;
       TextStyle = GOFF::ESD_TS_Structured;
       LoadBehavior = GOFF::ESD_LB_NoLoad;
     }
@@ -119,6 +132,28 @@ class MCSectionGOFF final : public MCSection {
     }
     return "";
   }
+
+  std::optional<MCSymbolGOFF *> getTextOwner() const {
+    if (TextOwnedByED)
+      return std::nullopt;
+    else if (TextOwner)
+      return TextOwner;
+    return std::nullopt;
+  }
+
+  std::string getTextOwnerName() const {
+    if (TextOwnedByED)
+      return getExternalDefinitionName();
+    else if (Type == GOFF::Static)
+      return "";
+    else if (Type == GOFF::PPA2Offset)
+      return ".&ppa2";
+    else if (Type == GOFF::Other) {
+      if (TextOwner)
+        return TextOwner->getName().str();
+    }
+    return getName().str();
+  }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index a6c176486364f3..b60961c5f782b1 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2738,17 +2738,17 @@ MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal(
 MCSection *TargetLoweringObjectFileGOFF::getSectionForLSDA(
     const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const {
   std::string Name = ".gcc_exception_table." + F.getName().str();
-  return getContext().getGOFFLSDASection(Name, SectionKind::getData(),
+  return getContext().getGOFFSection(Name, SectionKind::getData(),
                                          GOFF::ESD_TS_ByteOriented,
                                          GOFF::ESD_BA_Merge,
                                          GOFF::ESD_LB_Deferred,
                                          GOFF::ESD_BSC_Section,
-                                         true);
+                                         true, &FnSym);
 }
 
 MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
-  auto *Symbol = TM.getSymbol(GO);
+  auto *Symbol = cast<MCSymbolGOFF *>(TM.getSymbol(GO));
   if (Kind.isData() || Kind.isBSS()) {
     auto BindingScope = Symbol.isExternal()
                           ? (Symbol.isExported() ? GOFF::ESD_BSC_ImportExport
@@ -2759,7 +2759,7 @@ MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
                                        GOFF::ESD_BA_Merge,
                                        GOFF::ESD_LB_Deferred,
                                        BindingScope,
-                                       false);
+                                       false, Symbol);
   }
   return getContext().getObjectFileInfo()->getTextSection();
 }
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index 95207fb2151f99..d16951fce5729a 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -939,16 +939,21 @@ void GOFFObjectWriter::writeSectionSymbols(const MCSectionGOFF &GSection,
     GOFFSection GoffSec = GOFFSection(LD.EsdId, SDEDSymbols.second.EsdId, SDEDSymbols.first.EsdId);
     writeSymbol(LD, Layout);
   } else if (!GSection.isTextOwnedByED()) {
-    MCSymbolGOFF *GSym = nullptr;
-    // TODO: Should be GSection.getTextOwnerName()
-    GOFFSymbol PR = createPRSymbol(GSection.getName(), SDEDSymbols.second.EsdId,
+    auto GSym = GSection.getTextOwner();
+    GOFF::ESDExecutable Executability = GOFF::ESD_EXE_DATA;
+    bool IsOSLinkage = false;
+    if (GSym.has_value()) {
+      Executability = GSym.value()->getExecutable();
+      IsOSLinkage = GSym.value()->isOSLinkage();
+    }
+    GOFFSymbol PR = createPRSymbol(GSection.getTextOwnerName(), SDEDSymbols.second.EsdId,
                                    GOFF::ESD_NS_Parts,
                                    GOFF::ESD_EXE_DATA,
                                    GOFFSymbol::setGOFFAlignment(GSection.getAlign()),
                                    GOFF::ESD_BSC_Section,
                                    Layout.getSectionAddressSize(&GSection),
                                    GSection.getLoadBehavior(),
-                                   GSym->isOSLinkage() ? GOFF::ESD_LT_OS : GOFF::ESD_LT_XPLink);
+                                   IsOSLinkage ? GOFF::ESD_LT_OS : GOFF::ESD_LT_XPLink);
     writeSymbol(PR, Layout);
     GOFFSection GoffSec = GOFFSection(PR.EsdId, SDEDSymbols.second.EsdId, SDEDSymbols.first.EsdId);
     SectionMap.insert(std::make_pair(&GSection, GoffSec));
@@ -1056,10 +1061,6 @@ uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
   writeHeader();
   writeSymbol(RootSD, Layout);
 
-  /*
-  writeADAandCodeSectionSymbols(Asm, Layout);
-  writeSectionSymbols(Asm, Layout);
-  */
   for (MCSection &S : Asm) {
     auto &GSection = cast<MCSectionGOFF>(S);
     if (!(GSection.isCode() || GSection.isStatic()))
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 5d82f88c3aca25..1b653e4bdf3e1b 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -651,24 +651,16 @@ MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
                                       : std::nullopt;
 }
 
-MCSectionGOFF *MCContext::getGOFFLSDASection(StringRef Section,
-                                             SectionKind Kind) {
-  return getGOFFSection(Section, Kind, nullptr, nullptr,
-                        GOFF::GOFFSectionType::Other, GOFF::ESD_TS_Unstructured, GOFF::ESD_BA_Merge,
-                        GOFF::ESD_LB_Deferred, GOFF::ESD_BSC_Section, true);
-}
-
 MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
                                          GOFF::ESDTextStyle TextStyle,
                                          GOFF::ESDBindingAlgorithm BindAlgorithm,
                                          GOFF::ESDLoadingBehavior LoadBehavior,
                                          GOFF::ESDBindingScope BindingScope,
-                                         bool isRooted) {
+                                         bool isRooted, MCSymbolGOFF *TextOwner) {
   return getGOFFSection(Section, Kind, nullptr, nullptr, GOFF::GOFFSectionType::Other,
-  TextStyle, BindAlgorithm, LoadBehavior, BindingScope, isRooted);
+  TextStyle, BindAlgorithm, LoadBehavior, BindingScope, isRooted, TextOwner);
 }
 
-
 MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
                                          MCSection *Parent,
                                          const MCExpr *SubsectionId,
@@ -677,7 +669,7 @@ MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
                                          GOFF::ESDBindingAlgorithm BindAlgorithm,
                                          GOFF::ESDLoadingBehavior LoadBehavior,
                                          GOFF::ESDBindingScope BindingScope,
-                                         bool isRooted) {
+                                         bool isRooted, MCSymbolGOFF *TextOwner) {
   // Do the lookup. If we don't have a hit, return a new section.
   auto IterBool = GOFFUniquingMap.insert(std::make_pair(
       GOFFSectionKey{Section.str(), SectionType, (Parent != nullptr)},
@@ -693,7 +685,7 @@ MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
         MCSectionGOFF(CachedName, Kind, Parent, SubsectionId, SectionType);
   else
     GOFFSection = new (GOFFAllocator.Allocate())
-        MCSectionGOFF(CachedName, Kind, Parent, SubsectionId, TextStyle, BindAlgorithm, LoadBehavior, BindingScope, isRooted);
+        MCSectionGOFF(CachedName, Kind, Parent, SubsectionId, TextStyle, BindAlgorithm, LoadBehavior, BindingScope, isRooted, TextOwner);
   Iter->second = GOFFSection;
 
   return GOFFSection;

>From 2976931faa56f8de56de2fafb26321a7078c0f5d Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Sat, 6 Apr 2024 18:47:45 -0400
Subject: [PATCH 10/10] Properly do the remaining ED fields

---
 llvm/include/llvm/MC/MCSectionGOFF.h | 8 ++++++++
 llvm/lib/MC/GOFFObjectWriter.cpp     | 8 ++++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index 716552c28cd6f7..a6cbfd23171973 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -154,6 +154,14 @@ class MCSectionGOFF final : public MCSection {
     }
     return getName().str();
   }
+
+  bool isReadOnly() const {
+    return isCode() || isPPA2Offset() || isB_IDRL();
+  }
+
+  GOFF::ESDNameSpaceId getNameSpace() const {
+    return isB_IDRL() ? GOFF::ESD_NS_NormalName : GOFF::ESD_NS_Parts;
+  }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index d16951fce5729a..fedd12c3eca7c5 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -911,11 +911,11 @@ std::pair<GOFFSymbol, GOFFSymbol> GOFFObjectWriter::getSDEDSymbolsForSection(con
   GOFFSymbol SD = GSection.getRooted() ? RootSD : createSDSymbol(GSection.getName());
 
   GOFFSymbol ED = createEDSymbol(GSection.getExternalDefinitionName(), SD.EsdId, Layout.getSectionAddressSize(&GSection),
-                                 GOFF::ESD_EXE_Unspecified, //TODO: No.
+                                 GSection.isCode() ? GOFF::ESD_EXE_CODE : GOFF::ESD_EXE_DATA,
                                  GSection.getBindingScope(),
-                                 GOFF::ESD_NS_ProgramManagementBinder, //TODO: Definitely fucking not.
+                                 GSection.getNameSpace(),
                                  GSection.getBindingAlgorithm(),
-                                 true, //TODO: No. (This is read only btw)
+                                 GSection.isReadOnly(),
                                  GSection.getTextStyle(),
                                  GSection.getLoadBehavior()
                                  );
@@ -948,7 +948,7 @@ void GOFFObjectWriter::writeSectionSymbols(const MCSectionGOFF &GSection,
     }
     GOFFSymbol PR = createPRSymbol(GSection.getTextOwnerName(), SDEDSymbols.second.EsdId,
                                    GOFF::ESD_NS_Parts,
-                                   GOFF::ESD_EXE_DATA,
+                                   Executability,
                                    GOFFSymbol::setGOFFAlignment(GSection.getAlign()),
                                    GOFF::ESD_BSC_Section,
                                    Layout.getSectionAddressSize(&GSection),



More information about the llvm-commits mailing list