Skip to content

[z/OS][GOFF] Implement support for writing ESD + TXT records by the GOFFObjectWriter #85851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
36 changes: 30 additions & 6 deletions llvm/include/llvm/BinaryFormat/GOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -166,9 +169,30 @@ 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,
};

// \brief Type of sections (properly - classes or modules) in the object file.
enum GOFFSectionType : uint8_t {
/// Code - This section belongs to the the Code CSECT.
Code,

/// Static - This section belongs to the Static CSECT.
Static,

/// PPA2Offset - This section contains the offset to the PPA2.
/// Note: This is NOT the PPA2 section itself, which should
/// reside within the Code CSECT.
PPA2Offset,

/// B_IDRL -
B_IDRL,

/// Other - All other sections.
Other,
};
} // end namespace GOFF

} // end namespace llvm
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/CodeGen/AsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -912,4 +912,4 @@ class AsmPrinter : public MachineFunctionPass {

} // end namespace llvm

#endif // LLVM_CODEGEN_ASMPRINTER_H
#endif // LLVM_CODEGEN_ASMPRINTER_H
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile {
const TargetMachine &TM) const override;
MCSection *getSectionForLSDA(const Function &F, const MCSymbol &FnSym,
const TargetMachine &TM) const override;
MCSymbol *getTargetSymbol(const GlobalValue *GV,
const TargetMachine &TM) const override;
};

} // end namespace llvm
Expand Down
41 changes: 39 additions & 2 deletions llvm/include/llvm/MC/MCContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/BinaryFormat/GOFF.h"
#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/MC/MCAsmMacro.h"
#include "llvm/MC/MCDwarf.h"
Expand Down Expand Up @@ -61,6 +62,7 @@ class MCStreamer;
class MCSubtargetInfo;
class MCSymbol;
class MCSymbolELF;
class MCSymbolGOFF;
class MCSymbolWasm;
class MCSymbolXCOFF;
class MCTargetOptions;
Expand Down Expand Up @@ -299,6 +301,25 @@ class MCContext {
}
};

struct GOFFSectionKey {
std::string SectionName;
GOFF::GOFFSectionType SectionType;
bool HasParentSection;

GOFFSectionKey(StringRef SectionName, GOFF::GOFFSectionType SectionType,
bool HasParentSection)
: SectionName(SectionName), SectionType(SectionType),
HasParentSection(HasParentSection) {}

bool operator<(const GOFFSectionKey &Other) const {
if (SectionType == GOFF::GOFFSectionType::Other
&& SectionType == GOFF::GOFFSectionType::Other) {
return SectionName < Other.SectionName;
}
return SectionType < Other.SectionType;
}
};

struct WasmSectionKey {
std::string SectionName;
StringRef GroupName;
Expand Down Expand Up @@ -352,7 +373,7 @@ class MCContext {
StringMap<MCSectionMachO *> MachOUniquingMap;
std::map<ELFSectionKey, MCSectionELF *> ELFUniquingMap;
std::map<COFFSectionKey, MCSectionCOFF *> COFFUniquingMap;
std::map<std::string, MCSectionGOFF *> GOFFUniquingMap;
std::map<GOFFSectionKey, MCSectionGOFF *> GOFFUniquingMap;
std::map<WasmSectionKey, MCSectionWasm *> WasmUniquingMap;
std::map<XCOFFSectionKey, MCSectionXCOFF *> XCOFFUniquingMap;
StringMap<MCSectionDXContainer *> DXCUniquingMap;
Expand Down Expand Up @@ -634,7 +655,23 @@ class MCContext {
unsigned EntrySize);

MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
MCSection *Parent, const MCExpr *SubsectionId);
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,
bool isRooted = false,
const MCSymbolGOFF *TextOwner = nullptr);

MCSectionGOFF *
getGOFFSection(StringRef Section, SectionKind Kind,
MCSection *Parent = nullptr,
const MCExpr *SubsectionId = nullptr,
GOFF::GOFFSectionType SectionType = GOFF::Other,
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,
bool isRooted = false, const MCSymbolGOFF * TextOwner = nullptr);

MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
SectionKind Kind, StringRef COMDATSymName,
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCDirectives.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ enum MCSymbolAttr {
MCSA_WeakDefAutoPrivate, ///< .weak_def_can_be_hidden (MachO)
MCSA_WeakAntiDep, ///< .weak_anti_dep (COFF)
MCSA_Memtag, ///< .memtag (ELF)

MCSA_ZOS_OS_Linkage,
};

enum MCAssemblerFlag {
Expand Down
11 changes: 7 additions & 4 deletions llvm/include/llvm/MC/MCGOFFStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down
117 changes: 116 additions & 1 deletion llvm/include/llvm/MC/MCSectionGOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,81 @@
/// This file declares the MCSectionGOFF class, which contains all of the
/// necessary machine code sections for the GOFF file format.
///
/// GOFF doesn't truly have sections in the way object file formats on Unix
/// such as ELF does, so MCSectionGOFF (more or less) represents a Class in
/// GOFF. A GOFF Class is defined by a tuple of ESD symbols; specifically a SD
/// symbol, an ED symbol, and PR or LD symbols. One of these symbols (PR or ED)
/// must be the owner of a TXT record, which contains the actual contents of
/// this Class.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_MC_MCSECTIONGOFF_H
#define LLVM_MC_MCSECTIONGOFF_H

#include "llvm/BinaryFormat/GOFF.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbolGOFF.h"
#include "llvm/Support/raw_ostream.h"

namespace llvm {

class MCExpr;

class MCSectionGOFF final : public MCSection {
private:
MCSection *Parent;
const MCExpr *SubsectionId;
GOFF::GOFFSectionType Type = GOFF::Other;
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;

/// IsRooted - True iff the SD symbol used to define the GOFF Class this
/// MCSectionGOFF represents is the "root" SD symbol.
bool IsRooted = false;

/// TextOwnedByED - True if the ED Symbol in the GOFF Class this MCSectionGOFF
/// represents is the owner of TXT record. False if the TXT record is owned by
/// a LD or PR Symbol.
bool TextOwnedByED = false;

/// TextOwner - Valid if owned the text record containing the body of this section
/// is not owned by an ED Symbol. The MCSymbol that represents the part or label that
/// actually owns the TXT Record.
const MCSymbolGOFF *TextOwner = nullptr;

friend class MCContext;
MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub)
: MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub) {}

MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
GOFF::ESDTextStyle TextStyle, GOFF::ESDBindingAlgorithm BindAlgorithm,
GOFF::ESDLoadingBehavior LoadBehavior, GOFF::ESDBindingScope BindingScope, bool IsRooted, const MCSymbolGOFF *TextOwner)
: MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub),
TextStyle(TextStyle), BindAlgorithm(BindAlgorithm), LoadBehavior(LoadBehavior), BindingScope(BindingScope), IsRooted(IsRooted), TextOwner(TextOwner) {}

MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub,
GOFF::GOFFSectionType Type)
: MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub),
Type(Type) {
if (Type == GOFF::GOFFSectionType::Code) {
IsRooted = true;
TextOwnedByED = true;
} else if (Type == GOFF::GOFFSectionType::Static) {
IsRooted = true;
TextOwnedByED = false;
} else if (Type == GOFF::GOFFSectionType::PPA2Offset) {
IsRooted = true;
TextOwnedByED = false;
TextStyle = GOFF::ESD_TS_ByteOriented;
} else if (Type == GOFF::GOFFSectionType::B_IDRL) {
IsRooted = true;
TextOwnedByED = true;
TextStyle = GOFF::ESD_TS_Structured;
LoadBehavior = GOFF::ESD_LB_NoLoad;
}
}

public:
void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
Expand All @@ -43,10 +97,71 @@ class MCSectionGOFF final : public MCSection {

bool isVirtualSection() const override { return false; }

bool isCode() const { return Type == GOFF::Code; }
bool isStatic() const { return Type == GOFF::Static; }
bool isPPA2Offset() const { return Type == GOFF::PPA2Offset; }
bool isB_IDRL() const { return Type == GOFF::B_IDRL; }

GOFF::ESDTextStyle getTextStyle() const { return TextStyle; }
GOFF::ESDBindingAlgorithm getBindingAlgorithm() const { return BindAlgorithm; }
GOFF::ESDLoadingBehavior getLoadBehavior() const { return LoadBehavior; }
GOFF::ESDBindingScope getBindingScope() const { return BindingScope; }
bool getRooted() const { return IsRooted; }
bool isTextOwnedByED() const { return TextOwnedByED; }

MCSection *getParent() const { return Parent; }
const MCExpr *getSubsectionId() const { return SubsectionId; }

static bool classof(const MCSection *S) { return S->getVariant() == SV_GOFF; }

// Return the name of the External Definition (ED) used to represent this
// MCSectionGOFF in the object file.
std::string getExternalDefinitionName() const {
switch (Type)
{
case GOFF::GOFFSectionType::Code:
return "C_CODE64";
case GOFF::GOFFSectionType::Static:
return "C_WSA64";
case GOFF::GOFFSectionType::PPA2Offset:
return "C_@@QPPA2";
case GOFF::GOFFSectionType::B_IDRL:
return "B_IDRL";
case GOFF::GOFFSectionType::Other:
return "C_WSA64";
}
return "";
}

std::optional<const MCSymbolGOFF *> getTextOwner() const {
if (TextOwnedByED)
return std::nullopt;
else if (TextOwner)
return TextOwner;
return std::nullopt;
}

std::string getTextOwnerName() const {
if (TextOwnedByED)
return getExternalDefinitionName();
else if (Type == GOFF::Static)
return "";
else if (Type == GOFF::PPA2Offset)
return ".&ppa2";
else if (Type == GOFF::Other) {
if (TextOwner)
return TextOwner->getName().str();
}
return getName().str();
}

bool isReadOnly() const {
return isCode() || isPPA2Offset() || isB_IDRL();
}

GOFF::ESDNameSpaceId getNameSpace() const {
return isB_IDRL() ? GOFF::ESD_NS_NormalName : GOFF::ESD_NS_Parts;
}
};
} // end namespace llvm

Expand Down
40 changes: 40 additions & 0 deletions llvm/include/llvm/MC/MCSymbolGOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,50 @@
namespace llvm {

class MCSymbolGOFF : public MCSymbol {
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) {}
static bool classof(const MCSymbol *S) { return S->isGOFF(); }

void setOSLinkage(bool Value = true) const {
modifyFlags(Value ? SF_OSLinkage : 0, SF_OSLinkage);
}
bool isOSLinkage() const { return getFlags() & SF_OSLinkage; }

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

Expand Down
Loading
Loading