[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 21:58:10 PDT 2024


================
@@ -259,6 +633,411 @@ void GOFFObjectWriter::writeHeader() {
   OS.write_zeros(6);       // Reserved
 }
 
+void GOFFObjectWriter::writeSymbol(const GOFFSymbol &Symbol,
+                                   const MCAsmLayout &Layout) {
+  uint32_t Offset = 0;
+  uint32_t Length = 0;
+  GOFF::ESDNameSpaceId NameSpaceId = GOFF::ESD_NS_ProgramManagementBinder;
+  Flags SymbolFlags;
+  uint8_t FillByteValue = 0;
+
+  Flags BehavAttrs[10] = {};
+  auto setAmode = [&BehavAttrs](GOFF::ESDAmode Amode) {
+    BehavAttrs[0].set(0, 8, Amode);
+  };
+  auto setRmode = [&BehavAttrs](GOFF::ESDRmode Rmode) {
+    BehavAttrs[1].set(0, 8, Rmode);
+  };
+  auto setTextStyle = [&BehavAttrs](GOFF::ESDTextStyle Style) {
+    BehavAttrs[2].set(0, 4, Style);
+  };
+  auto setBindingAlgorithm =
+      [&BehavAttrs](GOFF::ESDBindingAlgorithm Algorithm) {
+        BehavAttrs[2].set(4, 4, Algorithm);
+      };
+  auto setTaskingBehavior =
+      [&BehavAttrs](GOFF::ESDTaskingBehavior TaskingBehavior) {
+        BehavAttrs[3].set(0, 3, TaskingBehavior);
+      };
+  auto setReadOnly = [&BehavAttrs](bool ReadOnly) {
+    BehavAttrs[3].set(4, 1, ReadOnly);
+  };
+  auto setExecutable = [&BehavAttrs](GOFF::ESDExecutable Executable) {
+    BehavAttrs[3].set(5, 3, Executable);
+  };
+  auto setDuplicateSeverity =
+      [&BehavAttrs](GOFF::ESDDuplicateSymbolSeverity DSS) {
+        BehavAttrs[4].set(2, 2, DSS);
+      };
+  auto setBindingStrength = [&BehavAttrs](GOFF::ESDBindingStrength Strength) {
+    BehavAttrs[4].set(4, 4, Strength);
+  };
+  auto setLoadingBehavior = [&BehavAttrs](GOFF::ESDLoadingBehavior Behavior) {
+    BehavAttrs[5].set(0, 2, Behavior);
+  };
+  auto setIndirectReference = [&BehavAttrs](bool Indirect) {
+    uint8_t Value = Indirect ? 1 : 0;
+    BehavAttrs[5].set(3, 1, Value);
+  };
+  auto setBindingScope = [&BehavAttrs](GOFF::ESDBindingScope Scope) {
+    BehavAttrs[5].set(4, 4, Scope);
+  };
+  auto setLinkageType = [&BehavAttrs](GOFF::ESDLinkageType Type) {
+    BehavAttrs[6].set(2, 1, Type);
+  };
+  auto setAlignment = [&BehavAttrs](GOFF::ESDAlignment Alignment) {
+    BehavAttrs[6].set(3, 5, Alignment);
+  };
+
+  uint32_t AdaEsdId = 0;
+  uint32_t SortPriority = 0;
+
+  switch (Symbol.SymbolType) {
+  case GOFF::ESD_ST_SectionDefinition: {
+    if (Symbol.isExecutable()) // Unspecified otherwise
+      setTaskingBehavior(GOFF::ESD_TA_Rent);
+    if (Symbol.BindingScope == GOFF::ESD_BSC_Section)
+      setBindingScope(Symbol.BindingScope);
+  } break;
+  case GOFF::ESD_ST_ElementDefinition: {
+    SymbolFlags.set(3, 1, Symbol.isRemovable()); // Removable
+    if (Symbol.isExecutable()) {
+      setExecutable(GOFF::ESD_EXE_CODE);
+      setReadOnly(true);
+    } else {
+      if (Symbol.isExecUnspecified())
+        setExecutable(GOFF::ESD_EXE_Unspecified);
+      else
+        setExecutable(GOFF::ESD_EXE_DATA);
+
+      if (Symbol.isForceRent() || Symbol.isReadOnly()) // TODO
+        setReadOnly(true);
+    }
+    Offset = 0; // TODO ED and SD are 1-1 for now
+    setAlignment(Symbol.Alignment);
+    SymbolFlags.set(0, 1, 1); // Fill-Byte Value Presence Flag
+    FillByteValue = 0;
+    SymbolFlags.set(1, 1, 0); // Mangled Flag TODO ?
+    setAmode(Symbol.Amode);
+    setRmode(Symbol.Rmode);
+    setTextStyle(Symbol.TextStyle);
+    setBindingAlgorithm(Symbol.BindAlgorithm);
+    setLoadingBehavior(Symbol.LoadBehavior);
+    SymbolFlags.set(5, 3, GOFF::ESD_RQ_0); // Reserved Qwords
+    if (Symbol.isForceRent())
+      setReadOnly(true);
+    NameSpaceId = Symbol.NameSpace;
+    Length = Symbol.SectionLength;
+    break;
+  }
+  case GOFF::ESD_ST_LabelDefinition: {
+    if (Symbol.isExecutable())
+      setExecutable(GOFF::ESD_EXE_CODE);
+    else
+      setExecutable(GOFF::ESD_EXE_DATA);
+    setBindingStrength(Symbol.BindingStrength);
+    setLinkageType(Symbol.Linkage);
+    SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable;
+    setAmode(Symbol.Amode);
+    NameSpaceId = Symbol.NameSpace;
+    setBindingScope(Symbol.BindingScope);
+    AdaEsdId = Symbol.ADAEsdId;
+
+    // Only symbol that doesn't have an MC is the SectionLabelSymbol which
+    // implicitly has 0 offset into the parent SD!
+    if (auto *MCSym = Symbol.MCSym) {
+      uint64_t Ofs = Layout.getSymbolOffset(*MCSym);
+      // We only have signed 32bits of offset!
+      assert(Ofs < (((uint64_t)1) << 31) && "ESD offset out of range.");
+      Offset = static_cast<uint32_t>(Ofs);
+    }
+    break;
+  }
+  case GOFF::ESD_ST_ExternalReference: {
+    setExecutable(Symbol.isExecutable() ? GOFF::ESD_EXE_CODE
+                                        : GOFF::ESD_EXE_DATA);
+    setBindingStrength(Symbol.BindingStrength);
+    setLinkageType(Symbol.Linkage);
+    SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable;
+    setIndirectReference(Symbol.Indirect);
+    Offset = 0; // ERs don't do offsets
+    NameSpaceId = Symbol.NameSpace;
+    setBindingScope(Symbol.BindingScope);
+    setAmode(Symbol.Amode);
+    break;
+  }
+  case GOFF::ESD_ST_PartReference: {
+    setExecutable(Symbol.isExecutable() ? GOFF::ESD_EXE_CODE
+                                        : GOFF::ESD_EXE_DATA);
+    NameSpaceId = Symbol.NameSpace;
+    setAlignment(Symbol.Alignment);
+    setAmode(Symbol.Amode);
+    setLinkageType(Symbol.Linkage);
+    setBindingScope(Symbol.BindingScope);
+    SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable;
+    setDuplicateSeverity(Symbol.isWeakRef() ? GOFF::ESD_DSS_NoWarning
+                                            : GOFF::ESD_DSS_Warning);
+    setIndirectReference(Symbol.Indirect);
+    setReadOnly(Symbol.ReadOnly);
+    SortPriority = Symbol.SortKey;
+
+    Length = Symbol.SectionLength;
+    break;
+  }
+  } // End switch
+
+  SmallString<256> Res;
+  ConverterEBCDIC::convertToEBCDIC(Symbol.Name, Res);
+  StringRef Name = Res.str();
+
+  // Assert here since this number is technically signed but we need uint for
+  // writing to records.
+  assert(Name.size() < GOFF::MaxDataLength &&
+         "Symbol max name length exceeded");
+  uint16_t NameLength = Name.size();
+
+  OS.newRecord(GOFF::RT_ESD, GOFF::ESDMetadataLength + NameLength);
+  OS.writebe<uint8_t>(Symbol.SymbolType);       // Symbol Type
+  OS.writebe<uint32_t>(Symbol.EsdId);           // ESDID
+  OS.writebe<uint32_t>(Symbol.ParentEsdId);     // Parent or Owning ESDID
+  OS.writebe<uint32_t>(0);                      // Reserved
+  OS.writebe<uint32_t>(Offset);                 // Offset or Address
+  OS.writebe<uint32_t>(0);                      // Reserved
+  OS.writebe<uint32_t>(Length);                 // Length
+  OS.writebe<uint32_t>(Symbol.EASectionEsdId);  // Extended Attribute ESDID
+  OS.writebe<uint32_t>(Symbol.EASectionOffset); // Extended Attribute Offset
+  OS.writebe<uint32_t>(0);                      // Reserved
+  OS.writebe<uint8_t>(NameSpaceId);             // Name Space ID
+  OS.writebe<uint8_t>(SymbolFlags);             // Flags
+  OS.writebe<uint8_t>(FillByteValue);           // Fill-Byte Value
+  OS.writebe<uint8_t>(0);                       // Reserved
+  OS.writebe<uint32_t>(AdaEsdId);               // ADA ESDID
+  OS.writebe<uint32_t>(SortPriority);           // Sort Priority
+  OS.writebe<uint64_t>(0);                      // Reserved
+  for (auto F : BehavAttrs)
+    OS.writebe<uint8_t>(F);          // Behavioral Attributes
+  OS.writebe<uint16_t>(NameLength);  // Name Length
+  OS.write(Name.data(), NameLength); // Name
+}
+
+void GOFFObjectWriter::writeADAandCodeSectionSymbols(
+    MCAssembler &Asm, const MCAsmLayout &Layout) {
+  // Write ESD Records for ADA Section
+  GOFFSymbol ADAED = createWSASymbol(RootSD.EsdId, true);
+  StringRef FileName = "";
+  if (!Asm.getFileNames().empty())
+    FileName = sys::path::stem((*(Asm.getFileNames().begin())).first);
+  std::pair<std::string, std::string> CsectNames = Asm.getCsectNames();
+
+  GOFFSymbol ADA;
+  if (CsectNames.second.empty()) {
+    ADA = createPRSymbol(FileName.str().append("#S"), ADAED.EsdId);
+    ADA.BindingScope = GOFF::ESD_BSC_Section;
+  } else {
+    ADA = createPRSymbol(CsectNames.second, ADAED.EsdId);
+    ADA.BindingScope = GOFF::ESD_BSC_Library;
+  }
+  ADA.Executable = GOFF::ESD_EXE_DATA;
+  ADA.NameSpace = GOFF::ESD_NS_Parts;
+  ADA.Alignment = GOFF::ESD_ALIGN_Quadword;
+
+  ADA.SectionLength = std::max(getADASectionLength(Asm, Layout), 2u);
+  writeSymbol(ADAED, Layout);
+  writeSymbol(ADA, Layout);
+
+  // Write ESD Records for Code Section
+  GOFFSymbol ED = createEDSymbol("C_CODE64", RootSD.EsdId);
+  ED.SectionLength = 0;
+  ED.Executable = GOFF::ESD_EXE_CODE;
+  ED.ForceRent = true;
+
+  for (const MCSection &MCSec : Asm) {
+    SectionKind Kind = MCSec.getKind();
+    if (Kind.isText()) {
+      if (!ED.SectionLength)
+        ED.SectionLength = Layout.getSectionAddressSize(&MCSec);
+    }
+  }
+
+  GOFFSymbol LD = createLDSymbol(RootSD.Name, ED.EsdId);
+  LD.Executable = GOFF::ESD_EXE_CODE;
+  if (RootSD.BindingScope == GOFF::ESD_BSC_Section)
+    LD.BindingScope = GOFF::ESD_BSC_Section;
+  else
+    LD.BindingScope = GOFF::ESD_BSC_Library;
+
+  LD.ADAEsdId = GOFFObjectWriter::ADAEsdId;
+
+  EntryEDEsdId = ED.EsdId;
+  CodeLDEsdId = LD.EsdId;
+  writeSymbol(ED, Layout);
+  writeSymbol(LD, Layout);
+}
+
+void GOFFObjectWriter::writeSectionSymbols(MCAssembler &Asm,
+                                           const MCAsmLayout &Layout) {
+  bool IsOSLinkageType = false;
+  for (MCSection &S : Asm) {
+    auto &Section = cast<MCSectionGOFF>(S);
+    SectionKind Kind = Section.getKind();
+
+    if (Kind.isText()) {
+      // The only text section is the code section and the relevant ESD Records
+      // are already created. All we need to do is populate the SectionMap.
+      uint32_t RootSDEsdId = RootSD.EsdId;
+
+      GOFFSection GoffSec = GOFFSection(EntryEDEsdId, CodeLDEsdId, RootSDEsdId);
+      SectionMap.insert(std::make_pair(&Section, GoffSec));
+    } else if (Section.getName().starts_with(".lsda")) {
+      GOFFSymbol SD = RootSD;
+
+      const char *WSAClassName = "C_WSA64";
+      GOFFSymbol ED = createEDSymbol(WSAClassName, SD.EsdId);
+      if (IsOSLinkageType)
+        ED.LoadBehavior = GOFF::ESDLoadingBehavior::ESD_LB_Deferred;
+      ED.BindAlgorithm = GOFF::ESD_BA_Merge;
+      ED.Executable = GOFF::ESD_EXE_DATA;
+      ED.NameSpace = GOFF::ESD_NS_Parts;
+
+      GOFFSymbol PR = createPRSymbol(Section.getName(), ED.EsdId);
----------------
Everybody0523 wrote:

**Short Answer**
MCSections map to a tuple of (SD, ED, LD/PR). Both can be valid but there is a functional difference (at least by the binder) for whether or not LD or PR is used.

**Longer Answer**
MCSections map to a tuple of (SD, ED, LD/PR). Such a tuple maps to a "GOFF section" (aside: my understanding is that the preferred term by the binder for this is a _Class_). Note these can have the same SD symbol, or even ED symbol, you need all three to define a section. The SD symbol owns the ED symbol, and the ED symbol owns the PR/LD symbol.

The difference is that if the third item is a LD symbol, the above is called a CAT class and when it is a PR symbol, it's a MRG class. When the binder tries to bind two different compilation units, and it sees two identically named classes in both compilation units (ie. SD and ED have same names), in the case of a CAT class it will just concatenate everything. On the other hand, in the case of a MRG class it will first merge and align PR elements with the same name in both CUs before concatenating them with other PR items. 

![image](https://github.com/llvm/llvm-project/assets/22278196/be55a7b5-e05c-49bd-9d97-f6062989bb25)

`C_MYCODE/DATA` are CAT classes and `C_EXTDATA` is a MRG class.

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


More information about the llvm-commits mailing list