[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:33 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;
----------------
uweigand wrote:
Why does this have to be a known constant? Is this a requirement of the format? It seems more coincidental given the way code chooses to write out sections ...
https://github.com/llvm/llvm-project/pull/85851
More information about the llvm-commits
mailing list