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

Ulrich Weigand via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 22 06:51:34 PDT 2024


================
@@ -217,34 +222,403 @@ 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);
+  }
+
+  void setAlignment(Align A) {
+    // The GOFF alignment is encoded as log_2 value.
+    uint8_t Log = Log2(A);
+    if (Log <= GOFF::ESD_ALIGN_4Kpage)
+      Alignment = static_cast<GOFF::ESDAlignment>(Log);
+    else
+      llvm_unreachable("Unsupported 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 GOFFSymbols.  Needed to determine EsdIds
+  /// of symbols in Relocations.
+  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 EntryEDEsdId;
+  uint32_t CodeLDEsdId;
+
 public:
   GOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
                    raw_pwrite_stream &OS)
       : TargetObjectWriter(std::move(MOTW)), OS(OS) {}
 
   ~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:
+  GOFFSection *createGOFFSection(GOFFSymbol *Pptr, GOFFSymbol *Rptr,
+                                 GOFFSymbol *SD, const MCSectionGOFF *MC);
+  GOFFSymbol createGOFFSymbol(StringRef Name, GOFF::ESDSymbolType Type,
+                              uint32_t ParentEsdId);
+  GOFFSymbol createSDSymbol(StringRef Name);
+  GOFFSymbol createEDSymbol(StringRef Name, uint32_t ParentEsdId);
+  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 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 defineSectionSymbols(const MCAssembler &Asm,
+                            const MCSectionGOFF &Section,
+                            const MCAsmLayout &Layout);
+  void writeSymbolDefinedInModule(const MCSymbolGOFF &Symbol, MCAssembler &Asm,
+                                  const MCAsmLayout &Layout);
+  void writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol, MCAssembler &Asm,
+                                   const MCAsmLayout &Layout);
+
+  // In XPLINK, the ESD Record owning the ADA is always the 4th record, behind
+  // the HDR record, the Root SD, and the ED symbol for the ADA, meaning it
+  // always has EsdId = 3.
+  static constexpr uint32_t ADAEsdId = 3u;
 };
 } // 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) {
+  GOFFSymbol ED =
+      createGOFFSymbol(Name, GOFF::ESD_ST_ElementDefinition, ParentEsdId);
+
+  ED.Alignment = GOFF::ESD_ALIGN_Doubleword;
+  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::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) {
+  for (MCSection &S : Asm)
+    if (S.getName().equals(".ada"))
+      return Layout.getSectionAddressSize(&S);
+  return 0;
+}
+
+void GOFFObjectWriter::defineRootSD(MCAssembler &Asm,
+                                    const MCAsmLayout &Layout) {
+  StringRef FileName = "";
+  if (!Asm.getFileNames().empty())
+    FileName = sys::path::stem((*(Asm.getFileNames().begin())).first);
+  std::pair<std::string, std::string> CsectNames = Asm.getCsectNames();
+  if (CsectNames.first.empty()) {
+    RootSD = createSDSymbol(FileName.str().append("#C"));
+    RootSD.BindingScope = GOFF::ESD_BSC_Section;
+  } else {
+    RootSD = createSDSymbol(CsectNames.first);
+  }
+  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 = GOFFObjectWriter::ADAEsdId;
+
+    if (Symbol.getName().equals("main")) {
----------------
uweigand wrote:

This seems weird.  The name "main" is only special in some programming languages - if anything special is needed here, that should use a more generic mechanism.

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


More information about the llvm-commits mailing list