[llvm] 33872f1 - [GOFF] Add writing of section symbols (#133799)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 26 08:52:18 PDT 2025


Author: Kai Nacke
Date: 2025-06-26T11:52:14-04:00
New Revision: 33872f12187b352b63e1749652cb18e678fc4f29

URL: https://github.com/llvm/llvm-project/commit/33872f12187b352b63e1749652cb18e678fc4f29
DIFF: https://github.com/llvm/llvm-project/commit/33872f12187b352b63e1749652cb18e678fc4f29.diff

LOG: [GOFF] Add writing of section symbols (#133799)

Unlike other formats, the GOFF object file format uses a 2 dimensional structure
to define the location of data. For example, the equivalent of the ELF .text
section is made up of a Section Definition (SD) and a class (Element Definition;
ED). The name of the SD symbol depends on the application, while the class has
the predefined name C_CODE/C_CODE64 in AMODE31 and AMODE64 respectively.

Data can be placed into this structure in 2 ways. First, the data (in a text
record) can be associated with an ED symbol. To refer to data, a Label
Definition (LD) is used to give an offset into the data a name. When binding,
the whole data is pulled into the resulting executable, and the addresses
given by the LD symbols are resolved.

The alternative is to use a Part Definition (PR). In this case, the data (in
a text record) is associated with the part. When binding, only the data of
referenced PRs is pulled into the resulting binary.

Both approaches are used. SD, ED, and PR elements are modeled by nested
MCSectionGOFF instances, while LD elements are associated with MCSymbolGOFF
instances.

At the binary level, a record called "External Symbol Definition" (ESD) is used. The
ESD has a type (SD, ED, PR, LD), and depending on the type a different subset of
the fields is used.

Added: 
    llvm/include/llvm/MC/MCGOFFAttributes.h
    llvm/lib/MC/MCSectionGOFF.cpp
    llvm/test/CodeGen/SystemZ/zos-ppa1.ll
    llvm/test/CodeGen/SystemZ/zos-section-1.ll
    llvm/test/CodeGen/SystemZ/zos-section-2.ll

Modified: 
    llvm/include/llvm/BinaryFormat/GOFF.h
    llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
    llvm/include/llvm/MC/MCContext.h
    llvm/include/llvm/MC/MCGOFFStreamer.h
    llvm/include/llvm/MC/MCObjectFileInfo.h
    llvm/include/llvm/MC/MCSectionGOFF.h
    llvm/include/llvm/MC/MCSymbolGOFF.h
    llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/lib/MC/CMakeLists.txt
    llvm/lib/MC/GOFFObjectWriter.cpp
    llvm/lib/MC/MCContext.cpp
    llvm/lib/MC/MCGOFFStreamer.cpp
    llvm/lib/MC/MCObjectFileInfo.cpp
    llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
    llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll
    llvm/test/CodeGen/SystemZ/zos-intrinsics.ll
    llvm/test/CodeGen/SystemZ/zos-landingpad.ll
    llvm/test/CodeGen/SystemZ/zos-ppa2.ll
    llvm/test/CodeGen/SystemZ/zos-simple-test.ll
    llvm/test/MC/GOFF/empty-goff.s

Removed: 
    llvm/test/MC/GOFF/ppa1.ll


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h
index 443bcfc9479a8..49d2809cb6524 100644
--- a/llvm/include/llvm/BinaryFormat/GOFF.h
+++ b/llvm/include/llvm/BinaryFormat/GOFF.h
@@ -169,6 +169,91 @@ enum SubsectionKind : uint8_t {
   SK_PPA1 = 2,
   SK_PPA2 = 4,
 };
+
+// The standard System/390 convention is to name the high-order (leftmost) bit
+// in a byte as bit zero. The Flags type helps to set bits in byte according
+// to this numeration order.
+class Flags {
+  uint8_t Val = 0;
+
+  constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value,
+                                uint8_t OldValue) {
+    uint8_t Pos = 8 - BitIndex - Length;
+    uint8_t Mask = ((1 << Length) - 1) << Pos;
+    Value = Value << Pos;
+    return (OldValue & ~Mask) | Value;
+  }
+
+public:
+  constexpr Flags() = default;
+  constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value)
+      : Val(bits(BitIndex, Length, Value, 0)) {}
+
+  template <typename T>
+  constexpr void set(uint8_t BitIndex, uint8_t Length, T NewValue) {
+    Val = bits(BitIndex, Length, static_cast<uint8_t>(NewValue), Val);
+  }
+
+  template <typename T>
+  constexpr T get(uint8_t BitIndex, uint8_t Length) const {
+    return static_cast<T>((Val >> (8 - BitIndex - Length)) &
+                          ((1 << Length) - 1));
+  }
+
+  constexpr operator uint8_t() const { return Val; }
+};
+
+// Structure for the flag field of a symbol. See
+// https://www.ibm.com/docs/en/zos/3.1.0?topic=formats-external-symbol-definition-record
+// at offset 41 for the definition.
+struct SymbolFlags {
+  Flags SymFlags;
+
+#define GOFF_SYMBOL_FLAG(NAME, TYPE, BITINDEX, LENGTH)                         \
+  void set##NAME(TYPE Val) { SymFlags.set<TYPE>(BITINDEX, LENGTH, Val); }      \
+  TYPE get##NAME() const { return SymFlags.get<TYPE>(BITINDEX, LENGTH); }
+
+  GOFF_SYMBOL_FLAG(FillBytePresence, bool, 0, 1)
+  GOFF_SYMBOL_FLAG(Mangled, bool, 1, 1)
+  GOFF_SYMBOL_FLAG(Renameable, bool, 2, 1)
+  GOFF_SYMBOL_FLAG(RemovableClass, bool, 3, 1)
+  GOFF_SYMBOL_FLAG(ReservedQwords, ESDReserveQwords, 5, 3)
+
+#undef GOFF_SYMBOL_FLAG
+
+  constexpr operator uint8_t() const { return static_cast<uint8_t>(SymFlags); }
+};
+
+// Structure for the behavioral attributes. See
+// https://www.ibm.com/docs/en/zos/3.1.0?topic=record-external-symbol-definition-behavioral-attributes
+// for the definition.
+struct BehavioralAttributes {
+  Flags Attr[10];
+
+#define GOFF_BEHAVIORAL_ATTRIBUTE(NAME, TYPE, ATTRIDX, BITINDEX, LENGTH)       \
+  void set##NAME(TYPE Val) { Attr[ATTRIDX].set<TYPE>(BITINDEX, LENGTH, Val); } \
+  TYPE get##NAME() const { return Attr[ATTRIDX].get<TYPE>(BITINDEX, LENGTH); }
+
+  GOFF_BEHAVIORAL_ATTRIBUTE(Amode, GOFF::ESDAmode, 0, 0, 8)
+  GOFF_BEHAVIORAL_ATTRIBUTE(Rmode, GOFF::ESDRmode, 1, 0, 8)
+  GOFF_BEHAVIORAL_ATTRIBUTE(TextStyle, GOFF::ESDTextStyle, 2, 0, 4)
+  GOFF_BEHAVIORAL_ATTRIBUTE(BindingAlgorithm, GOFF::ESDBindingAlgorithm, 2, 4,
+                            4)
+  GOFF_BEHAVIORAL_ATTRIBUTE(TaskingBehavior, GOFF::ESDTaskingBehavior, 3, 0, 3)
+  GOFF_BEHAVIORAL_ATTRIBUTE(ReadOnly, bool, 3, 4, 1)
+  GOFF_BEHAVIORAL_ATTRIBUTE(Executable, GOFF::ESDExecutable, 3, 5, 3)
+  GOFF_BEHAVIORAL_ATTRIBUTE(DuplicateSymbolSeverity,
+                            GOFF::ESDDuplicateSymbolSeverity, 4, 2, 2)
+  GOFF_BEHAVIORAL_ATTRIBUTE(BindingStrength, GOFF::ESDBindingStrength, 4, 4, 4)
+  GOFF_BEHAVIORAL_ATTRIBUTE(LoadingBehavior, GOFF::ESDLoadingBehavior, 5, 0, 2)
+  GOFF_BEHAVIORAL_ATTRIBUTE(COMMON, bool, 5, 2, 1)
+  GOFF_BEHAVIORAL_ATTRIBUTE(IndirectReference, bool, 5, 3, 1)
+  GOFF_BEHAVIORAL_ATTRIBUTE(BindingScope, GOFF::ESDBindingScope, 5, 4, 4)
+  GOFF_BEHAVIORAL_ATTRIBUTE(LinkageType, GOFF::ESDLinkageType, 6, 2, 1)
+  GOFF_BEHAVIORAL_ATTRIBUTE(Alignment, GOFF::ESDAlignment, 6, 3, 5)
+
+#undef GOFF_BEHAVIORAL_ATTRIBUTE
+};
 } // end namespace GOFF
 
 } // end namespace llvm

diff  --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index 00e681e6bf53e..fe450b3c1a3a2 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -316,10 +316,15 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile {
 };
 
 class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile {
+  std::string DefaultRootSDName;
+  std::string DefaultADAPRName;
+
 public:
   TargetLoweringObjectFileGOFF();
   ~TargetLoweringObjectFileGOFF() override = default;
 
+  void getModuleMetadata(Module &M) override;
+
   MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
                                     const TargetMachine &TM) const override;
   MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,

diff  --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 76a750db3fa17..50085c436c63c 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -19,8 +19,10 @@
 #include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/MC/MCAsmMacro.h"
 #include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCGOFFAttributes.h"
 #include "llvm/MC/MCPseudoProbe.h"
 #include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionGOFF.h"
 #include "llvm/MC/MCSymbolTableEntry.h"
 #include "llvm/MC/SectionKind.h"
 #include "llvm/Support/Allocator.h"
@@ -54,7 +56,6 @@ class MCSection;
 class MCSectionCOFF;
 class MCSectionDXContainer;
 class MCSectionELF;
-class MCSectionGOFF;
 class MCSectionMachO;
 class MCSectionSPIRV;
 class MCSectionWasm;
@@ -356,6 +357,10 @@ class MCContext {
   MCSymbolXCOFF *createXCOFFSymbolImpl(const MCSymbolTableEntry *Name,
                                        bool IsTemporary);
 
+  template <typename TAttr>
+  MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
+                                TAttr SDAttributes, MCSection *Parent);
+
   /// Map of currently defined macros.
   StringMap<MCAsmMacro> MacroMap;
 
@@ -606,9 +611,12 @@ class MCContext {
   getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
                            unsigned EntrySize);
 
-  LLVM_ABI MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
-                                         MCSection *Parent,
-                                         uint32_t Subsection = 0);
+  MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
+                                GOFF::SDAttr SDAttributes);
+  MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
+                                GOFF::EDAttr EDAttributes, MCSection *Parent);
+  MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name,
+                                GOFF::PRAttr PRAttributes, MCSection *Parent);
 
   LLVM_ABI MCSectionCOFF *
   getCOFFSection(StringRef Section, unsigned Characteristics,

diff  --git a/llvm/include/llvm/MC/MCGOFFAttributes.h b/llvm/include/llvm/MC/MCGOFFAttributes.h
new file mode 100644
index 0000000000000..c996f0cae2c69
--- /dev/null
+++ b/llvm/include/llvm/MC/MCGOFFAttributes.h
@@ -0,0 +1,92 @@
+//===- MCGOFFAttributes.h - Attributes of GOFF symbols --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the various attribute collections defining GOFF symbols.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCGOFFATTRIBUTES_H
+#define LLVM_MC_MCGOFFATTRIBUTES_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include <cstdint>
+
+namespace llvm {
+namespace GOFF {
+// An "External Symbol Definition" in the GOFF file has a type, and depending on
+// the type a 
diff erent subset of the fields is used.
+//
+// Unlike other formats, a 2 dimensional structure is used to define the
+// location of data. For example, the equivalent of the ELF .text section is
+// made up of a Section Definition (SD) and a class (Element Definition; ED).
+// The name of the SD symbol depends on the application, while the class has the
+// predefined name C_CODE/C_CODE64 in AMODE31 and AMODE64 respectively.
+//
+// Data can be placed into this structure in 2 ways. First, the data (in a text
+// record) can be associated with an ED symbol. To refer to data, a Label
+// Definition (LD) is used to give an offset into the data a name. When binding,
+// the whole data is pulled into the resulting executable, and the addresses
+// given by the LD symbols are resolved.
+//
+// The alternative is to use a Part Definition (PR). In this case, the data (in
+// a text record) is associated with the part. When binding, only the data of
+// referenced PRs is pulled into the resulting binary.
+//
+// Both approaches are used. SD, ED, and PR elements are modelled by nested
+// MCSectionGOFF instances, while LD elements are associated with MCSymbolGOFF
+// instances.
+
+// Attributes for SD symbols.
+struct SDAttr {
+  GOFF::ESDTaskingBehavior TaskingBehavior = GOFF::ESD_TA_Unspecified;
+  GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
+};
+
+// Attributes for ED symbols.
+struct EDAttr {
+  bool IsReadOnly = false;
+  GOFF::ESDRmode Rmode;
+  GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_NormalName;
+  GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented;
+  GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate;
+  GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial;
+  GOFF::ESDReserveQwords ReservedQwords = GOFF::ESD_RQ_0;
+  GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Doubleword;
+  uint8_t FillByteValue = 0;
+};
+
+// Attributes for LD symbols.
+struct LDAttr {
+  bool IsRenamable = false;
+  GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
+  GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong;
+  GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
+  GOFF::ESDAmode Amode;
+  GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
+};
+
+// Attributes for PR symbols.
+struct PRAttr {
+  bool IsRenamable = false;
+  GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified;
+  GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink;
+  GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified;
+  uint32_t SortKey = 0;
+};
+
+// Predefined GOFF class names.
+constexpr StringLiteral CLASS_CODE = "C_CODE64";
+constexpr StringLiteral CLASS_WSA = "C_WSA64";
+constexpr StringLiteral CLASS_DATA = "C_DATA64";
+constexpr StringLiteral CLASS_PPA2 = "C_@@QPPA2";
+
+} // namespace GOFF
+} // namespace llvm
+
+#endif

diff  --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h
index 28202f634f95a..b89d516e1452b 100644
--- a/llvm/include/llvm/MC/MCGOFFStreamer.h
+++ b/llvm/include/llvm/MC/MCGOFFStreamer.h
@@ -16,6 +16,7 @@ namespace llvm {
 class GOFFObjectWriter;
 
 class MCGOFFStreamer : public MCObjectStreamer {
+
 public:
   MCGOFFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
                  std::unique_ptr<MCObjectWriter> OW,
@@ -25,6 +26,8 @@ class MCGOFFStreamer : public MCObjectStreamer {
 
   ~MCGOFFStreamer() override;
 
+  void changeSection(MCSection *Section, uint32_t Subsection = 0) override;
+
   GOFFObjectWriter &getWriter();
 
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {

diff  --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h
index 20c819bdfd961..5ce58ae0a836f 100644
--- a/llvm/include/llvm/MC/MCObjectFileInfo.h
+++ b/llvm/include/llvm/MC/MCObjectFileInfo.h
@@ -231,8 +231,6 @@ class LLVM_ABI MCObjectFileInfo {
   MCSection *GLJMPSection = nullptr;
 
   // GOFF specific sections.
-  MCSection *PPA1Section = nullptr;
-  MCSection *PPA2Section = nullptr;
   MCSection *PPA2ListSection = nullptr;
   MCSection *ADASection = nullptr;
   MCSection *IDRLSection = nullptr;
@@ -439,8 +437,6 @@ class LLVM_ABI MCObjectFileInfo {
   MCSection *getGLJMPSection() const { return GLJMPSection; }
 
   // GOFF specific sections.
-  MCSection *getPPA1Section() const { return PPA1Section; }
-  MCSection *getPPA2Section() const { return PPA2Section; }
   MCSection *getPPA2ListSection() const { return PPA2ListSection; }
   MCSection *getADASection() const { return ADASection; }
   MCSection *getIDRLSection() const { return IDRLSection; }

diff  --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index 11c0f95364037..b8b8cf112a34d 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -16,7 +16,9 @@
 #define LLVM_MC_MCSECTIONGOFF_H
 
 #include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/MC/MCGOFFAttributes.h"
 #include "llvm/MC/MCSection.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace llvm {
@@ -24,26 +26,85 @@ namespace llvm {
 class MCExpr;
 
 class MCSectionGOFF final : public MCSection {
-private:
-  MCSection *Parent;
-  uint32_t Subsection;
+  // Parent of this section. Implies that the parent is emitted first.
+  MCSectionGOFF *Parent;
+
+  // The attributes of the GOFF symbols.
+  union {
+    GOFF::SDAttr SDAttributes;
+    GOFF::EDAttr EDAttributes;
+    GOFF::PRAttr PRAttributes;
+  };
+
+  // The type of this section.
+  GOFF::ESDSymbolType SymbolType;
+
+  // Indicates that the PR symbol needs to set the length of the section to a
+  // non-zero value. This is only a problem with the ADA PR - the binder will
+  // generate an error in this case.
+  unsigned RequiresNonZeroLength : 1;
+
+  // Set to true if the section definition was already emitted.
+  mutable unsigned Emitted : 1;
 
   friend class MCContext;
-  MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, uint32_t Sub)
+  friend class MCSymbolGOFF;
+
+  MCSectionGOFF(StringRef Name, SectionKind K, GOFF::SDAttr SDAttributes,
+                MCSectionGOFF *Parent)
+      : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
+        Parent(Parent), SDAttributes(SDAttributes),
+        SymbolType(GOFF::ESD_ST_SectionDefinition), RequiresNonZeroLength(0),
+        Emitted(0) {}
+
+  MCSectionGOFF(StringRef Name, SectionKind K, GOFF::EDAttr EDAttributes,
+                MCSectionGOFF *Parent)
+      : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
+        Parent(Parent), EDAttributes(EDAttributes),
+        SymbolType(GOFF::ESD_ST_ElementDefinition), RequiresNonZeroLength(0),
+        Emitted(0) {}
+
+  MCSectionGOFF(StringRef Name, SectionKind K, GOFF::PRAttr PRAttributes,
+                MCSectionGOFF *Parent)
       : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr),
-        Parent(P), Subsection(Sub) {}
+        Parent(Parent), PRAttributes(PRAttributes),
+        SymbolType(GOFF::ESD_ST_PartReference), RequiresNonZeroLength(0),
+        Emitted(0) {}
 
 public:
   void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
                             raw_ostream &OS,
-                            uint32_t /*Subsection*/) const override {
-    OS << "\t.section\t\"" << getName() << "\"\n";
-  }
+                            uint32_t Subsection) const override;
 
   bool useCodeAlign() const override { return false; }
 
-  MCSection *getParent() const { return Parent; }
-  uint32_t getSubsection() const { return Subsection; }
+  // Return the parent section.
+  MCSectionGOFF *getParent() const { return Parent; }
+
+  // Returns the type of this section.
+  GOFF::ESDSymbolType getSymbolType() const { return SymbolType; }
+
+  bool isSD() const { return SymbolType == GOFF::ESD_ST_SectionDefinition; }
+  bool isED() const { return SymbolType == GOFF::ESD_ST_ElementDefinition; }
+  bool isPR() const { return SymbolType == GOFF::ESD_ST_PartReference; }
+
+  // Accessors to the attributes.
+  GOFF::SDAttr getSDAttributes() const {
+    assert(isSD() && "Not a SD section");
+    return SDAttributes;
+  }
+  GOFF::EDAttr getEDAttributes() const {
+    assert(isED() && "Not a ED section");
+    return EDAttributes;
+  }
+  GOFF::PRAttr getPRAttributes() const {
+    assert(isPR() && "Not a PR section");
+    return PRAttributes;
+  }
+
+  bool requiresNonZeroLength() const { return RequiresNonZeroLength; }
+
+  void setName(StringRef SectionName) { Name = SectionName; }
 
   static bool classof(const MCSection *S) { return S->getVariant() == SV_GOFF; }
 };

diff  --git a/llvm/include/llvm/MC/MCSymbolGOFF.h b/llvm/include/llvm/MC/MCSymbolGOFF.h
index 9ca53a5653108..d8c570d2de240 100644
--- a/llvm/include/llvm/MC/MCSymbolGOFF.h
+++ b/llvm/include/llvm/MC/MCSymbolGOFF.h
@@ -13,15 +13,41 @@
 #ifndef LLVM_MC_MCSYMBOLGOFF_H
 #define LLVM_MC_MCSYMBOLGOFF_H
 
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/MC/MCGOFFAttributes.h"
+#include "llvm/MC/MCSectionGOFF.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCSymbolTableEntry.h"
 
 namespace llvm {
 
 class MCSymbolGOFF : public MCSymbol {
+  // Associated data area of the section. Needs to be emitted first.
+  MCSectionGOFF *ADA;
+
+  GOFF::LDAttr LDAttributes;
+
+  enum SymbolFlags : uint16_t {
+    SF_LD = 0x01, // LD attributes are set.
+  };
+
 public:
   MCSymbolGOFF(const MCSymbolTableEntry *Name, bool IsTemporary)
       : MCSymbol(SymbolKindGOFF, Name, IsTemporary) {}
+
+  void setLDAttributes(GOFF::LDAttr Attr) {
+    modifyFlags(SF_LD, SF_LD);
+    LDAttributes = Attr;
+  }
+  GOFF::LDAttr getLDAttributes() const { return LDAttributes; }
+  bool hasLDAttributes() const { return getFlags() & SF_LD; }
+
+  void setADA(MCSectionGOFF *AssociatedDataArea) {
+    ADA = AssociatedDataArea;
+    AssociatedDataArea->RequiresNonZeroLength = true;
+  }
+  MCSectionGOFF *getADA() const { return ADA; }
+
   static bool classof(const MCSymbol *S) { return S->isGOFF(); }
 };
 } // end namespace llvm

diff  --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index c804a179d8865..5454cd475f5ed 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -19,6 +19,7 @@
 #include "llvm/BinaryFormat/COFF.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/BinaryFormat/MachO.h"
 #include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/CodeGen/BasicBlockSectionUtils.h"
@@ -47,6 +48,7 @@
 #include "llvm/MC/MCAsmInfoDarwin.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCGOFFAttributes.h"
 #include "llvm/MC/MCSectionCOFF.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSectionGOFF.h"
@@ -56,6 +58,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"
@@ -64,6 +67,7 @@
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/TargetParser/Triple.h"
@@ -2775,6 +2779,29 @@ MCSection *TargetLoweringObjectFileXCOFF::getSectionForLSDA(
 //===----------------------------------------------------------------------===//
 TargetLoweringObjectFileGOFF::TargetLoweringObjectFileGOFF() = default;
 
+void TargetLoweringObjectFileGOFF::getModuleMetadata(Module &M) {
+  // Construct the default names for the root SD and the ADA PR symbol.
+  StringRef FileName = sys::path::stem(M.getSourceFileName());
+  if (FileName.size() > 1 && FileName.starts_with('<') &&
+      FileName.ends_with('>'))
+    FileName = FileName.substr(1, FileName.size() - 2);
+  DefaultRootSDName = Twine(FileName).concat("#C").str();
+  DefaultADAPRName = Twine(FileName).concat("#S").str();
+  MCSectionGOFF *RootSD =
+      static_cast<MCSectionGOFF *>(TextSection)->getParent();
+  MCSectionGOFF *ADAPR = static_cast<MCSectionGOFF *>(ADASection);
+  RootSD->setName(DefaultRootSDName);
+  ADAPR->setName(DefaultADAPRName);
+  // Initialize the label for the text section.
+  MCSymbolGOFF *TextLD = static_cast<MCSymbolGOFF *>(
+      getContext().getOrCreateSymbol(RootSD->getName()));
+  TextLD->setLDAttributes(GOFF::LDAttr{
+      false, GOFF::ESD_EXE_CODE, GOFF::ESD_BST_Strong, GOFF::ESD_LT_XPLink,
+      GOFF::ESD_AMODE_64, GOFF::ESD_BSC_Section});
+  TextLD->setADA(ADAPR);
+  TextSection->setBeginSymbol(TextLD);
+}
+
 MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
   return SelectSectionForGlobal(GO, Kind, TM);
@@ -2783,15 +2810,56 @@ 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, 0);
+
+  MCSectionGOFF *WSA = getContext().getGOFFSection(
+      SectionKind::getMetadata(), GOFF::CLASS_WSA,
+      GOFF::EDAttr{false, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts,
+                   GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge,
+                   GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0,
+                   GOFF::ESD_ALIGN_Fullword, 0},
+      static_cast<MCSectionGOFF *>(TextSection)->getParent());
+  return getContext().getGOFFSection(SectionKind::getData(), Name,
+                                     GOFF::PRAttr{true, GOFF::ESD_EXE_DATA,
+                                                  GOFF::ESD_LT_XPLink,
+                                                  GOFF::ESD_BSC_Section, 0},
+                                     WSA);
 }
 
 MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
   auto *Symbol = TM.getSymbol(GO);
-  if (Kind.isBSS())
-    return getContext().getGOFFSection(Symbol->getName(), SectionKind::getBSS(),
-                                       nullptr, 0);
 
-  return getContext().getObjectFileInfo()->getTextSection();
+  if (Kind.isBSS() || Kind.isData()) {
+    GOFF::ESDBindingScope PRBindingScope =
+        GO->hasExternalLinkage()
+            ? (GO->hasDefaultVisibility() ? GOFF::ESD_BSC_ImportExport
+                                          : GOFF::ESD_BSC_Library)
+            : GOFF::ESD_BSC_Section;
+    GOFF::ESDBindingScope SDBindingScope =
+        PRBindingScope == GOFF::ESD_BSC_Section ? GOFF::ESD_BSC_Section
+                                                : GOFF::ESD_BSC_Unspecified;
+    MaybeAlign Alignment;
+    if (auto *F = dyn_cast<Function>(GO))
+      Alignment = F->getAlign();
+    else if (auto *V = dyn_cast<GlobalVariable>(GO))
+      Alignment = V->getAlign();
+    GOFF::ESDAlignment Align =
+        Alignment ? static_cast<GOFF::ESDAlignment>(Log2(*Alignment))
+                  : GOFF::ESD_ALIGN_Doubleword;
+    MCSectionGOFF *SD = getContext().getGOFFSection(
+        SectionKind::getMetadata(), Symbol->getName(),
+        GOFF::SDAttr{GOFF::ESD_TA_Unspecified, SDBindingScope});
+    MCSectionGOFF *ED = getContext().getGOFFSection(
+        SectionKind::getMetadata(), GOFF::CLASS_WSA,
+        GOFF::EDAttr{false, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts,
+                     GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge,
+                     GOFF::ESD_LB_Deferred, GOFF::ESD_RQ_0, Align, 0},
+        SD);
+    return getContext().getGOFFSection(Kind, Symbol->getName(),
+                                       GOFF::PRAttr{false, GOFF::ESD_EXE_DATA,
+                                                    GOFF::ESD_LT_XPLink,
+                                                    PRBindingScope, 0},
+                                       ED);
+  }
+  return TextSection;
 }

diff  --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index f49f14c848b90..d662c42c522fc 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -46,6 +46,7 @@ add_llvm_component_library(LLVMMC
   MCSectionCOFF.cpp
   MCSectionDXContainer.cpp
   MCSectionELF.cpp
+  MCSectionGOFF.cpp
   MCSectionMachO.cpp
   MCSectionWasm.cpp
   MCSectionXCOFF.cpp

diff  --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index dd249d3608566..1f3c131289b49 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -12,8 +12,13 @@
 
 #include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCGOFFAttributes.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/raw_ostream.h"
@@ -23,44 +28,13 @@ using namespace llvm;
 #define DEBUG_TYPE "goff-writer"
 
 namespace {
-
-// The standard System/390 convention is to name the high-order (leftmost) bit
-// in a byte as bit zero. The Flags type helps to set bits in a byte according
-// to this numeration order.
-class Flags {
-  uint8_t Val;
-
-  constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value,
-                                uint8_t OldValue) {
-    assert(BitIndex < 8 && "Bit index out of bounds!");
-    assert(Length + BitIndex <= 8 && "Bit length too long!");
-
-    uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length);
-    Value = Value << (8 - BitIndex - Length);
-    assert((Value & Mask) == Value && "Bits set outside of range!");
-
-    return (OldValue & ~Mask) | Value;
-  }
-
-public:
-  constexpr Flags() : Val(0) {}
-  constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value)
-      : Val(bits(BitIndex, Length, Value, 0)) {}
-
-  void set(uint8_t BitIndex, uint8_t Length, uint8_t Value) {
-    Val = bits(BitIndex, Length, Value, Val);
-  }
-
-  constexpr operator uint8_t() const { return Val; }
-};
-
 // Common flag values on records.
 
 // Flag: This record is continued.
-constexpr uint8_t RecContinued = Flags(7, 1, 1);
+constexpr uint8_t RecContinued = GOFF::Flags(7, 1, 1);
 
 // Flag: This record is a continuation.
-constexpr uint8_t RecContinuation = Flags(6, 1, 1);
+constexpr uint8_t RecContinuation = GOFF::Flags(6, 1, 1);
 
 // The GOFFOstream is responsible to write the data into the fixed physical
 // records of the format. A user of this class announces the begin of a new
@@ -223,19 +197,160 @@ void GOFFOstream::finalizeRecord() {
 }
 
 namespace {
+// A GOFFSymbol holds all the data required for writing an ESD record.
+class GOFFSymbol {
+public:
+  std::string Name;
+  uint32_t EsdId;
+  uint32_t ParentEsdId;
+  uint64_t Offset = 0; // Offset of the symbol into the section. LD only.
+                       // Offset is only 32 bit, the larger type is used to
+                       // enable error checking.
+  GOFF::ESDSymbolType SymbolType;
+  GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_ProgramManagementBinder;
+
+  GOFF::BehavioralAttributes BehavAttrs;
+  GOFF::SymbolFlags SymbolFlags;
+  uint32_t SortKey = 0;
+  uint32_t SectionLength = 0;
+  uint32_t ADAEsdId = 0;
+  uint32_t EASectionEDEsdId = 0;
+  uint32_t EASectionOffset = 0;
+  uint8_t FillByteValue = 0;
+
+  GOFFSymbol() : EsdId(0), ParentEsdId(0) {}
+
+  GOFFSymbol(StringRef Name, uint32_t EsdID, const GOFF::SDAttr &Attr)
+      : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(0),
+        SymbolType(GOFF::ESD_ST_SectionDefinition) {
+    BehavAttrs.setTaskingBehavior(Attr.TaskingBehavior);
+    BehavAttrs.setBindingScope(Attr.BindingScope);
+  }
+
+  GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
+             const GOFF::EDAttr &Attr)
+      : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
+        SymbolType(GOFF::ESD_ST_ElementDefinition) {
+    this->NameSpace = Attr.NameSpace;
+    // We always set a fill byte value.
+    this->FillByteValue = Attr.FillByteValue;
+    SymbolFlags.setFillBytePresence(1);
+    SymbolFlags.setReservedQwords(Attr.ReservedQwords);
+    // TODO Do we need/should set the "mangled" flag?
+    BehavAttrs.setReadOnly(Attr.IsReadOnly);
+    BehavAttrs.setRmode(Attr.Rmode);
+    BehavAttrs.setTextStyle(Attr.TextStyle);
+    BehavAttrs.setBindingAlgorithm(Attr.BindAlgorithm);
+    BehavAttrs.setLoadingBehavior(Attr.LoadBehavior);
+    BehavAttrs.setAlignment(Attr.Alignment);
+  }
+
+  GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
+             GOFF::ESDNameSpaceId NameSpace, const GOFF::LDAttr &Attr)
+      : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
+        SymbolType(GOFF::ESD_ST_LabelDefinition), NameSpace(NameSpace) {
+    SymbolFlags.setRenameable(Attr.IsRenamable);
+    BehavAttrs.setExecutable(Attr.Executable);
+    BehavAttrs.setBindingStrength(Attr.BindingStrength);
+    BehavAttrs.setLinkageType(Attr.Linkage);
+    BehavAttrs.setAmode(Attr.Amode);
+    BehavAttrs.setBindingScope(Attr.BindingScope);
+  }
+
+  GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
+             const GOFF::EDAttr &EDAttr, const GOFF::PRAttr &Attr)
+      : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID),
+        SymbolType(GOFF::ESD_ST_PartReference), NameSpace(EDAttr.NameSpace) {
+    SymbolFlags.setRenameable(Attr.IsRenamable);
+    BehavAttrs.setExecutable(Attr.Executable);
+    BehavAttrs.setLinkageType(Attr.Linkage);
+    BehavAttrs.setBindingScope(Attr.BindingScope);
+    BehavAttrs.setAlignment(EDAttr.Alignment);
+  }
+};
+
 class GOFFWriter {
   GOFFOstream OS;
+  MCAssembler &Asm;
 
   void writeHeader();
+  void writeSymbol(const GOFFSymbol &Symbol);
   void writeEnd();
 
+  void defineSectionSymbols(const MCSectionGOFF &Section);
+  void defineLabel(const MCSymbolGOFF &Symbol);
+  void defineSymbols();
+
 public:
-  GOFFWriter(raw_pwrite_stream &OS);
+  GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm);
   uint64_t writeObject();
 };
 } // namespace
 
-GOFFWriter::GOFFWriter(raw_pwrite_stream &OS) : OS(OS) {}
+GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm)
+    : OS(OS), Asm(Asm) {}
+
+void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) {
+  if (Section.isSD()) {
+    GOFFSymbol SD(Section.getName(), Section.getOrdinal(),
+                  Section.getSDAttributes());
+    writeSymbol(SD);
+  }
+
+  if (Section.isED()) {
+    GOFFSymbol ED(Section.getName(), Section.getOrdinal(),
+                  Section.getParent()->getOrdinal(), Section.getEDAttributes());
+    ED.SectionLength = Asm.getSectionAddressSize(Section);
+    writeSymbol(ED);
+  }
+
+  if (Section.isPR()) {
+    MCSectionGOFF *Parent = Section.getParent();
+    GOFFSymbol PR(Section.getName(), Section.getOrdinal(), Parent->getOrdinal(),
+                  Parent->getEDAttributes(), Section.getPRAttributes());
+    PR.SectionLength = Asm.getSectionAddressSize(Section);
+    if (Section.requiresNonZeroLength()) {
+      // We cannot have a zero-length section for data.  If we do,
+      // artificially inflate it. Use 2 bytes to avoid odd alignments. Note:
+      // if this is ever changed, you will need to update the code in
+      // SystemZAsmPrinter::emitCEEMAIN and SystemZAsmPrinter::emitCELQMAIN to
+      // generate -1 if there is no ADA
+      if (!PR.SectionLength)
+        PR.SectionLength = 2;
+    }
+    writeSymbol(PR);
+  }
+}
+
+void GOFFWriter::defineLabel(const MCSymbolGOFF &Symbol) {
+  MCSectionGOFF &Section = static_cast<MCSectionGOFF &>(Symbol.getSection());
+  GOFFSymbol LD(Symbol.getName(), Symbol.getIndex(), Section.getOrdinal(),
+                Section.getEDAttributes().NameSpace, Symbol.getLDAttributes());
+  if (Symbol.getADA())
+    LD.ADAEsdId = Symbol.getADA()->getOrdinal();
+  writeSymbol(LD);
+}
+
+void GOFFWriter::defineSymbols() {
+  unsigned Ordinal = 0;
+  // Process all sections.
+  for (MCSection &S : Asm) {
+    auto &Section = cast<MCSectionGOFF>(S);
+    Section.setOrdinal(++Ordinal);
+    defineSectionSymbols(Section);
+  }
+
+  // Process all symbols
+  for (const MCSymbol &Sym : Asm.symbols()) {
+    if (Sym.isTemporary())
+      continue;
+    auto &Symbol = cast<MCSymbolGOFF>(Sym);
+    if (Symbol.hasLDAttributes()) {
+      Symbol.setIndex(++Ordinal);
+      defineLabel(Symbol);
+    }
+  }
+}
 
 void GOFFWriter::writeHeader() {
   OS.newRecord(GOFF::RT_HDR);
@@ -251,6 +366,45 @@ void GOFFWriter::writeHeader() {
   OS.write_zeros(6);       // Reserved
 }
 
+void GOFFWriter::writeSymbol(const GOFFSymbol &Symbol) {
+  if (Symbol.Offset >= (((uint64_t)1) << 31))
+    report_fatal_error("ESD offset out of range");
+
+  // All symbol names are in EBCDIC.
+  SmallString<256> Name;
+  ConverterEBCDIC::convertToEBCDIC(Symbol.Name, Name);
+
+  // Check length here since this number is technically signed but we need uint
+  // for writing to records.
+  if (Name.size() >= GOFF::MaxDataLength)
+    report_fatal_error("Symbol max name length exceeded");
+  uint16_t NameLength = Name.size();
+
+  OS.newRecord(GOFF::RT_ESD);
+  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>(
+      static_cast<uint32_t>(Symbol.Offset));     // Offset or Address
+  OS.writebe<uint32_t>(0);                       // Reserved
+  OS.writebe<uint32_t>(Symbol.SectionLength);    // Length
+  OS.writebe<uint32_t>(Symbol.EASectionEDEsdId); // Extended Attribute ESDID
+  OS.writebe<uint32_t>(Symbol.EASectionOffset);  // Extended Attribute Offset
+  OS.writebe<uint32_t>(0);                       // Reserved
+  OS.writebe<uint8_t>(Symbol.NameSpace);         // Name Space ID
+  OS.writebe<uint8_t>(Symbol.SymbolFlags);       // Flags
+  OS.writebe<uint8_t>(Symbol.FillByteValue);     // Fill-Byte Value
+  OS.writebe<uint8_t>(0);                        // Reserved
+  OS.writebe<uint32_t>(Symbol.ADAEsdId);         // ADA ESDID
+  OS.writebe<uint32_t>(Symbol.SortKey);          // Sort Priority
+  OS.writebe<uint64_t>(0);                       // Reserved
+  for (auto F : Symbol.BehavAttrs.Attr)
+    OS.writebe<uint8_t>(F);          // Behavioral Attributes
+  OS.writebe<uint16_t>(NameLength);  // Name Length
+  OS.write(Name.data(), NameLength); // Name
+}
+
 void GOFFWriter::writeEnd() {
   uint8_t F = GOFF::END_EPR_None;
   uint8_t AMODE = 0;
@@ -259,9 +413,9 @@ void GOFFWriter::writeEnd() {
   // TODO Set Flags/AMODE/ESDID for entry point.
 
   OS.newRecord(GOFF::RT_END);
-  OS.writebe<uint8_t>(Flags(6, 2, F)); // Indicator flags
-  OS.writebe<uint8_t>(AMODE);          // AMODE
-  OS.write_zeros(3);                   // Reserved
+  OS.writebe<uint8_t>(GOFF::Flags(6, 2, F)); // Indicator flags
+  OS.writebe<uint8_t>(AMODE);                // AMODE
+  OS.write_zeros(3);                         // Reserved
   // The record count is the number of logical records. In principle, this value
   // is available as OS.logicalRecords(). However, some tools rely on this field
   // being zero.
@@ -271,6 +425,9 @@ void GOFFWriter::writeEnd() {
 
 uint64_t GOFFWriter::writeObject() {
   writeHeader();
+
+  defineSymbols();
+
   writeEnd();
 
   // Make sure all records are written.
@@ -289,7 +446,7 @@ GOFFObjectWriter::GOFFObjectWriter(
 GOFFObjectWriter::~GOFFObjectWriter() {}
 
 uint64_t GOFFObjectWriter::writeObject() {
-  uint64_t Size = GOFFWriter(OS).writeObject();
+  uint64_t Size = GOFFWriter(OS, *Asm).writeObject();
   return Size;
 }
 

diff  --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 99c74f6f5c978..f3bb5aa88e8fb 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -14,6 +14,7 @@
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/COFF.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/MC/MCAsmInfo.h"
@@ -720,22 +721,46 @@ MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
                                       : std::nullopt;
 }
 
-MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
-                                         MCSection *Parent,
-                                         uint32_t Subsection) {
+template <typename TAttr>
+MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
+                                         TAttr Attributes, MCSection *Parent) {
+  std::string UniqueName(Name);
+  if (Parent) {
+    UniqueName.append("/").append(Parent->getName());
+    if (auto *P = static_cast<MCSectionGOFF *>(Parent)->getParent())
+      UniqueName.append("/").append(P->getName());
+  }
   // Do the lookup. If we don't have a hit, return a new section.
-  auto [Iter, Inserted] = GOFFUniquingMap.try_emplace(Section.str());
-  if (!Inserted)
+  auto IterBool = GOFFUniquingMap.insert(std::make_pair(UniqueName, nullptr));
+  auto Iter = IterBool.first;
+  if (!IterBool.second)
     return Iter->second;
 
-  StringRef CachedName = Iter->first;
-  MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate())
-      MCSectionGOFF(CachedName, Kind, Parent, Subsection);
+  StringRef CachedName = StringRef(Iter->first.c_str(), Name.size());
+  MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate()) MCSectionGOFF(
+      CachedName, Kind, Attributes, static_cast<MCSectionGOFF *>(Parent));
   Iter->second = GOFFSection;
   allocInitialFragment(*GOFFSection);
   return GOFFSection;
 }
 
+MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
+                                         GOFF::SDAttr SDAttributes) {
+  return getGOFFSection<GOFF::SDAttr>(Kind, Name, SDAttributes, nullptr);
+}
+
+MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
+                                         GOFF::EDAttr EDAttributes,
+                                         MCSection *Parent) {
+  return getGOFFSection<GOFF::EDAttr>(Kind, Name, EDAttributes, Parent);
+}
+
+MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name,
+                                         GOFF::PRAttr PRAttributes,
+                                         MCSection *Parent) {
+  return getGOFFSection<GOFF::PRAttr>(Kind, Name, PRAttributes, Parent);
+}
+
 MCSectionCOFF *MCContext::getCOFFSection(StringRef Section,
                                          unsigned Characteristics,
                                          StringRef COMDATSymName, int Selection,

diff  --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp
index c9e4c21c857ce..b7021915e7b70 100644
--- a/llvm/lib/MC/MCGOFFStreamer.cpp
+++ b/llvm/lib/MC/MCGOFFStreamer.cpp
@@ -26,6 +26,21 @@ GOFFObjectWriter &MCGOFFStreamer::getWriter() {
   return static_cast<GOFFObjectWriter &>(getAssembler().getWriter());
 }
 
+// Make sure that all section are registered in the correct order.
+static void registerSectionHierarchy(MCAssembler &Asm, MCSectionGOFF *Section) {
+  if (Section->isRegistered())
+    return;
+  if (Section->getParent())
+    registerSectionHierarchy(Asm, Section->getParent());
+  Asm.registerSection(*Section);
+}
+
+void MCGOFFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
+  registerSectionHierarchy(getAssembler(),
+                           static_cast<MCSectionGOFF *>(Section));
+  MCObjectStreamer::changeSection(Section, Subsection);
+}
+
 MCStreamer *llvm::createGOFFStreamer(MCContext &Context,
                                      std::unique_ptr<MCAsmBackend> &&MAB,
                                      std::unique_ptr<MCObjectWriter> &&OW,

diff  --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 9ad56aaf05bc5..0069d12dce396 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -13,6 +13,7 @@
 #include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCGOFFAttributes.h"
 #include "llvm/MC/MCSection.h"
 #include "llvm/MC/MCSectionCOFF.h"
 #include "llvm/MC/MCSectionDXContainer.h"
@@ -546,18 +547,51 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
 }
 
 void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
-  TextSection = Ctx->getGOFFSection(".text", SectionKind::getText(), nullptr);
-  BSSSection = Ctx->getGOFFSection(".bss", SectionKind::getBSS(), nullptr);
-  PPA1Section = Ctx->getGOFFSection(".ppa1", SectionKind::getMetadata(),
-                                    TextSection, GOFF::SK_PPA1);
-  PPA2Section = Ctx->getGOFFSection(".ppa2", SectionKind::getMetadata(),
-                                    TextSection, GOFF::SK_PPA2);
-
-  PPA2ListSection =
-      Ctx->getGOFFSection(".ppa2list", SectionKind::getData(), nullptr);
-
-  ADASection = Ctx->getGOFFSection(".ada", SectionKind::getData(), nullptr);
-  IDRLSection = Ctx->getGOFFSection("B_IDRL", SectionKind::getData(), nullptr);
+  MCSectionGOFF *RootSDSection = Ctx->getGOFFSection(
+      SectionKind::getMetadata(), "#C",
+      GOFF::SDAttr{GOFF::ESD_TA_Rent, GOFF::ESD_BSC_Section});
+
+  MCSectionGOFF *ADAEDSection = Ctx->getGOFFSection(
+      SectionKind::getMetadata(), GOFF::CLASS_WSA,
+      GOFF::EDAttr{false, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts,
+                   GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge,
+                   GOFF::ESD_LB_Deferred, GOFF::ESD_RQ_1,
+                   GOFF::ESD_ALIGN_Quadword, 0},
+      RootSDSection);
+  ADASection = Ctx->getGOFFSection(SectionKind::getData(), "#S",
+                                   GOFF::PRAttr{false, GOFF::ESD_EXE_DATA,
+                                                GOFF::ESD_LT_XPLink,
+                                                GOFF::ESD_BSC_Section, 0},
+                                   ADAEDSection);
+
+  TextSection = Ctx->getGOFFSection(
+      SectionKind::getText(), GOFF::CLASS_CODE,
+      GOFF::EDAttr{true, GOFF::ESD_RMODE_64, GOFF::ESD_NS_NormalName,
+                   GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Concatenate,
+                   GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0,
+                   GOFF::ESD_ALIGN_Doubleword, 0},
+      RootSDSection);
+
+  MCSectionGOFF *PPA2ListEDSection = Ctx->getGOFFSection(
+      SectionKind::getMetadata(), GOFF::CLASS_PPA2,
+      GOFF::EDAttr{true, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts,
+                   GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge,
+                   GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0,
+                   GOFF::ESD_ALIGN_Doubleword, 0},
+      RootSDSection);
+  PPA2ListSection = Ctx->getGOFFSection(SectionKind::getData(), ".&ppa2",
+                                        GOFF::PRAttr{true, GOFF::ESD_EXE_DATA,
+                                                     GOFF::ESD_LT_OS,
+                                                     GOFF::ESD_BSC_Section, 0},
+                                        PPA2ListEDSection);
+
+  IDRLSection = Ctx->getGOFFSection(
+      SectionKind::getData(), "B_IDRL",
+      GOFF::EDAttr{true, GOFF::ESD_RMODE_64, GOFF::ESD_NS_NormalName,
+                   GOFF::ESD_TS_Structured, GOFF::ESD_BA_Concatenate,
+                   GOFF::ESD_LB_NoLoad, GOFF::ESD_RQ_0,
+                   GOFF::ESD_ALIGN_Doubleword, 0},
+      RootSDSection);
 }
 
 void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {

diff  --git a/llvm/lib/MC/MCSectionGOFF.cpp b/llvm/lib/MC/MCSectionGOFF.cpp
new file mode 100644
index 0000000000000..8163e5bbd632b
--- /dev/null
+++ b/llvm/lib/MC/MCSectionGOFF.cpp
@@ -0,0 +1,143 @@
+//===- MCSectionGOFF.cpp - GOFF Code Section Representation ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCSectionGOFF.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+static void emitCATTR(raw_ostream &OS, StringRef Name, GOFF::ESDRmode Rmode,
+                      GOFF::ESDAlignment Alignment,
+                      GOFF::ESDLoadingBehavior LoadBehavior,
+                      GOFF::ESDExecutable Executable, bool IsReadOnly,
+                      uint32_t SortKey, uint8_t FillByteValue,
+                      StringRef PartName) {
+  OS << Name << " CATTR ";
+  OS << "ALIGN(" << static_cast<unsigned>(Alignment) << "),"
+     << "FILL(" << static_cast<unsigned>(FillByteValue) << ")";
+  switch (LoadBehavior) {
+  case GOFF::ESD_LB_Deferred:
+    OS << ",DEFLOAD";
+    break;
+  case GOFF::ESD_LB_NoLoad:
+    OS << ",NOLOAD";
+    break;
+  default:
+    break;
+  }
+  switch (Executable) {
+  case GOFF::ESD_EXE_CODE:
+    OS << ",EXECUTABLE";
+    break;
+  case GOFF::ESD_EXE_DATA:
+    OS << ",NOTEXECUTABLE";
+    break;
+  default:
+    break;
+  }
+  if (IsReadOnly)
+    OS << ",READONLY";
+  if (Rmode != GOFF::ESD_RMODE_None) {
+    OS << ',';
+    OS << "RMODE(";
+    switch (Rmode) {
+    case GOFF::ESD_RMODE_24:
+      OS << "24";
+      break;
+    case GOFF::ESD_RMODE_31:
+      OS << "31";
+      break;
+    case GOFF::ESD_RMODE_64:
+      OS << "64";
+      break;
+    case GOFF::ESD_RMODE_None:
+      break;
+    }
+    OS << ')';
+  }
+  if (SortKey)
+    OS << ",PRIORITY(" << SortKey << ")";
+  if (!PartName.empty())
+    OS << ",PART(" << PartName << ")";
+  OS << '\n';
+}
+
+static void emitXATTR(raw_ostream &OS, StringRef Name,
+                      GOFF::ESDLinkageType Linkage,
+                      GOFF::ESDExecutable Executable,
+                      GOFF::ESDBindingScope BindingScope) {
+  OS << Name << " XATTR ";
+  OS << "LINKAGE(" << (Linkage == GOFF::ESD_LT_OS ? "OS" : "XPLINK") << "),";
+  if (Executable != GOFF::ESD_EXE_Unspecified)
+    OS << "REFERENCE(" << (Executable == GOFF::ESD_EXE_CODE ? "CODE" : "DATA")
+       << "),";
+  if (BindingScope != GOFF::ESD_BSC_Unspecified) {
+    OS << "SCOPE(";
+    switch (BindingScope) {
+    case GOFF::ESD_BSC_Section:
+      OS << "SECTION";
+      break;
+    case GOFF::ESD_BSC_Module:
+      OS << "MODULE";
+      break;
+    case GOFF::ESD_BSC_Library:
+      OS << "LIBRARY";
+      break;
+    case GOFF::ESD_BSC_ImportExport:
+      OS << "EXPORT";
+      break;
+    default:
+      break;
+    }
+    OS << ')';
+  }
+  OS << '\n';
+}
+
+void MCSectionGOFF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+                                         raw_ostream &OS,
+                                         uint32_t Subsection) const {
+  switch (SymbolType) {
+  case GOFF::ESD_ST_SectionDefinition: {
+    OS << Name << " CSECT\n";
+    Emitted = true;
+    break;
+  }
+  case GOFF::ESD_ST_ElementDefinition: {
+    getParent()->printSwitchToSection(MAI, T, OS, Subsection);
+    if (!Emitted) {
+      emitCATTR(OS, Name, EDAttributes.Rmode, EDAttributes.Alignment,
+                EDAttributes.LoadBehavior, GOFF::ESD_EXE_Unspecified,
+                EDAttributes.IsReadOnly, 0, EDAttributes.FillByteValue,
+                StringRef());
+      Emitted = true;
+    } else
+      OS << Name << " CATTR\n";
+    break;
+  }
+  case GOFF::ESD_ST_PartReference: {
+    MCSectionGOFF *ED = getParent();
+    ED->getParent()->printSwitchToSection(MAI, T, OS, Subsection);
+    if (!Emitted) {
+      emitCATTR(OS, ED->getName(), ED->getEDAttributes().Rmode,
+                ED->EDAttributes.Alignment, ED->EDAttributes.LoadBehavior,
+                PRAttributes.Executable, ED->EDAttributes.IsReadOnly,
+                PRAttributes.SortKey, ED->EDAttributes.FillByteValue, Name);
+      emitXATTR(OS, Name, PRAttributes.Linkage, PRAttributes.Executable,
+                PRAttributes.BindingScope);
+      ED->Emitted = true;
+      Emitted = true;
+    } else
+      OS << ED->getName() << " CATTR PART(" << Name << ")\n";
+    break;
+  }
+  default:
+    llvm_unreachable("Wrong section type");
+  }
+}
\ No newline at end of file

diff  --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 6f9d25c050b71..eb0365d1f1893 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -21,6 +21,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"
@@ -1254,7 +1255,8 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() {
     OutStreamer->emitLabel(FnEndSym);
 
     OutStreamer->pushSection();
-    OutStreamer->switchSection(getObjFileLowering().getPPA1Section());
+    OutStreamer->switchSection(getObjFileLowering().getTextSection(),
+                               GOFF::SK_PPA1);
     emitPPA1(FnEndSym);
     OutStreamer->popSection();
 
@@ -1559,7 +1561,8 @@ void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
 
 void SystemZAsmPrinter::emitPPA2(Module &M) {
   OutStreamer->pushSection();
-  OutStreamer->switchSection(getObjFileLowering().getPPA2Section());
+  OutStreamer->switchSection(getObjFileLowering().getTextSection(),
+                             GOFF::SK_PPA2);
   MCContext &OutContext = OutStreamer->getContext();
   // Make CELQSTRT symbol.
   const char *StartSymbolName = "CELQSTRT";

diff  --git a/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll b/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll
index 068b56d8cef8b..d6aa99b5634d7 100644
--- a/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll
@@ -55,7 +55,9 @@ entry:
 
 declare signext i32 @callout(i32 signext)
 
-; CHECK:     .section    ".ada"
+; CHECK: stdin#C CSECT
+; CHECK: C_WSA64 CATTR ALIGN(4),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(stdin#S)
+; CHECK: stdin#S XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(SECTION)
 ; CHECK:  .set L#DoFunc at indirect0, DoFunc
 ; CHECK:      .indirect_symbol   L#DoFunc at indirect0
 ; CHECK:  .quad V(L#DoFunc at indirect0)          * Offset 0 pointer to function descriptor DoFunc

diff  --git a/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll b/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll
index b1f0c9e5b8e54..c963d85d60f1c 100644
--- a/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll
@@ -30,7 +30,9 @@ declare double @llvm.sin.f64(double)
 declare fp128 @llvm.exp2.f128(fp128)
 
 ; Check the calls in the ADA.
-; CHECK: .section ".ada"
+; CHECK: stdin#C CSECT
+; CHECK: C_WSA64 CATTR ALIGN(4),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(stdin#S)
+; CHECK: stdin#S XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(SECTION)
 
 ; Check that there is no call to sqrt.
 ; CHECK-NOT:  .quad   R(@@WSQT at B)

diff  --git a/llvm/test/CodeGen/SystemZ/zos-landingpad.ll b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll
index 63c332eb423e3..307f280617619 100644
--- a/llvm/test/CodeGen/SystemZ/zos-landingpad.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll
@@ -37,5 +37,7 @@ lpad:
 ; CHECK: Personality routine
 ; CHECK: LSDA location
 ; Check that the exception table is emitted into .lsda section.
-; CHECK: .section ".gcc_exception_table.test1"
+; CHECK:  stdin#C CSECT
+; CHECK:  C_WSA64 CATTR ALIGN(2),FILL(0),NOTEXECUTABLE,RMODE(64),PART(.gcc_exception_table.test1)
+; CHECK:  .gcc_exception_table.test1 XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(SECTION)
 ; CHECK: GCC_except_table0:

diff  --git a/llvm/test/MC/GOFF/ppa1.ll b/llvm/test/CodeGen/SystemZ/zos-ppa1.ll
similarity index 97%
rename from llvm/test/MC/GOFF/ppa1.ll
rename to llvm/test/CodeGen/SystemZ/zos-ppa1.ll
index fe2dc77bba2f5..fc51e9c5eccc5 100644
--- a/llvm/test/MC/GOFF/ppa1.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-ppa1.ll
@@ -12,7 +12,8 @@
 ; CHECK: *   Bit 1: 1 = Leaf function
 ; CHECK: *   Bit 2: 0 = Does not use alloca
 ; CHECK: L#func_end0:
-; CHECK: .section        ".ppa1"
+; CHECK: stdin#C CSECT
+; CHECK: C_CODE64 CATTR
 ; CHECK: L#PPA1_void_test_0:                     * PPA1
 ; CHECK:        .byte   2                               * Version
 ; CHECK:        .byte   206                             * LE Signature X'CE'

diff  --git a/llvm/test/CodeGen/SystemZ/zos-ppa2.ll b/llvm/test/CodeGen/SystemZ/zos-ppa2.ll
index 07025091fb240..8f3847da32e31 100644
--- a/llvm/test/CodeGen/SystemZ/zos-ppa2.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-ppa2.ll
@@ -1,6 +1,6 @@
 ; RUN: llc -mtriple s390x-ibm-zos -mcpu=z15 -asm-verbose=true < %s | FileCheck %s
 
-; CHECK:    .section    ".ppa2"
+; CHECK: C_CODE64 CATTR
 ; CHECK: L#PPA2:
 ; CHECK:    .byte   3
 ; CHECK:    .byte   231
@@ -19,7 +19,7 @@
 ; CHECK:    .quad   L#PPA2-CELQSTRT                 * A(PPA2-CELQSTRT)
 ; CHECK: L#PPA1_void_test_0:
 ; CHECK:    .long   L#PPA2-L#PPA1_void_test_0       * Offset to PPA2
-; CHECK:    .section    "B_IDRL"
+; CHECK: B_IDRL CATTR
 ; CHECK:    .byte   0
 ; CHECK:    .byte   3
 ; CHECK:    .short  30

diff  --git a/llvm/test/CodeGen/SystemZ/zos-section-1.ll b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
new file mode 100644
index 0000000000000..ea9bc4ce95174
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
@@ -0,0 +1,112 @@
+; RUN: llc <%s --mtriple s390x-ibm-zos --filetype=obj | \
+; RUN:   od -Ax -tx1 -v | FileCheck --ignore-case %s
+
+source_filename = "test.ll"
+
+declare void @other(...)
+
+define void @me() {
+entry:
+  tail call void @other()
+  ret void
+}
+
+; Header record:
+;  03 is prefix byte
+;  f. is header type
+;  .0 is flag
+;  00 is version
+; The 1 at offset 0x33 is the architecture level.
+; CHECK:      000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+; ESD record, type SD.
+;  03 is prefix byte
+;  0. is header type
+;  .0 is flag
+;  00 is version
+;  00 is type = SD
+; The 01 at offset 0x57 is the id of the symbol.
+; The 60 at offset 0x89 is the tasking behavior.
+; The 01 at offset 0x91 is the binding scope.
+; The name begins at offset 0x97, and is test#C.
+; CHECK-NEXT: 000050 03 00 00 00 [[ROOTSD:00 00 00 01]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60
+; CHECK-NEXT: 000090 00 01 00 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00
+
+; ESD record, type ED.
+; The name is C_CODE64.
+; The regular expression matches the low byte of the length.
+; CHECK-NEXT: 0000a0 03 00 00 01 [[C_CODE64:00 00 00 02]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 0000b0 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00
+; CHECK-NEXT: 0000c0 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00
+; CHECK-NEXT: 0000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 08
+; CHECK-NEXT: 0000e0 00 00 03 00 00 00 00 08 c3 6d c3 d6 c4 c5 f6 f4
+
+; ESD record, type ED.
+; The name is C_@@QPPA2.
+; This record has a continuation, therefore the falg at offset 0xf1 is set.
+; CHECK-NEXT: 0000f0 03 01 00 01 [[C_QPPA2:00 00 00 03]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000110 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK-NEXT: 000120 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 08
+; CHECK-NEXT: 000130 00 00 03 00 00 00 00 09 c3 6d 7c 7c d8 d7 d7 c1
+;
+; Continuation:
+; CHECK-NEXT: 000140 03 02 00 f2 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+; ESD record, type PR.
+; The name is .&ppa2.
+; CHECK-NEXT: 000190 03 00 00 03 [[PPA2:00 00 00 04]] [[C_QPPA2]] 00 00 00 00
+; CHECK-NEXT: 0001a0 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00
+; CHECK-NEXT: 0001b0 00 00 00 00 00 00 00 00 03 20 00 00 00 00 00 00
+; CHECK-NEXT: 0001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
+; CHECK-NEXT: 0001d0 00 01 03 00 00 00 00 06 4b 50 97 97 81 f2 00 00
+
+; ESD record, type ED.
+; The name is C_WSA64.
+; CHECK-NEXT: 0001e0 03 00 00 01 [[C_WSA64:00 00 00 05]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 0001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000200 00 00 00 00 00 00 00 00 03 81 00 00 00 00 00 00
+; CHECK-NEXT: 000210 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00
+; CHECK-NEXT: 000220 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; ESD record, type PR.
+; The name is test#S.
+; CHECK-NEXT: 000230 03 00 00 03 [[TESTS:00 00 00 06]] [[C_WSA64]] 00 00 00 00
+; CHECK-NEXT: 000240 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00
+; CHECK-NEXT: 000250 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK-NEXT: 000260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
+; CHECK-NEXT: 000270 00 01 24 00 00 00 00 06 a3 85 a2 a3 7b e2 00 00
+
+; ESD record, type ED.
+; The name is B_IDRL.
+; CHECK-NEXT: 000280 03 00 00 01 [[BIDRL:00 00 00 07]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 000290 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00
+; CHECK-NEXT: 0002a0 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00
+; CHECK-NEXT: 0002b0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 10 08
+; CHECK-NEXT: 0002c0 00 80 03 00 00 00 00 06 c2 6d c9 c4 d9 d3 00 00
+
+; ESD record, type LD.
+; The name is test#C.
+; CHECK-NEXT: 0002d0 03 00 00 02 [[TESTC:00 00 00 08]] [[C_CODE64]] 00 00 00 00
+; CHECK-NEXT: 0002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0002f0 00 00 00 00 00 00 00 00 01 00 00 00 [[TESTS]]
+; CHECK-NEXT: 000300 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK-NEXT: 000310 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00
+
+; End record.
+; CHECK-NEXT: 000320 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

diff  --git a/llvm/test/CodeGen/SystemZ/zos-section-2.ll b/llvm/test/CodeGen/SystemZ/zos-section-2.ll
new file mode 100644
index 0000000000000..472517acc4a45
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-section-2.ll
@@ -0,0 +1,155 @@
+; RUN: llc <%s --mtriple s390x-ibm-zos --filetype=obj | \
+; RUN:   od -Ax -tx1 -v | FileCheck --ignore-case %s
+
+source_filename = "test.ll"
+
+ at data = hidden global i32 42, align 4
+ at bss = hidden global i64 0, align 8
+
+; Header record:
+;  03 is prefix byte
+;  f. is header type
+;  .0 is flag
+;  00 is version
+; The 1 at offset 0x33 is the architecture level.
+; CHECK:      000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+; ESD record, type SD.
+;  03 is prefix byte
+;  0. is header type
+;  .0 is flag
+;  00 is version
+;  00 is type = SD
+; The 01 at offset 0x57 is the id of the symbol.
+; The 60 at offset 0x89 is the tasking behavior.
+; The 01 at offset 0x91 is the binding scope.
+; The name begins at offset 0x97, and is test#C.
+; CHECK-NEXT: 000050 03 00 00 00 [[ROOTSD:00 00 00 01]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60
+; CHECK-NEXT: 000090 00 01 00 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00
+
+; ESD record, type ED.
+; The name is C_CODE64.
+; The regular expression matches the low byte of the length.
+; CHECK-NEXT: 0000a0 03 00 00 01 [[C_CODE64:00 00 00 02]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 0000b0 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00
+; CHECK-NEXT: 0000c0 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00
+; CHECK-NEXT: 0000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 08
+; CHECK-NEXT: 0000e0 00 00 03 00 00 00 00 08 c3 6d c3 d6 c4 c5 f6 f4
+
+; ESD record, type ED.
+; The name is C_@@QPPA2.
+; This record has a continuation, therefore the falg at offset 0xf1 is set.
+; CHECK-NEXT: 0000f0 03 01 00 01 [[C_QPPA2:00 00 00 03]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000110 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK-NEXT: 000120 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 08
+; CHECK-NEXT: 000130 00 00 03 00 00 00 00 09 c3 6d 7c 7c d8 d7 d7 c1
+;
+; Continuation:
+; CHECK-NEXT: 000140 03 02 00 f2 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+; ESD record, type PR.
+; The name is .&ppa2.
+; CHECK-NEXT: 000190 03 00 00 03 [[PPA2:00 00 00 04]] [[C_QPPA2]] 00 00 00 00
+; CHECK-NEXT: 0001a0 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00
+; CHECK-NEXT: 0001b0 00 00 00 00 00 00 00 00 03 20 00 00 00 00 00 00
+; CHECK-NEXT: 0001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
+; CHECK-NEXT: 0001d0 00 01 03 00 00 00 00 06 4b 50 97 97 81 f2 00 00
+
+; ESD record, type SD.
+; The name is data.
+; CHECK-NEXT: 0001e0 03 00 00 00 [[DATA:00 00 00 05]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000220 00 00 00 00 00 00 00 04 84 81 a3 81 00 00 00 00
+
+; ESD record, type ED.
+; The name is C_WSA64.
+; CHECK-NEXT: 000230 03 00 00 01 [[DATA_WSA:00 00 00 06]] [[DATA]] 00 00 00 00
+; CHECK-NEXT: 000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000250 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK-NEXT: 000260 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00
+; CHECK-NEXT: 000270 00 40 02 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; ESD record, type PR.
+; The name is data.
+; CHECK-NEXT: 000280 03 00 00 03 [[DATA_PR:00 00 00 07]] [[DATA_WSA]] 00 00 00 00
+; CHECK-NEXT: 000290 00 00 00 00 00 00 00 00 [[DATA_LEN:00 00 00 04]] 00 00 00 00
+; CHECK-NEXT: 0002a0 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK-NEXT: 0002b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
+; CHECK-NEXT: 0002c0 00 03 22 00 00 00 00 04 84 81 a3 81 00 00 00 00
+
+; ESD record, type SD.
+; The name is bss.
+; CHECK-NEXT: 0002d0 03 00 00 00 [[BSS:00 00 00 08]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0002f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000310 00 00 00 00 00 00 00 03 82 a2 a2 00 00 00 00 00
+
+; ESD record, type ED.
+; The name is C_WSA64.
+; CHECK-NEXT: 000320 03 00 00 01 [[BSS_WSA:00 00 00 09]] [[BSS]] 00 00 00 00
+; CHECK-NEXT: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000340 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK-NEXT: 000350 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00
+; CHECK-NEXT: 000360 00 40 03 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; ESD record, type PR.
+; The name is bss.
+; CHECK-NEXT: 000370 03 00 00 03 [[BSS_PR:00 00 00 0a]] [[BSS_WSA]] 00 00 00 00
+; CHECK-NEXT: 000380 00 00 00 00 00 00 00 00 [[BSS_LEN:00 00 00 08]] 00 00 00 00
+; CHECK-NEXT: 000390 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK-NEXT: 0003a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
+; CHECK-NEXT: 0003b0 00 03 23 00 00 00 00 03 82 a2 a2 00 00 00 00 00
+
+; ESD record, type ED.
+; The name is C_WSA64.
+; CHECK-NEXT: 0003c0 03 00 00 01 [[C_WSA64:00 00 00 0b]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 0003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0003e0 00 00 00 00 00 00 00 00 03 81 00 00 00 00 00 00
+; CHECK-NEXT: 0003f0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00
+; CHECK-NEXT: 000400 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; ESD record, type PR.
+; The name is test#S.
+; CHECK-NEXT: 000410 03 00 00 03 [[TESTS:00 00 00 0c]] [[C_WSA64]] 00 00 00 00
+; CHECK-NEXT: 000420 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00
+; CHECK-NEXT: 000430 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK-NEXT: 000440 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
+; CHECK-NEXT: 000450 00 01 24 00 00 00 00 06 a3 85 a2 a3 7b e2 00 00
+
+; ESD record, type ED.
+; The name is B_IDRL.
+; CHECK-NEXT: 000460 03 00 00 01 [[BIDRL:00 00 00 0d]] [[ROOTSD]] 00 00 00 00
+; CHECK-NEXT: 000470 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00
+; CHECK-NEXT: 000480 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00
+; CHECK-NEXT: 000490 00 00 00 00 00 00 00 00 00 00 00 00 00 04 10 08
+; CHECK-NEXT: 0004a0 00 80 03 00 00 00 00 06 c2 6d c9 c4 d9 d3 00 00
+
+; ESD record, type LD.
+; The name is test#C.
+; CHECK-NEXT: 0004b0 03 00 00 02 [[TESTC:00 00 00 0e]] [[C_CODE64]] 00 00 00 00
+; CHECK-NEXT: 0004c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0004d0 00 00 00 00 00 00 00 00 01 00 00 00 [[TESTS]]
+; CHECK-NEXT: 0004e0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK-NEXT: 0004f0 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00
+
+; End record.
+; CHECK-NEXT: 000500 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000520 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000540 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

diff  --git a/llvm/test/CodeGen/SystemZ/zos-simple-test.ll b/llvm/test/CodeGen/SystemZ/zos-simple-test.ll
index a46079818b130..f1f7cee8268f7 100644
--- a/llvm/test/CodeGen/SystemZ/zos-simple-test.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-simple-test.ll
@@ -5,9 +5,13 @@
 @a = global i32 0, align 4
 
 define signext i32 @main() {
-; CHECK: .section ".text"
+; CHECK: stdin#C CSECT
+; CHECK: C_CODE64 CATTR ALIGN(3),FILL(0),READONLY,RMODE(64)
 ; CHECK: main:
-; CHECK: .section "a"
+; CHECK: stdin#C CSECT
+; CHECK: C_WSA64 CATTR ALIGN(2),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(a)
+; CHECK: a XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(EXPORT)
+; CHECK: a:
 entry:
   ret i32 0
 }

diff  --git a/llvm/test/MC/GOFF/empty-goff.s b/llvm/test/MC/GOFF/empty-goff.s
index f6d402863d71c..ba1b0e0a49077 100644
--- a/llvm/test/MC/GOFF/empty-goff.s
+++ b/llvm/test/MC/GOFF/empty-goff.s
@@ -17,8 +17,8 @@
 *  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
+* CHECK: {{([[:xdigit:]]{6})}} 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


        


More information about the llvm-commits mailing list