[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
Mon Mar 25 01:58:05 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);
----------------
uweigand wrote:

My question was not really about the resulting GOFF, but rather about the structure of the LLVM implementation.  Specifically, should the PR GOFF symbol be generated in writeSectionSymbols or rather in writeSymbolDefinedInModule like the other PR GOFF symbols?

That said, your comment raises a couple of other questions in my mind:
- I don't know why we would want to characterize LD as a "section" - it doesn't own any TXT records.  I'd been considering ED as the "section" for text, and PR as the "section" for static data (i.e. those GOFF symbols that own TXT).  The LD seems much more clearly equivalent to a symbol inside the text section.
- The concatenate vs. merge distinction is triggered by the BindAlgorithm flag (ESD_BA_Concatenate vs. ESD_BA_Merge) rather than the symbol type (ED/LD/PR), isn't it?   

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


More information about the llvm-commits mailing list