[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
Fri Mar 22 10:28:38 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;
----------------
Everybody0523 wrote:

GOFF alone doesn't require any particular position for the ADA section beyond the fact that any externally visible symbol (in the case of C for example, non-static function or global variable) must be defined after it. In fact, the legacy compiler always defines this section second, so the ADAEsdId would always be 5. This difference doesn't make any functional difference and doesn't break compatibility in any way though.

However, here will always be emitting this section first, so this is (practically speaking) a constant. 

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


More information about the llvm-commits mailing list