[llvm] [SystemZ][z/OS] Implement executePostLayoutBinding for GOFFObjectWriter (PR #67868)
Neumann Hon via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 27 11:34:29 PDT 2023
https://github.com/Everybody0523 updated https://github.com/llvm/llvm-project/pull/67868
>From dbdec03bcd35d4b9176bd38ecb557c98dd24e43c Mon Sep 17 00:00:00 2001
From: Neumann Hon <neumann.hon at ibm.com>
Date: Fri, 29 Sep 2023 19:52:27 -0400
Subject: [PATCH] [SystemZ][z/OS] Implement executePostLayoutBinding for
GOFFObjectWriter
Implement executePostLayoutBinding() for the GOFFObjectWriter. With this
patch, we can now emit the ESD/TXT Records that are required by
global variables and functions.
---
llvm/include/llvm/BinaryFormat/GOFF.h | 15 +-
llvm/include/llvm/MC/MCAssembler.h | 7 +
llvm/include/llvm/MC/MCContext.h | 3 +-
llvm/include/llvm/MC/MCGOFFStreamer.h | 10 +-
llvm/include/llvm/MC/MCSymbolGOFF.h | 38 +
.../CodeGen/TargetLoweringObjectFileImpl.cpp | 7 +-
llvm/lib/MC/GOFFObjectWriter.cpp | 710 +++++++++++++++++-
llvm/lib/MC/MCGOFFStreamer.cpp | 50 ++
llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 32 +
llvm/lib/Target/SystemZ/SystemZAsmPrinter.h | 2 +
llvm/test/MC/GOFF/basic-goff-64.ll | 243 ++++++
llvm/test/MC/GOFF/empty-goff.s | 18 +-
12 files changed, 1113 insertions(+), 22 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 f1a30e41b736bda..00b6ac011c39879 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,
diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h
index 5e1fc738b1dab4b..2b7b62e29722146 100644
--- a/llvm/include/llvm/MC/MCAssembler.h
+++ b/llvm/include/llvm/MC/MCAssembler.h
@@ -134,6 +134,9 @@ class MCAssembler {
/// List of declared file names
std::vector<std::pair<std::string, size_t>> FileNames;
+ /// GOFF Csect names.
+ std::pair<std::string, std::string> CsectNames;
+
MCDwarfLineTableParams LTParams;
/// The set of function symbols for which a .thumb_func directive has
@@ -483,6 +486,10 @@ class MCAssembler {
FileNames.emplace_back(std::string(FileName), Symbols.size());
}
+ std::pair<std::string, std::string> const &getCsectNames() {
+ return CsectNames;
+ }
+
/// Write the necessary bundle padding to \p OS.
/// Expects a fragment \p F containing instructions and its size \p FSize.
void writeFragmentPadding(raw_ostream &OS, const MCEncodedFragment &F,
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 68d6f3e59d2d41a..dd5709d3be14c7f 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -621,7 +621,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 2345509b161da5b..235edc01e88d5a5 100644
--- a/llvm/include/llvm/MC/MCGOFFStreamer.h
+++ b/llvm/include/llvm/MC/MCGOFFStreamer.h
@@ -24,9 +24,13 @@ 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 {}
diff --git a/llvm/include/llvm/MC/MCSymbolGOFF.h b/llvm/include/llvm/MC/MCSymbolGOFF.h
index cc4e2bbe246e2de..6df12cd0f07d50f 100644
--- a/llvm/include/llvm/MC/MCSymbolGOFF.h
+++ b/llvm/include/llvm/MC/MCSymbolGOFF.h
@@ -18,10 +18,48 @@
namespace llvm {
class MCSymbolGOFF : public MCSymbol {
+ Align Alignment;
+ 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.
+ };
+
+ // 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) {}
static bool classof(const MCSymbol *S) { return S->isGOFF(); }
+
+ 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 f3ba380818901ca..cf6cee07c286247 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2686,9 +2686,12 @@ MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal(
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 addeb6db9596931..46acacdc380f456 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,121 @@ 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;
+ 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) {}
+
+ 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");
+ }
+
+ void setMaxAlignment(Align A) {
+ GOFF::ESDAlignment CurrAlign = Alignment;
+ setAlignment(A);
+ if (CurrAlign > Alignment)
+ Alignment = CurrAlign;
+ }
+};
+
+/// \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.
+class GOFFSection {
+public:
+ GOFFSymbol *Pptr = nullptr;
+ GOFFSymbol *Rptr = nullptr;
+ GOFFSymbol *SD = nullptr;
+ const MCSectionGOFF *MCSec = nullptr;
+ bool IsStructured = false;
+
+ GOFFSection(GOFFSymbol *Pptr, GOFFSymbol *Rptr, GOFFSymbol *SD,
+ const MCSectionGOFF *MCSec)
+ : Pptr(Pptr), Rptr(Rptr), SD(SD), MCSec(MCSec), IsStructured(false) {}
+};
+
class GOFFObjectWriter : public MCObjectWriter {
+ typedef std::vector<std::unique_ptr<GOFFSymbol>> SymbolListType;
+ typedef DenseMap<MCSymbol const *, GOFFSymbol *> SymbolMapType;
+ typedef std::vector<std::unique_ptr<GOFFSection>> SectionListType;
+ typedef DenseMap<MCSection const *, GOFFSection *> SectionMapType;
+
// The target specific GOFF writer instance.
std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
+ /// The symbol table for a GOFF file. It is order sensitive.
+ SymbolListType EsdSymbols;
+
+ /// Lookup table for MCSymbols to GOFFSymbols. Needed to determine EsdIds
+ /// of symbols in Relocations.
+ SymbolMapType SymbolMap;
+
+ /// The list of sections for the GOFF file.
+ SectionListType Sections;
+
+ /// 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;
+
+ GOFFSymbol *RootSD = nullptr;
+ GOFFSymbol *CodeLD = nullptr;
+ GOFFSymbol *ADA = nullptr;
+ bool HasADA = false;
+
public:
GOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
raw_pwrite_stream &OS)
@@ -231,20 +344,349 @@ class GOFFObjectWriter : public MCObjectWriter {
~GOFFObjectWriter() override {}
+private:
// Write GOFF records.
void writeHeader();
+
+ void writeSymbol(const GOFFSymbol &Symbol, const MCAsmLayout &Layout);
+ void writeText(const GOFFSection &Section, const 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);
+ void defineRootAndADASD(MCAssembler &Asm);
+ void defineSectionSymbols(const MCAssembler &Asm,
+ const MCSectionGOFF &Section,
+ const MCAsmLayout &Layout);
+ void processSymbolDefinedInModule(const MCSymbolGOFF &MCSymbol,
+ const MCAssembler &Asm,
+ const MCAsmLayout &Layout);
+ void processSymbolDeclaredInModule(const MCSymbolGOFF &Symbol);
};
} // end anonymous namespace
+GOFFSection *GOFFObjectWriter::createGOFFSection(GOFFSymbol *Pptr,
+ GOFFSymbol *Rptr,
+ GOFFSymbol *SD,
+ const MCSectionGOFF *MC) {
+ Sections.push_back(std::make_unique<GOFFSection>(Pptr, Rptr, SD, MC));
+
+ return Sections.back().get();
+}
+
+GOFFSymbol *GOFFObjectWriter::createGOFFSymbol(StringRef Name,
+ GOFF::ESDSymbolType Type,
+ uint32_t ParentEsdId) {
+ EsdSymbols.push_back(
+ std::make_unique<GOFFSymbol>(Name, Type, EsdCounter, ParentEsdId));
+ ++EsdCounter;
+ return EsdSymbols.back().get();
+}
+
+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 = 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) {
+ 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;
+
+ return WSA;
+}
+
+void GOFFObjectWriter::defineRootAndADASD(MCAssembler &Asm) {
+ assert(!RootSD && !ADA && "SD already initialzed");
+ StringRef FileName = "";
+ if (Asm.getFileNames().size())
+ 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;
+
+ GOFFSymbol *ADAED = createWSASymbol(RootSD->EsdId);
+ 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;
+ // The ADA Section length can increase after this point. The final ADA
+ // length is assigned in populateADASection().
+ // We need to be careful, because a value of 0 causes issues with function
+ // labels. In populateADASection(), we make sure that the ADA content is
+ // defined before createing function labels.
+ ADA->SectionLength = 0;
+ // Assume there is an ADA.
+ HasADA = true;
+}
+
+void GOFFObjectWriter::defineSectionSymbols(const MCAssembler &Asm,
+ const MCSectionGOFF &Section,
+ const MCAsmLayout &Layout) {
+ GOFFSection *GSection = nullptr;
+ SectionKind Kind = Section.getKind();
+
+ if (Kind.isText()) {
+ GOFFSymbol *SD = RootSD;
+ const char *CodeClassName = "C_CODE64";
+ GOFFSymbol *ED = createEDSymbol(CodeClassName, SD->EsdId);
+ GOFFSymbol *LD = createLDSymbol(SD->Name, ED->EsdId);
+
+ ED->SectionLength = Layout.getSectionAddressSize(&Section);
+ ED->Executable = GOFF::ESD_EXE_CODE;
+ ED->ForceRent = true;
+
+ LD->Executable = GOFF::ESD_EXE_CODE;
+ if (SD->BindingScope == GOFF::ESD_BSC_Section) {
+ LD->BindingScope = GOFF::ESD_BSC_Section;
+ } else {
+ LD->BindingScope = GOFF::ESD_BSC_Library;
+ }
+
+ CodeLD = LD;
+
+ GSection = createGOFFSection(ED, LD, SD, &Section);
+ } else if (Section.getName().equals(".ada")) {
+ // Symbols already defined in defineRootAndADASD, nothing to do.
+ ADA->SectionLength = Layout.getSectionAddressSize(&Section);
+ if (ADA->SectionLength)
+ CodeLD->ADAEsdId = ADA->EsdId;
+ else {
+ // We cannot have a zero-length section for data. If we do, artificially
+ // inflate it. Use 2 bytes to avoid odd alignments.
+ ADA->SectionLength = 2;
+ HasADA = false;
+ }
+ GSection = createGOFFSection(ADA, ADA, RootSD, &Section);
+ } else if (Kind.isBSS() || Kind.isData()) {
+ // Statics and globals that are defined.
+ StringRef SectionName = Section.getName();
+ GOFFSymbol *SD = createSDSymbol(SectionName);
+
+ // Determine if static/global variable is marked with the norent attribute.
+ MCContext &Ctx = Asm.getContext();
+ auto *Sym = cast_or_null<MCSymbolGOFF>(Ctx.lookupSymbol(SectionName));
+
+ if (Sym) {
+ 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;
+
+ GSection = createGOFFSection(PR, PR, SD, &Section);
+ }
+ } else
+ llvm_unreachable("Unhandled section kind");
+
+ SectionMap[&Section] = GSection;
+}
+
+void GOFFObjectWriter::processSymbolDefinedInModule(
+ const MCSymbolGOFF &MCSymbol, const MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ MCSection &Section = MCSymbol.getSection();
+ SectionKind Kind = Section.getKind();
+ auto &Sec = cast<MCSectionGOFF>(Section);
+
+ GOFFSection *GSection = SectionMap[&Sec];
+ assert(GSection && "No corresponding section found");
+
+ GOFFSymbol *GSectionSym = GSection->Pptr;
+ assert(GSectionSym &&
+ "Defined symbols must exist in an initialized GSection");
+
+ StringRef SymbolName = MCSymbol.getName();
+ // If it's a text section, then create a label for it.
+ if (Kind.isText()) {
+ GOFFSymbol *LD = createLDSymbol(SymbolName, GSectionSym->EsdId);
+ LD->BindingStrength = MCSymbol.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 = MCSymbol.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 = MCSymbol.isExternal()
+ ? (MCSymbol.isExported()
+ ? GOFF::ESD_BSC_ImportExport
+ : (LD->isExecutable() ? GOFF::ESD_BSC_Library
+ : GOFF::ESD_BSC_Module))
+ : GOFF::ESD_BSC_Section;
+
+ if (ADA && ADA->SectionLength > 0)
+ LD->ADAEsdId = ADA->EsdId;
+ else
+ LD->ADAEsdId = 0;
+
+ GSectionSym->setMaxAlignment(MCSymbol.getAlignment());
+
+ LD->MCSym = &MCSymbol;
+ SymbolMap[&MCSymbol] = LD;
+ } else if (Kind.isBSS() || Kind.isData()) {
+ GSectionSym = GSection->Rptr;
+ GSectionSym->BindingScope =
+ MCSymbol.isExternal()
+ ? (MCSymbol.isExported() ? GOFF::ESD_BSC_ImportExport
+ : GOFF::ESD_BSC_Library)
+ : GOFF::ESD_BSC_Section;
+ if (GSectionSym->BindingScope == GOFF::ESD_BSC_Section)
+ GSection->SD->BindingScope = GOFF::ESD_BSC_Section;
+ GSectionSym->setAlignment(MCSymbol.getAlignment());
+ GSectionSym->SectionLength = Layout.getSectionAddressSize(&Section);
+
+ // We cannot have a zero-length section for data. If we do, artificially
+ // inflate it. Use 2 bytes to avoid odd alignments.
+ if (!GSectionSym->SectionLength)
+ GSectionSym->SectionLength = 2;
+
+ GSectionSym->MCSym = &MCSymbol;
+ GSection->SD->MCSym = &MCSymbol;
+ SymbolMap[&MCSymbol] = GSectionSym;
+ } else
+ llvm_unreachable("Unhandled section kind for Symbol");
+}
+
+void GOFFObjectWriter::processSymbolDeclaredInModule(
+ const MCSymbolGOFF &Symbol) {
+ GOFFSymbol *SD = RootSD;
+
+ switch (Symbol.getExecutable()) {
+ case GOFF::ESD_EXE_CODE:
+ case GOFF::ESD_EXE_Unspecified: {
+ GOFFSymbol *ER = createERSymbol(Symbol.getName(), SD->EsdId, &Symbol);
+ ER->BindingScope = GOFF::ESD_BSC_ImportExport;
+ ER->MCSym = &Symbol;
+ SymbolMap[&Symbol] = ER;
+ break;
+ }
+ case GOFF::ESD_EXE_DATA: {
+ GOFFSymbol *ED = createWSASymbol(SD->EsdId);
+ ED->setAlignment(Symbol.getAlignment());
+ 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;
+ PR->MCSym = &Symbol;
+ SymbolMap[&Symbol] = PR;
+ break;
+ }
+ }
+}
+
+void GOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ LLVM_DEBUG(dbgs() << "Entering " << __FUNCTION__ << "\n");
+
+ // Define the GOFF root and ADA symbol.
+ defineRootAndADASD(Asm);
+
+ for (MCSection &S : Asm) {
+ auto &Section = cast<MCSectionGOFF>(S);
+ LLVM_DEBUG(dbgs() << "Current Section (" << Section.getName() << "): ";
+ Section.dump(); dbgs() << "\n");
+ defineSectionSymbols(Asm, Section, Layout);
+ }
+
+ for (const MCSymbol &Sym : Asm.symbols()) {
+ if (Sym.isTemporary() && !Sym.isUsedInReloc())
+ continue;
+
+ auto &Symbol = cast<MCSymbolGOFF>(Sym);
+ if (Symbol.isDefined())
+ processSymbolDefinedInModule(Symbol, Asm, Layout);
+ else
+ processSymbolDeclaredInModule(Symbol);
+ }
+}
+
void GOFFObjectWriter::writeHeader() {
OS.newRecord(GOFF::RT_HDR, /*Size=*/57);
OS.write_zeros(1); // Reserved
@@ -259,6 +701,268 @@ 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
+}
+
+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 GOFFSection &Section,
+ const MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ // TODO: This assumes the ED. Is that correct? Probably not.
+ TextStream S(OS, Section.Pptr->EsdId,
+ Section.IsStructured ? GOFF::TXT_RS_Structured
+ : GOFF::TXT_RS_Byte);
+ Asm.writeSectionData(S, Section.MCSec, Layout);
+}
+
void GOFFObjectWriter::writeEnd() {
uint8_t F = GOFF::END_EPR_None;
uint8_t AMODE = 0;
@@ -283,6 +987,10 @@ uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
uint64_t StartOffset = OS.tell();
writeHeader();
+ for (const auto &Sym : EsdSymbols)
+ writeSymbol(*Sym, Layout);
+ for (const auto &Sec : Sections)
+ writeText(*Sec, 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 58d13c9f3788534..ea7b819b918d2ea 100644
--- a/llvm/lib/MC/MCGOFFStreamer.cpp
+++ b/llvm/lib/MC/MCGOFFStreamer.cpp
@@ -12,10 +12,16 @@
#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"
using namespace llvm;
@@ -32,3 +38,47 @@ MCStreamer *llvm::createGOFFStreamer(MCContext &Context,
S->getAssembler().setRelaxAll(true);
return S;
}
+
+void MCGOFFStreamer::initSections(bool NoExecStack,
+ const MCSubtargetInfo &STI) {
+ MCContext &Ctx = getContext();
+ switchSection(Ctx.getObjectFileInfo()->getTextSection());
+
+ if (NoExecStack)
+ switchSection(Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx));
+}
+
+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;
+}
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index b3075c150ebb36f..f00f2e18d151a41 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/ConvertEBCDIC.h"
@@ -1296,6 +1298,36 @@ 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);
+}
+
+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) {
+ Sym->setExecutable(GOFF::ESD_EXE_DATA);
+ return MCSymbolRefExpr::create(Sym, OutContext);
+ }
+ }
+
+ return AsmPrinter::lowerConstant(CV);
+}
+
void SystemZAsmPrinter::emitFunctionEntryLabel() {
const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index c9dbbfd0b4c4335..4e329d799e36ce5 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -113,6 +113,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
}
void emitFunctionEntryLabel() override;
void emitFunctionBodyEnd() override;
+ void emitGlobalVariable(const GlobalVariable *GV) override;
+ const MCExpr *lowerConstant(const Constant *CV) override;
private:
void emitCallInformation(CallType CT);
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 000000000000000..bf501a9e424073c
--- /dev/null
+++ b/llvm/test/MC/GOFF/basic-goff-64.ll
@@ -0,0 +1,243 @@
+; 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)
+
+; HDR Record
+; 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
+
+; 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).
+; 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
+
+
+; 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
+
+; Record for C_CODE64.
+; Byte 3 is 0x01 to indicate SD (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 2a 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
+
+; 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 6.
+; Byte 3 is 0x00 to indicate SD.
+; CHECK: 0002d0 03 00 00 00 00 00 00 06 00 00 00 00 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 00 00 00 00 00 00 00 00
+; CHECK: 000300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000310 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 6.
+; CHECK: 000320 03 00 00 01 00 00 00 07 00 00 00 06 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 03 80 00 00 00 00 00 00
+; CHECK: 000350 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 000360 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 7, 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: 000370 03 00 00 03 00 00 00 08 00 00 00 07 00 00 00 00
+; CHECK: 000380 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00
+; CHECK: 000390 00 00 00 00 00 00 00 00 03 00 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 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: 0003c0 03 00 00 00 00 00 00 09 00 00 00 00 00 00 00 00
+; CHECK: 0003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0003e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0003f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000400 00 01 00 00 00 00 00 01 a8 00 00 00 00 00 00 00
+; CHECK: 000410 03 00 00 01 00 00 00 0a 00 00 00 09 00 00 00 00
+; CHECK: 000420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000430 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 000440 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 000450 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00
+; CHECK: 000460 03 00 00 03 00 00 00 0b 00 00 00 0a 00 00 00 00
+; CHECK: 000470 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00
+; CHECK: 000480 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 000490 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 0004a0 10 01 20 00 00 00 00 01 a8 00 00 00 00 00 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.
+; CHECK: 0004b0 03 00 00 02 00 00 00 0c 00 00 00 04 00 00 00 00
+; CHECK: 0004c0 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0004d0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 03
+; CHECK: 0004e0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
+; CHECK: 0004f0 00 03 20 00 00 00 00 03 86 96 96 00 00 00 00 00
+
+; Record for C_WSA64. Child of section basic-goff-64#C
+; and contains externally defined global variables.
+; CHECK: 000500 03 00 00 01 00 00 00 0d 00 00 00 01 00 00 00 00
+; CHECK: 000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000520 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00
+; CHECK: 000530 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01
+; CHECK: 000540 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: 000550 03 00 00 03 00 00 00 0e 00 00 00 0d 00 00 00 00
+; CHECK: 000560 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000570 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00
+; CHECK: 000580 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 000590 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: 0005a0 03 00 00 04 00 00 00 0f 00 00 00 01 00 00 00 00
+; CHECK: 0005b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 0005c0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
+; CHECK: 0005d0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01
+; CHECK: 0005e0 00 04 20 00 00 00 00 03 82 81 99 00 00 00 00 00
+
+; TXT Records
+; One TXT Record corresponding to the C_CODE64 Section.
+; This contains the bodies of the function(s) that make up
+; a module. Bytes 0-23 contain metadata, bytes 24 and onwards
+; contain data so we don't check those.
+; Byte 1 is 0x10 = 0b00010000. Byte 2, bits 0-3 indicate the
+; record type. 0b0001 indicates a TXT Record.
+; Bytes 4-7 indicate that the owning ESD has ID 4. This is
+; C_CODE64. Note that the parent ESD record must be an ED or
+; PR Record.
+; Bytes 22-23 contain the data length.
+; CHECK: 0005f0 03 10 00 00 00 00 00 04 00 00 00 00 00 00 00 00
+; CHECK: 000600 00 00 00 00 00 00 00 2a
+
+; TXT Record corresponding to global variable x. This belongs
+; to the PR of x.
+; Bytes 4-7 indicate that the owning ESD has ID 8. This is the
+; PR for global variable x.
+; Byte 22-23 contain the data length, which is 4, as expected for
+; an integer.
+; CHECK: 000640 03 10 00 00 00 00 00 08 00 00 00 00 00 00 00 00
+; CHECK: 000650 00 00 00 00 00 00 00 04
+
+; TXT Record corresponding to global variable y. This is essentially
+; the same as the above TXT Record except for the different
+; owning PR.
+; CHECK: 000690 03 10 00 00 00 00 00 0b 00 00 00 00 00 00 00 00
+; CHECK: 0006a0 00 00 00 00 00 00 00 04
+
+; TXT Record corresponding to the ADA Record.
+; CHECK: 0006e0 03 10 00 00 00 00 00 03 00 00 00 00 00 00 00 00
+; CHECK: 0006f0 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00 00
+; CHECK: 000700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000710 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK: 000720 00 00 00 00 00 00 00 00 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 f6d402863d71c80..a9819a83de29536 100644
--- a/llvm/test/MC/GOFF/empty-goff.s
+++ b/llvm/test/MC/GOFF/empty-goff.s
@@ -13,12 +13,12 @@
* 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: 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
+** 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
More information about the llvm-commits
mailing list