[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
Tue Mar 19 12:30:22 PDT 2024
https://github.com/Everybody0523 created https://github.com/llvm/llvm-project/pull/85851
This PR implements generation of ESD/TXT Records in GOFF Writer.
A few notes on GOFF and the overall design:
### GOFF Structure
GOFF (GOFF Object File Format) is is the object file format used on z/OS. GOFF files are built out of 80-byte records.
There are 5 types of records. They are:
1. HDR (Header)
2. ESD (External Symbol)
3. TXT (Text)
4. RLD (Relocation Data)
5. END (End).
The HDR and END records are present in every file, and are implemented already [by this commit](https://github.com/llvm/llvm-project/commit/3adc2a0b84d0fbccead5d77d1b7d7a9b0bec175d).
ESD and TXT records have a notion of "ownership", which means that an ESD symbol can be "owned" another ESD symbol. TXT records are always owned by an ESD symbol.
GOFF doesn't truly have "sections" or "symbols" in the way other object file formats do, although it does have something vaguely analogous, which will be discussed below.
### MCSymbol handling
An MCSymbol _mostly_ maps to one (or more) ESD Record. Some types of symbols may cause more than one symbol to be generated. In addition, every compilation unit has a few special symbols that are used by the binder.
### MCSection handling
GOFF "sections" are defined by a triple of ESD Symbols. Specifically, each section is defined by an SD symbol, an ED symbol, and a PR or LD symbol. The PR/LD symbol's parent should be the ED symbol and the ED symbol's parent should be the SD symbol. Furthermore, the PR/LD symbol should own a TXT record. The contents of the section reside in that TXT record. The SD symbol need not be unique to the section; in fact it is quite common that multiple GOFF sections are are "rooted" and the initial SD node (ie. the first ESD entry).
Some examples of "sections" are:
- Global Variables. Each global variable with external linkage has its own section.
- The "code section". The code section is a code csect with the default name `<filename>#C` The bodies of all functions reside in this section.
- The ADA section. This is a section that contains a pointer to the body of each function as well as metadata relevant to that function.
>From adf262bb65cfc5a2adfabc9ec10eab79533d1371 Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Tue, 19 Mar 2024 12:03:05 -0400
Subject: [PATCH] new attempt for implementing ESD+TXT
---
llvm/include/llvm/BinaryFormat/GOFF.h | 16 +-
llvm/include/llvm/CodeGen/AsmPrinter.h | 5 +-
llvm/include/llvm/MC/MCAssembler.h | 7 +
llvm/include/llvm/MC/MCContext.h | 3 +-
llvm/include/llvm/MC/MCGOFFStreamer.h | 11 +-
llvm/include/llvm/MC/MCSymbolGOFF.h | 55 +-
.../CodeGen/TargetLoweringObjectFileImpl.cpp | 8 +-
llvm/lib/MC/GOFFObjectWriter.cpp | 807 +++++++++++++++++-
llvm/lib/MC/MCGOFFStreamer.cpp | 76 ++
llvm/lib/MC/MCObjectFileInfo.cpp | 3 +
.../SystemZ/MCTargetDesc/SystemZMCExpr.cpp | 4 +
.../SystemZ/MCTargetDesc/SystemZMCExpr.h | 2 +
llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 99 ++-
llvm/lib/Target/SystemZ/SystemZAsmPrinter.h | 4 +
llvm/test/MC/GOFF/basic-goff-64.ll | 252 ++++++
llvm/test/MC/GOFF/empty-goff.s | 39 +-
16 files changed, 1351 insertions(+), 40 deletions(-)
create mode 100644 llvm/test/MC/GOFF/basic-goff-64.ll
diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h
index 443bcfc9479a8b..b0cd2484536ea2 100644
--- a/llvm/include/llvm/BinaryFormat/GOFF.h
+++ b/llvm/include/llvm/BinaryFormat/GOFF.h
@@ -29,6 +29,8 @@ constexpr uint8_t RecordLength = 80;
constexpr uint8_t RecordPrefixLength = 3;
constexpr uint8_t PayloadLength = 77;
constexpr uint8_t RecordContentLength = RecordLength - RecordPrefixLength;
+constexpr uint8_t ESDMetadataLength = 69;
+constexpr uint8_t TXTMetadataLength = 21;
/// \brief Maximum data length before starting a new card for RLD and TXT data.
///
@@ -65,12 +67,7 @@ enum ESDNameSpaceId : uint8_t {
ESD_NS_Parts = 3
};
-enum ESDReserveQwords : uint8_t {
- ESD_RQ_0 = 0,
- ESD_RQ_1 = 1,
- ESD_RQ_2 = 2,
- ESD_RQ_3 = 3
-};
+enum ESDReserveQwords : uint8_t { ESD_RQ_0 = 0, ESD_RQ_1 = 1 };
enum ESDAmode : uint8_t {
ESD_AMODE_None = 0,
@@ -157,6 +154,12 @@ enum ESDAlignment : uint8_t {
ESD_ALIGN_4Kpage = 12,
};
+enum TXTRecordStyle : uint8_t {
+ TXT_RS_Byte = 0,
+ TXT_RS_Structured = 1,
+ TXT_RS_Unstructured = 2,
+};
+
enum ENDEntryPointRequest : uint8_t {
END_EPR_None = 0,
END_EPR_EsdidOffset = 1,
@@ -166,6 +169,7 @@ enum ENDEntryPointRequest : uint8_t {
// \brief Subsections of the primary C_CODE section in the object file.
enum SubsectionKind : uint8_t {
+ SK_ReadOnly = 1,
SK_PPA1 = 2,
SK_PPA2 = 4,
};
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index a7fbf4aeb74494..0fb696bbb68b13 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -897,10 +897,13 @@ class AsmPrinter : public MachineFunctionPass {
virtual void emitModuleCommandLines(Module &M);
GCMetadataPrinter *getOrCreateGCPrinter(GCStrategy &S);
+
+protected:
virtual void emitGlobalAlias(const Module &M, const GlobalAlias &GA);
- void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
private:
+ void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
+
/// This method decides whether the specified basic block requires a label.
bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const;
diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h
index 3fa5f2fe655e86..7c1b6bdb3ffb60 100644
--- a/llvm/include/llvm/MC/MCAssembler.h
+++ b/llvm/include/llvm/MC/MCAssembler.h
@@ -136,6 +136,9 @@ class MCAssembler {
// Optional compiler version.
std::string CompilerVersion;
+ /// GOFF Csect names.
+ std::pair<std::string, std::string> CsectNames;
+
MCDwarfLineTableParams LTParams;
/// The set of function symbols for which a .thumb_func directive has
@@ -488,6 +491,10 @@ class MCAssembler {
FileNames.emplace_back(std::string(FileName), Symbols.size());
}
+ std::pair<std::string, std::string> const &getCsectNames() {
+ return CsectNames;
+ }
+
void setCompilerVersion(std::string CompilerVers) {
if (CompilerVersion.empty())
CompilerVersion = std::move(CompilerVers);
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 3f585d4d2efaf5..e9c7c96298d683 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -623,7 +623,8 @@ class MCContext {
unsigned EntrySize);
MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
- MCSection *Parent, const MCExpr *SubsectionId);
+ MCSection *Parent = nullptr,
+ const MCExpr *SubsectionId = nullptr);
MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
SectionKind Kind, StringRef COMDATSymName,
diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h
index 2345509b161da5..52cde0632483a0 100644
--- a/llvm/include/llvm/MC/MCGOFFStreamer.h
+++ b/llvm/include/llvm/MC/MCGOFFStreamer.h
@@ -24,12 +24,15 @@ class MCGOFFStreamer : public MCObjectStreamer {
~MCGOFFStreamer() override;
- bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
- return false;
- }
+ // state management
+ void initSections(bool NoExecStack, const MCSubtargetInfo &STI) override;
+
+ void switchSection(MCSection *Section,
+ const MCExpr *Subsection = nullptr) override;
+ bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override {}
- void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override {}
+ void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override;
void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
uint64_t Size = 0, Align ByteAlignment = Align(1),
SMLoc Loc = SMLoc()) override {}
diff --git a/llvm/include/llvm/MC/MCSymbolGOFF.h b/llvm/include/llvm/MC/MCSymbolGOFF.h
index cc4e2bbe246e2d..bb3c3b07947aa3 100644
--- a/llvm/include/llvm/MC/MCSymbolGOFF.h
+++ b/llvm/include/llvm/MC/MCSymbolGOFF.h
@@ -18,10 +18,63 @@
namespace llvm {
class MCSymbolGOFF : public MCSymbol {
+ Align Alignment;
+
+ mutable StringRef AliasName; // ADA indirect
+
+ enum SymbolFlags : uint16_t {
+ SF_NoRent = 0x01, // Symbol is no-reentrant.
+ SF_Alias = 0x02, // Symbol is alias.
+ SF_Hidden = 0x04, // Symbol is hidden, aka not exported.
+ SF_Weak = 0x08, // Symbol is weak.
+ SF_OSLinkage = 0x10, // Symbol uses OS linkage.
+ };
+
+ // Shift value for GOFF::ESDExecutable. 3 possible values. 2 bits.
+ static constexpr uint8_t GOFF_Executable_Shift = 6;
+ static constexpr uint8_t GOFF_Executable_Bitmask = 0x03;
+
public:
MCSymbolGOFF(const StringMapEntry<bool> *Name, bool IsTemporary)
- : MCSymbol(SymbolKindGOFF, Name, IsTemporary) {}
+ : MCSymbol(SymbolKindGOFF, Name, IsTemporary), AliasName() {}
static bool classof(const MCSymbol *S) { return S->isGOFF(); }
+
+ bool hasAliasName() const { return !AliasName.empty(); }
+ void setAliasName(StringRef Name) { AliasName = Name; }
+ StringRef getAliasName() const { return AliasName; }
+
+ void setTemporary(bool Value) { IsTemporary = Value; }
+
+ void setOSLinkage(bool Value = true) const {
+ modifyFlags(Value ? SF_OSLinkage : 0, SF_OSLinkage);
+ }
+ bool isOSLinkage() const { return getFlags() & SF_OSLinkage; }
+
+ void setAlignment(Align Value) { Alignment = Value; }
+ Align getAlignment() const { return Alignment; }
+
+ void setExecutable(GOFF::ESDExecutable Value) const {
+ modifyFlags(Value << GOFF_Executable_Shift,
+ GOFF_Executable_Bitmask << GOFF_Executable_Shift);
+ }
+ GOFF::ESDExecutable getExecutable() const {
+ return static_cast<GOFF::ESDExecutable>(
+ (getFlags() >> GOFF_Executable_Shift) & GOFF_Executable_Bitmask);
+ }
+
+ void setHidden(bool Value = true) {
+ modifyFlags(Value ? SF_Hidden : 0, SF_Hidden);
+ }
+ bool isHidden() const { return getFlags() & SF_Hidden; }
+ bool isExported() const { return !isHidden(); }
+
+ void setWeak(bool Value = true) { modifyFlags(Value ? SF_Weak : 0, SF_Weak); }
+ bool isWeak() const { return getFlags() & SF_Weak; }
+
+ void setAlias(bool Value = true) {
+ modifyFlags(Value ? SF_Alias : 0, SF_Alias);
+ }
+ bool isAlias() const { return getFlags() & SF_Alias; }
};
} // end namespace llvm
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 15b59421a0f44a..3b4f7faa99d590 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2744,9 +2744,13 @@ MCSection *TargetLoweringObjectFileGOFF::getSectionForLSDA(
MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
auto *Symbol = TM.getSymbol(GO);
+ if (Kind.isData())
+ return getContext().getGOFFSection(Symbol->getName(),
+ SectionKind::getData());
+
if (Kind.isBSS())
- return getContext().getGOFFSection(Symbol->getName(), SectionKind::getBSS(),
- nullptr, nullptr);
+ return getContext().getGOFFSection(Symbol->getName(),
+ SectionKind::getBSS());
return getContext().getObjectFileInfo()->getTextSection();
}
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
index addeb6db959693..60ab410e9765e2 100644
--- a/llvm/lib/MC/GOFFObjectWriter.cpp
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -13,8 +13,13 @@
#include "llvm/BinaryFormat/GOFF.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCGOFFObjectWriter.h"
+#include "llvm/MC/MCSectionGOFF.h"
+#include "llvm/MC/MCSymbolGOFF.h"
#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ConvertEBCDIC.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Path.h"
@@ -217,13 +222,112 @@ 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)
@@ -231,20 +335,290 @@ class GOFFObjectWriter : public MCObjectWriter {
~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")) {
+ LD.BindingScope = GOFF::ESD_BSC_Library;
+ LD.Renamable = true;
+ }
+
+ LD.MCSym = &Symbol;
+ SymbolMap.insert(std::make_pair(&Symbol, LD.EsdId));
+ writeSymbol(LD, Layout);
+ } else if ((Kind.isBSS() || Kind.isData()) && Symbol.isAlias()) {
+ // Alias to variable at the object file level.
+ // Not supported in RENT mode.
+ llvm_unreachable("Alias to rent variable is unsupported");
+ } else if (Kind.isBSS() || Kind.isData()) {
+ std::string SectionName = Section.getName().str();
+ GOFFSymbol SD = createSDSymbol(SectionName);
+ auto BindingScope = Symbol.isExternal()
+ ? (Symbol.isExported() ? GOFF::ESD_BSC_ImportExport
+ : GOFF::ESD_BSC_Library)
+ : GOFF::ESD_BSC_Section;
+ if (!Symbol.isExternal())
+ SD.BindingScope = GOFF::ESD_BSC_Section;
+
+ GOFFSymbol ED = createWSASymbol(SD.EsdId);
+ GOFFSymbol PR = createPRSymbol(SectionName, ED.EsdId);
+ ED.Alignment =
+ std::max(static_cast<GOFF::ESDAlignment>(Log2(Section.getAlign())),
+ GOFF::ESD_ALIGN_Quadword);
+
+ PR.Executable = GOFF::ESD_EXE_DATA;
+ PR.NameSpace = GOFF::ESD_NS_Parts;
+ PR.BindingScope = BindingScope;
+ PR.setAlignment(Symbol.getAlignment());
+ PR.SectionLength = Layout.getSectionAddressSize(&Section);
+
+ // As above, avoid zero-length sections for data.
+ if (!PR.SectionLength)
+ PR.SectionLength = 2;
+
+ writeSymbol(SD, Layout);
+ writeSymbol(ED, Layout);
+ writeSymbol(PR, Layout);
+
+ SymbolMap.insert(std::make_pair(&Symbol, PR.EsdId));
+ GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
+ SectionMap.insert(std::make_pair(&Section, GoffSec));
+ } else
+ llvm_unreachable("Unhandled section kind for Symbol");
+}
+
+void GOFFObjectWriter::writeSymbolDeclaredInModule(const MCSymbolGOFF &Symbol,
+ MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ GOFFSymbol SD = RootSD;
+
+ GOFF::ESDExecutable Exec = Symbol.getExecutable();
+
+ GOFFSymbol GSym;
+ uint32_t GSymEsdId = 0;
+ switch (Exec) {
+ case GOFF::ESD_EXE_CODE:
+ case GOFF::ESD_EXE_Unspecified: {
+ bool IsIndirectSymbol = Symbol.hasAliasName();
+ GOFFSymbol ER = createERSymbol(IsIndirectSymbol ? Symbol.getAliasName()
+ : Symbol.getName(),
+ SD.EsdId, &Symbol);
+ ER.BindingScope = GOFF::ESD_BSC_ImportExport;
+ GSym.Indirect = IsIndirectSymbol;
+ GSym = ER;
+ GSymEsdId = ER.EsdId;
+ break;
+ }
+ case GOFF::ESD_EXE_DATA: {
+ GOFFSymbol ED = createWSASymbol(SD.EsdId);
+ ED.setAlignment(Symbol.getAlignment());
+ writeSymbol(ED, Layout);
+ GOFFSymbol PR = createPRSymbol(Symbol.getName(), ED.EsdId);
+ PR.BindingScope = GOFF::ESD_BSC_ImportExport;
+ PR.setAlignment(Symbol.getAlignment());
+ PR.NameSpace = GOFF::ESD_NS_Parts;
+ PR.SectionLength = 0;
+ GSym = PR;
+ GSymEsdId = PR.EsdId;
+ break;
+ }
+ }
+
+ GSym.BindingScope =
+ Symbol.isExported() ? GOFF::ESD_BSC_ImportExport : GOFF::ESD_BSC_Library;
+
+ SymbolMap.insert(std::make_pair(&Symbol, GSymEsdId));
+ writeSymbol(GSym, Layout);
+}
+
+void GOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ LLVM_DEBUG(dbgs() << "Entering " << __FUNCTION__ << "\n");
+
+ defineRootSD(Asm, Layout);
+}
+
void GOFFObjectWriter::writeHeader() {
OS.newRecord(GOFF::RT_HDR, /*Size=*/57);
OS.write_zeros(1); // Reserved
@@ -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);
+ PR.Alignment = GOFF::ESD_ALIGN_Fullword;
+ PR.SectionLength = Layout.getSectionAddressSize(&Section);
+ PR.LoadBehavior = GOFF::ESD_LB_Deferred;
+ PR.NameSpace = GOFF::ESD_NS_Parts;
+ PR.BindingScope = GOFF::ESD_BSC_Section;
+
+ writeSymbol(ED, Layout);
+ writeSymbol(PR, Layout);
+
+ GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
+ SectionMap.insert(std::make_pair(&Section, GoffSec));
+ } else if (Section.getName().equals(".ppa2list")) {
+ StringRef EDSectionName = "C_@@QPPA2";
+ StringRef PRSectionName = ".&ppa2";
+ GOFFSymbol SD = RootSD;
+ GOFFSymbol ED = createEDSymbol(EDSectionName, SD.EsdId);
+ GOFFSymbol PR = createPRSymbol(PRSectionName, ED.EsdId);
+
+ // Set namespace
+ ED.NameSpace = GOFF::ESD_NS_Parts;
+ ED.BindAlgorithm = GOFF::ESD_BA_Merge;
+ ED.Executable = GOFF::ESD_EXE_DATA;
+ ED.ReadOnly = true;
+
+ PR.SectionLength = Layout.getSectionAddressSize(&Section);
+ PR.NameSpace = GOFF::ESD_NS_Parts;
+ PR.BindingScope = GOFF::ESD_BSC_Section;
+ PR.Alignment = GOFF::ESD_ALIGN_Doubleword;
+ PR.Renamable = true;
+ PR.Linkage = GOFF::ESD_LT_OS;
+
+ writeSymbol(ED, Layout);
+ writeSymbol(PR, Layout);
+
+ GOFFSection GoffSec = GOFFSection(PR.EsdId, PR.EsdId, SD.EsdId);
+ SectionMap.insert(std::make_pair(&Section, GoffSec));
+ } else if (Section.getName().equals("B_IDRL")) {
+ GOFFSymbol SD = RootSD;
+ GOFFSymbol ED = createEDSymbol("B_IDRL", SD.EsdId);
+ ED.Executable = GOFF::ESD_EXE_Unspecified;
+ ED.BindingScope = GOFF::ESD_BSC_Module;
+ ED.NameSpace = GOFF::ESD_NS_NormalName;
+ ED.BindAlgorithm = GOFF::ESD_BA_Concatenate;
+ ED.ReadOnly = true;
+ ED.SectionLength = Layout.getSectionAddressSize(&Section);
+ ED.TextStyle = GOFF::ESD_TS_Structured;
+ ED.LoadBehavior = GOFF::ESD_LB_NoLoad;
+
+ writeSymbol(ED, Layout);
+
+ GOFFSection GoffSec = GOFFSection(ED.EsdId, 0, 0);
+ SectionMap.insert(std::make_pair(&Section, GoffSec));
+ } else if (Section.getName().equals(".ada")) {
+ GOFFSection GoffSec = GOFFSection(
+ GOFFObjectWriter::ADAEsdId, GOFFObjectWriter::ADAEsdId, RootSD.EsdId);
+ SectionMap.insert(std::make_pair(&Section, GoffSec));
+ } else if (Kind.isBSS() || Kind.isData() || Kind.isThreadData()) {
+ // We handle this with the symbol definition, so there is no need to do
+ // anything here.
+ } else {
+ llvm_unreachable("Unhandled section kind");
+ }
+ }
+}
+
+namespace {
+/// Adapter stream to write a text section.
+class TextStream : public raw_ostream {
+ /// The underlying GOFFOstream.
+ GOFFOstream &OS;
+
+ /// The buffer size is the maximum number of bytes in a TXT section.
+ static constexpr size_t BufferSize = GOFF::MaxDataLength;
+
+ /// Static allocated buffer for the stream, used by the raw_ostream class. The
+ /// buffer is sized to hold the payload of a logical TXT record.
+ char Buffer[BufferSize];
+
+ /// The offset for the next TXT record. This is equal to the number of bytes
+ /// written.
+ size_t Offset;
+
+ /// The Esdid of the GOFF section.
+ const uint32_t EsdId;
+
+ /// The record style.
+ const GOFF::TXTRecordStyle RecordStyle;
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ uint64_t current_pos() const override { return Offset; }
+
+public:
+ explicit TextStream(GOFFOstream &OS, uint32_t EsdId,
+ GOFF::TXTRecordStyle RecordStyle)
+ : OS(OS), Offset(0), EsdId(EsdId), RecordStyle(RecordStyle) {
+ SetBuffer(Buffer, sizeof(Buffer));
+ }
+
+ ~TextStream() { flush(); }
+};
+
+void TextStream::write_impl(const char *Ptr, size_t Size) {
+ size_t WrittenLength = 0;
+
+ // We only have signed 32bits of offset.
+ if (Offset + Size > std::numeric_limits<int32_t>::max())
+ report_fatal_error("TXT section too large");
+
+ while (WrittenLength < Size) {
+ size_t ToWriteLength =
+ std::min(Size - WrittenLength, size_t(GOFF::MaxDataLength));
+
+ OS.newRecord(GOFF::RT_TXT, GOFF::TXTMetadataLength + ToWriteLength);
+ OS.writebe<uint8_t>(Flags(4, 4, RecordStyle)); // Text Record Style
+ OS.writebe<uint32_t>(EsdId); // Element ESDID
+ OS.writebe<uint32_t>(0); // Reserved
+ OS.writebe<uint32_t>(static_cast<uint32_t>(Offset)); // Offset
+ OS.writebe<uint32_t>(0); // Text Field True Length
+ OS.writebe<uint16_t>(0); // Text Encoding
+ OS.writebe<uint16_t>(ToWriteLength); // Data Length
+ OS.write(Ptr + WrittenLength, ToWriteLength); // Data
+
+ WrittenLength += ToWriteLength;
+ Offset += ToWriteLength;
+ }
+}
+} // namespace
+
+void GOFFObjectWriter::writeText(const MCSectionGOFF *MCSec, uint32_t EsdId,
+ bool IsStructured, MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ TextStream S(OS, EsdId,
+ IsStructured ? GOFF::TXT_RS_Structured : GOFF::TXT_RS_Byte);
+ Asm.writeSectionData(S, MCSec, Layout);
+}
+
void GOFFObjectWriter::writeEnd() {
uint8_t F = GOFF::END_EPR_None;
uint8_t AMODE = 0;
@@ -283,6 +1062,32 @@ uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
uint64_t StartOffset = OS.tell();
writeHeader();
+ writeSymbol(RootSD, Layout);
+
+ writeADAandCodeSectionSymbols(Asm, Layout);
+ writeSectionSymbols(Asm, Layout);
+
+ // Process all MCSymbols and generate the ESD Record(s) for them.
+ // Symbols that are aliases of other symbols need to be processed
+ // at the end, after the symbols they alias are processed.
+ for (const MCSymbol &MCSym : Asm.symbols()) {
+ if (!MCSym.isTemporary()) {
+ auto &Symbol = cast<MCSymbolGOFF>(MCSym);
+ if (Symbol.isDefined())
+ writeSymbolDefinedInModule(Symbol, Asm, Layout);
+ else
+ writeSymbolDeclaredInModule(Symbol, Asm, Layout);
+ }
+ }
+
+ for (auto GSecIter = SectionMap.begin(); GSecIter != SectionMap.end();
+ GSecIter++) {
+ auto &MCGOFFSec = cast<MCSectionGOFF>(*(GSecIter->first));
+ GOFFSection &CurrGSec = GSecIter->second;
+ bool IsStructured = MCGOFFSec.getName().equals("B_IDRL");
+ writeText(&MCGOFFSec, CurrGSec.PEsdId, IsStructured, Asm, Layout);
+ }
+
writeEnd();
LLVM_DEBUG(dbgs() << "Wrote " << OS.logicalRecords() << " logical records.");
diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp
index 58d13c9f378853..bc9a30c52c15f8 100644
--- a/llvm/lib/MC/MCGOFFStreamer.cpp
+++ b/llvm/lib/MC/MCGOFFStreamer.cpp
@@ -12,10 +12,18 @@
#include "llvm/MC/MCGOFFStreamer.h"
#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionGOFF.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolGOFF.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Casting.h"
+
+#define DEBUG_TYPE "goff-streamer"
using namespace llvm;
@@ -32,3 +40,71 @@ MCStreamer *llvm::createGOFFStreamer(MCContext &Context,
S->getAssembler().setRelaxAll(true);
return S;
}
+
+void MCGOFFStreamer::initSections(bool NoExecStack,
+ const MCSubtargetInfo &STI) {
+ MCContext &Ctx = getContext();
+ if (NoExecStack)
+ switchSection(Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx));
+ else
+ switchSection(Ctx.getObjectFileInfo()->getTextSection());
+}
+
+void MCGOFFStreamer::switchSection(MCSection *S, const MCExpr *Subsection) {
+ auto Section = cast<MCSectionGOFF>(S);
+ MCSection *Parent = Section->getParent();
+
+ if (Parent) {
+ const MCExpr *Subsection = Section->getSubsectionId();
+ assert(Subsection && "No subsection associated with child section");
+ this->MCObjectStreamer::switchSection(Parent, Subsection);
+ return;
+ }
+
+ this->MCObjectStreamer::switchSection(Section, Subsection);
+}
+
+bool MCGOFFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
+ auto *Symbol = cast<MCSymbolGOFF>(S);
+
+ getAssembler().registerSymbol(*Symbol);
+
+ switch (Attribute) {
+ case MCSA_Global:
+ Symbol->setExternal(true);
+ break;
+ case MCSA_Local:
+ Symbol->setExternal(false);
+ break;
+ case MCSA_Hidden:
+ Symbol->setHidden(true);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void MCGOFFStreamer::emitInstToData(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ LLVM_DEBUG(dbgs() << "Entering " << __PRETTY_FUNCTION__ << "\n");
+ LLVM_DEBUG(dbgs() << "Inst: " << Inst << "\n");
+
+ MCAssembler &Assembler = getAssembler();
+ SmallVector<MCFixup, 4> Fixups;
+ SmallString<256> Code;
+ Assembler.getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
+
+ // Bundling is not currently supported.
+ assert(!Assembler.isBundlingEnabled() && "Do not handle bundling yet");
+
+ MCDataFragment *DF = getOrCreateDataFragment();
+
+ // Add the fixups and data.
+ for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+ Fixups[I].setOffset(Fixups[I].getOffset() + DF->getContents().size());
+ DF->getFixups().push_back(Fixups[I]);
+ }
+ DF->setHasInstructions(STI);
+ DF->getContents().append(Code.begin(), Code.end());
+}
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 1f8f8ec5572759..b203f1a1945921 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -548,6 +548,9 @@ void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
Ctx->getGOFFSection(".text", SectionKind::getText(), nullptr, nullptr);
BSSSection =
Ctx->getGOFFSection(".bss", SectionKind::getBSS(), nullptr, nullptr);
+ ReadOnlySection =
+ Ctx->getGOFFSection(".rodata", SectionKind::getReadOnly(), TextSection,
+ MCConstantExpr::create(GOFF::SK_ReadOnly, *Ctx));
PPA1Section =
Ctx->getGOFFSection(".ppa1", SectionKind::getMetadata(), TextSection,
MCConstantExpr::create(GOFF::SK_PPA1, *Ctx));
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
index 647cf765c6a3ea..89a69d8140b8f3 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
@@ -17,6 +17,10 @@ const SystemZMCExpr *SystemZMCExpr::create(VariantKind Kind, const MCExpr *Expr,
return new (Ctx) SystemZMCExpr(Kind, Expr);
}
+const SystemZMCExpr *SystemZMCExpr::create(const MCExpr *Expr, MCContext &Ctx) {
+ return create(VK_SystemZ_None, Expr, Ctx);
+}
+
StringRef SystemZMCExpr::getVariantKindName() const {
switch (static_cast<uint32_t>(getKind())) {
case VK_SystemZ_None:
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
index 62e61091a14c64..b1372cafdd6f02 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
@@ -36,6 +36,8 @@ class SystemZMCExpr : public MCTargetExpr {
static const SystemZMCExpr *create(VariantKind Kind, const MCExpr *Expr,
MCContext &Ctx);
+ static const SystemZMCExpr *create(const MCExpr *Expr, MCContext &Ctx);
+
/// getOpcode - Get the kind of this expression.
VariantKind getKind() const { return Kind; }
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 5696ae117d69f0..46f126e061e15f 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -19,6 +19,7 @@
#include "TargetInfo/SystemZTargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/GOFF.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/IR/Mangler.h"
@@ -26,6 +27,7 @@
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbolGOFF.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/ConvertEBCDIC.h"
@@ -985,12 +987,12 @@ void SystemZAsmPrinter::emitADASection() {
const unsigned PointerSize = getDataLayout().getPointerSize();
OutStreamer->switchSection(getObjFileLowering().getADASection());
-
+ OutStreamer->emitLabel(ADASym);
unsigned EmittedBytes = 0;
for (auto &Entry : ADATable.getTable()) {
- const MCSymbol *Sym;
- unsigned SlotKind;
- std::tie(Sym, SlotKind) = Entry.first;
+ MCSymbolGOFF *Sym =
+ static_cast<MCSymbolGOFF *>(const_cast<MCSymbol *>(Entry.first.first));
+ unsigned SlotKind = Entry.first.second;
unsigned Offset = Entry.second;
assert(Offset == EmittedBytes && "Offset not as expected");
(void)EmittedBytes;
@@ -1014,6 +1016,8 @@ void SystemZAsmPrinter::emitADASection() {
MCSymbolRefExpr::create(Sym, OutContext),
OutContext),
PointerSize);
+ Sym->setExecutable(GOFF::ESD_EXE_CODE);
+ Sym->setTemporary(false);
EmittedBytes += PointerSize * 2;
break;
case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:
@@ -1023,6 +1027,7 @@ void SystemZAsmPrinter::emitADASection() {
MCSymbolRefExpr::create(Sym, OutContext),
OutContext),
PointerSize);
+ Sym->setExecutable(GOFF::ESD_EXE_DATA);
EmittedBytes += PointerSize;
break;
case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {
@@ -1420,9 +1425,89 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
4);
}
+void SystemZAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
+ if (TM.getTargetTriple().isOSzOS()) {
+ auto *Sym = cast<MCSymbolGOFF>(getSymbol(GV));
+ Sym->setExecutable(GOFF::ESD_EXE_DATA);
+ }
+
+ return AsmPrinter::emitGlobalVariable(GV);
+}
+
+void SystemZAsmPrinter::emitGlobalAlias(const Module &M,
+ const GlobalAlias &GA) {
+ if (!TM.getTargetTriple().isOSzOS()) {
+ AsmPrinter::emitGlobalAlias(M, GA);
+ return;
+ }
+
+ MCSymbol *Name = getSymbol(&GA);
+ bool IsFunc = isa<Function>(GA.getAliasee()->stripPointerCasts());
+
+ if (GA.hasExternalLinkage() || !MAI->getWeakRefDirective())
+ OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
+ else if (GA.hasWeakLinkage() || GA.hasLinkOnceLinkage())
+ OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
+ else
+ assert(GA.hasLocalLinkage() && "Invalid alias linkage");
+
+ emitVisibility(Name, GA.getVisibility());
+
+ const MCExpr *Expr;
+
+ // For XPLINK, create a VCON relocation in case of a function, and
+ // a direct reference else.
+ MCSymbol *Sym = getSymbol(GA.getAliaseeObject());
+ if (IsFunc)
+ Expr = SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,
+ MCSymbolRefExpr::create(Sym, OutContext),
+ OutContext);
+
+ else
+ Expr = MCSymbolRefExpr::create(Sym, OutContext);
+
+ OutStreamer->emitAssignment(Name, Expr);
+}
+
+const MCExpr *SystemZAsmPrinter::lowerConstant(const Constant *CV) {
+ const Triple &TargetTriple = TM.getTargetTriple();
+ if (TargetTriple.isOSzOS()) {
+ const GlobalAlias *GA = dyn_cast<GlobalAlias>(CV);
+ const Function *FV = dyn_cast<Function>(CV);
+ bool IsFunc = FV || (GA && isa<Function>(GA->getAliaseeObject()));
+ MCSymbolGOFF *Sym = nullptr;
+
+ if (auto GValue = dyn_cast<GlobalValue>(CV))
+ Sym = cast<MCSymbolGOFF>(getSymbol(GValue));
+ // TODO: Is it necessary to assert if CV is of type GlobalIFunc?
+
+ if (IsFunc) {
+ Sym->setExecutable(GOFF::ESD_EXE_CODE);
+ if (Sym->isExternal())
+ return SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,
+ MCSymbolRefExpr::create(Sym, OutContext),
+ OutContext);
+ // Trigger creation of function descriptor in ADA for internal
+ // functions.
+ unsigned Disp = ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
+ return MCBinaryExpr::createAdd(
+ SystemZMCExpr::create(MCSymbolRefExpr::create(ADASym, OutContext),
+ OutContext),
+ MCConstantExpr::create(Disp, OutContext), OutContext);
+ } else if (Sym) {
+ Sym->setExecutable(GOFF::ESD_EXE_DATA);
+ return MCSymbolRefExpr::create(Sym, OutContext);
+ }
+ }
+
+ return AsmPrinter::lowerConstant(CV);
+}
+
void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
- if (TM.getTargetTriple().isOSzOS())
+ if (TM.getTargetTriple().isOSzOS()) {
+ ADASym = OutContext.createTempSymbol("ada_sec_start");
emitPPA2(M);
+ }
AsmPrinter::emitStartOfAsmFile(M);
}
@@ -1433,6 +1518,10 @@ void SystemZAsmPrinter::emitPPA2(Module &M) {
// Make CELQSTRT symbol.
const char *StartSymbolName = "CELQSTRT";
MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName);
+ auto *GStartSym = static_cast<MCSymbolGOFF *>(CELQSTRT);
+ GStartSym->setExecutable(GOFF::ESD_EXE_CODE);
+ GStartSym->setOSLinkage();
+ GStartSym->setExternal(true);
// Create symbol and assign to class field for use in PPA1.
PPA2Sym = OutContext.createTempSymbol("PPA2", false);
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 303cce1a1b6581..5da1307571cc76 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -28,6 +28,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
MCSymbol *CurrentFnPPA1Sym; // PPA1 Symbol.
MCSymbol *CurrentFnEPMarkerSym; // Entry Point Marker.
MCSymbol *PPA2Sym;
+ MCSymbol *ADASym;
SystemZTargetStreamer *getTargetStreamer() {
MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
@@ -117,6 +118,9 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
}
void emitFunctionEntryLabel() override;
void emitFunctionBodyEnd() override;
+ void emitGlobalVariable(const GlobalVariable *GV) override;
+ void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
+ const MCExpr *lowerConstant(const Constant *CV) override;
void emitStartOfAsmFile(Module &M) override;
private:
diff --git a/llvm/test/MC/GOFF/basic-goff-64.ll b/llvm/test/MC/GOFF/basic-goff-64.ll
new file mode 100644
index 00000000000000..555c3952e984f8
--- /dev/null
+++ b/llvm/test/MC/GOFF/basic-goff-64.ll
@@ -0,0 +1,252 @@
+; RUN: llc %s -mtriple s390x-ibm-zos -filetype=obj -o - | od -v -Ax -tx1 | FileCheck --ignore-case %s
+; REQUIRES: systemz-registered-target
+
+ at x = global i32 0, align 4
+ at y = internal global i32 1, align 4
+ at z = external global i32, align 4
+
+; Function Attrs: noinline nounwind optnone
+define hidden void @foo() {
+entry:
+ store i32 8200, ptr @x, align 4
+ %0 = load i32, ptr @x, align 4
+ store i32 2, ptr @y, align 4
+ store i32 100, ptr @z, align 4
+ call void @bar(i32 noundef signext %0)
+ ret void
+}
+
+declare void @bar(i32 noundef signext)
+
+; Records for basic-goff-64#C
+; Requires a continuation record due to the name's length. ESD items
+; with names of length greater than 8 require continuation records.
+; Byte 1 of the first record for this ESD entry is 0x01 to indicate
+; that this record is continued, and byte 2 of the second record
+; to indicate that this is the final continuation record.
+; Byte 3 of first record for this ESD entry is 0x00 to indicate
+; SD (Section Definition).
+; This is the "root" SD Node.
+; CHECK: 000050 03 01 00 00 00 00 00 01 00 00 00 00 00 00 00 00
+; CHECK: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60
+; CHECK: 000090 00 01 00 00 00 00 00 0f 82 81 a2 89 83 60 87 96
+; CHECK: 0000a0 03 02 00 86 86 60 f6 f4 7b c3 00 00 00 00 00 00
+; CHECK: 0000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+
+; The next two logical records represent the ADA.
+; Record for C_WSA64.
+; Byte 3 is 0x01 to indicate ED (Element Definition).
+; This represents the writable static area.
+; CHECK: 0000f0 03 00 00 01 00 00 00 02 00 00 00 01 00 00 00 00
+; CHECK: 000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000110 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 000120 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 000130 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; Records for basic-goff-64#S
+; Requires a continuation record.
+; Byte 3 is 0x03 to indicate PR (Part Reference).
+; This represents the ADA (associated data area).
+; CHECK: 000140 03 01 00 03 00 00 00 03 00 00 00 02 00 00 00 00
+; CHECK: 000150 00 00 00 00 00 00 00 00 00 00 00 28 00 00 00 00
+; CHECK: 000160 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 000170 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 000180 10 01 24 00 00 00 00 0f 82 81 a2 89 83 60 87 96
+; CHECK: 000190 03 02 00 86 86 60 f6 f4 7b e2 00 00 00 00 00 00
+; CHECK: 0001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+
+; The next two logical records represent the code section. Source
+; code and affiliated metadata (such as the PPA1 and PPA2 sections)
+; reside here.
+; Record for C_CODE64.
+; Byte 3 is 0x01 to indicate ED (Element Definition).
+; CHECK: 0001e0 03 00 00 01 00 00 00 04 00 00 00 01 00 00 00 00
+; CHECK: 0001f0 00 00 00 00 00 00 00 00 00 00 00 ac 00 00 00 00
+; CHECK: 000200 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00
+; CHECK: 000210 00 00 00 00 00 00 00 00 00 00 00 00 04 04 00 0a
+; CHECK: 000220 00 00 03 00 00 00 00 08 c3 6d c3 d6 c4 c5 f6 f4
+
+; Records for basic-goff-64#C. Note that names for ESD entries
+; need not be unique.
+; Byte 3 is 0x02 to indicate LD (Label Definition).
+; CHECK: 000230 03 01 00 02 00 00 00 05 00 00 00 04 00 00 00 00
+; CHECK: 000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000250 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 03
+; CHECK: 000260 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK: 000270 00 01 20 00 00 00 00 0f 82 81 a2 89 83 60 87 96
+; CHECK: 000280 03 02 00 86 86 60 f6 f4 7b c3 00 00 00 00 00 00
+; CHECK: 000290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+
+; Records for the C_@@QPPA2 section, which contains the offset
+; to the PPA2.
+; CHECK: 0002d0 03 01 00 01 00 00 00 06 00 00 00 01 00 00 00 00
+; CHECK: 0002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0002f0 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 000300 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 09
+; CHECK: 000310 00 00 03 00 00 00 00 09 c3 6d 7c 7c d8 d7 d7 c1
+; CHECK: 000320 03 02 00 f2 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000370 03 00 00 03 00 00 00 07 00 00 00 06 00 00 00 00
+; CHECK: 000380 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00
+; CHECK: 000390 00 00 00 00 00 00 00 00 03 20 00 00 00 00 00 00
+; CHECK: 0003a0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 0003b0 10 01 03 00 00 00 00 06 4b 50 97 97 81 f2 00 00
+
+
+; Record for function foo().
+; Byte 3 is 0x02 to indicate LD.
+; This record is owned by ESD entry with ID 4, which is
+; C_CODE64. That is in turn owned by ESD entry with ID 1,
+; which is C_WSA64, which is owned by Section Definition
+; basic-goff-64#C. All functions in GOFF defined in the
+; compilation unit are defined in this manner.
+; Byte 63 is 0x02 = 0b00000010. Bits 5-7 indicate that
+; this record is executable, since it contains code. Note
+; that Bits 5-7 should be 001 if it is not executable and
+; 000 if executability is not specified.
+; Byte 65 is 0x03 = 0b00000011. Bits 4-7 indicate the
+; binding scope, which is library scope. This means
+; that symbol is NOT available fo dynamic binding. However,
+; it is still available for static linking. This is due to the
+; hidden attribute on the function definition.
+; Note that the symbol name is written beginning in byte
+; 72. 0x86 0x96 0x96 spell `foo` in EBCDIC encoding.
+; CHECK: 03 00 00 02 00 00 00 0a 00 00 00 04 00 00 00 00
+; CHECK: 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 03
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK: 00 03 20 00 00 00 00 03 86 96 96 00 00 00 00 00
+
+; Record for Section Definition for global variable x.
+; Note that all initialized global variables require their
+; own section definition. This includes functions defined in
+; this module. Note that bytes 4-7 indicate that ESDID is 9.
+; Byte 3 is 0x00 to indicate SD.
+; CHECK: 03 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 01 a7 00 00 00 00 00 00 00
+
+; Record for C_WSA64 belonging to Section for global variable x.
+; Byte 3 is 0x01 to indicate ED.
+; Bytes 8-11 indicate that Parent ESDID is 9.
+; CHECK: 03 00 00 01 00 00 00 0c 00 00 00 0b 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+; Record for PR of global variable x.
+; Byte 3 is 0x03 to indicate PR.
+; Bytes 8-11 indicate that Parent ESDID is A, the above
+; C_WSA64.
+; Byte 65 is 0x04 = 0b00000100. Bits 4-7 indicate the
+; binding scope, which is Import-Export scope. This means
+; that symbol is available for dynamic binding.
+; Byte 66 is 0x20 = 0b00100000. Bits 1-2 indicate the linkage.
+; In this case 0b01 indicates XPLINK.
+; CHECK: 03 00 00 03 00 00 00 0d 00 00 00 0c 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 10 04 20 00 00 00 00 01 a7 00 00 00 00 00 00 00
+
+; Global variable y works much like x, but with a few
+; differences:
+; y is explicitly listed as internal, so its binding scope is
+; set to B'0001 (Section Scope). This is true for the SD record
+; as well as the PR record.
+; CHECK: 03 00 00 00 00 00 00 0e 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 01 00 00 00 00 00 01 a8 00 00 00 00 00 00 00
+; CHECK: 03 00 00 01 00 00 00 0f 00 00 00 0e 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+; CHECK: 03 00 00 03 00 00 00 10 00 00 00 0f 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 10 01 20 00 00 00 00 01 a8 00 00 00 00 00 00 00
+
+
+; Record for C_WSA64. Child of section basic-goff-64#C
+; and contains an extern global variable. (z)
+; CHECK: 03 00 00 01 00 00 00 11 00 00 00 01 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 00 40 00 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+
+
+; Record for external global variable z. This is NOT
+; initialized in this compilation unit and so unlike
+; global variable x, it lacks its own section definition.
+; Byte 3 is 0x03 to indicate PR.
+; Bytes 8-11 indicate that parent ESDID is 0d, which is
+; above C_WSA64.
+; Byte 65 is 0x04 = 0b00000100. Bits 4-7 indicate the
+; binding scope, which is Import-Export scope. This is
+; required because it is imported (not defined in this
+; module.
+; CHECK: 03 00 00 03 00 00 00 12 00 00 00 11 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 10 04 20 00 00 00 00 01 a9 00 00 00 00 00 00 00
+
+
+; Record for externally defined function bar().
+; Byte 3 is 0x04 to indicate External Reference (ErWx).
+; Bytes 8-11 indicate that parent ESDID is 01, the section
+; definition for this module. (basic-goff-64#C).
+; Byte 65 indicates that the binding scope is Import-Export
+; Scope, since the definition may be something we dynamically
+; link against.
+; CHECK: 03 00 00 04 00 00 00 13 00 00 00 01 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
+; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK: 00 04 20 00 00 00 00 03 82 81 99 00 00 00 00 00
+
+
+; TXT Records:
+
+; TXT Record corresponding to global variable y.
+; Bytes 4-7 indicate that the owning ESD has ID 0x10. This is the
+; PR for global variable x.
+; Byte 22-23 contain the data length, which is 4, as expected for
+; an i32 type.
+; CHECK-DAG: 03 10 00 00 00 00 00 10 00 00 00 00 00 00 00 00
+
+; TXT Record corresponding to global variable x.
+; CHECK-DAG: 03 10 00 00 00 00 00 0d 00 00 00 00 00 00 00 00
+
+; TXT Record corresponding to the C_CODE64 Section.
+; This contains the bodies of the function(s) that make up
+; a module.
+; CHECK-DAG: 03 11 00 00 00 00 00 04 00 00 00 00 00 00 00 00
+
+; TXT Record containing ADA.
+; CHECK-DAG: 03 10 00 00 00 00 00 03 00 00 00 00 00 00 00 00
diff --git a/llvm/test/MC/GOFF/empty-goff.s b/llvm/test/MC/GOFF/empty-goff.s
index f6d402863d71c8..48f50581335483 100644
--- a/llvm/test/MC/GOFF/empty-goff.s
+++ b/llvm/test/MC/GOFF/empty-goff.s
@@ -2,23 +2,24 @@
* RUN: od -Ax -tx1 -v | FileCheck --ignore-case %s
* REQUIRES: systemz-registered-target
-* Header record:
-* 03 is prefix byte
-* f. is header type
-* .0 is version
-* The 1 at offset 51 is the architecture level.
-* CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* Header record:
+* 03 is prefix byte
+* f. is header type
+* .0 is version
+* The 1 at offset 51 is the architecture level.
+* CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+** End record:
+** 03 is prefix byte
+** 4. is header type
+** .0 is version
+* CHECK: 0001e0 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 0001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* End record:
-* 03 is prefix byte
-* 4. is header type
-* .0 is version
-* CHECK: 000050 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-* CHECK: 000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
More information about the llvm-commits
mailing list