diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h index 443bcfc9479a8..49d2809cb6524 100644 --- a/llvm/include/llvm/BinaryFormat/GOFF.h +++ b/llvm/include/llvm/BinaryFormat/GOFF.h @@ -169,6 +169,91 @@ enum SubsectionKind : uint8_t { SK_PPA1 = 2, SK_PPA2 = 4, }; + +// The standard System/390 convention is to name the high-order (leftmost) bit +// in a byte as bit zero. The Flags type helps to set bits in byte according +// to this numeration order. +class Flags { + uint8_t Val = 0; + + constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value, + uint8_t OldValue) { + uint8_t Pos = 8 - BitIndex - Length; + uint8_t Mask = ((1 << Length) - 1) << Pos; + Value = Value << Pos; + return (OldValue & ~Mask) | Value; + } + +public: + constexpr Flags() = default; + constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value) + : Val(bits(BitIndex, Length, Value, 0)) {} + + template + constexpr void set(uint8_t BitIndex, uint8_t Length, T NewValue) { + Val = bits(BitIndex, Length, static_cast(NewValue), Val); + } + + template + constexpr T get(uint8_t BitIndex, uint8_t Length) const { + return static_cast((Val >> (8 - BitIndex - Length)) & + ((1 << Length) - 1)); + } + + constexpr operator uint8_t() const { return Val; } +}; + +// Structure for the flag field of a symbol. See +// https://www.ibm.com/docs/en/zos/3.1.0?topic=formats-external-symbol-definition-record +// at offset 41 for the definition. +struct SymbolFlags { + Flags SymFlags; + +#define GOFF_SYMBOL_FLAG(NAME, TYPE, BITINDEX, LENGTH) \ + void set##NAME(TYPE Val) { SymFlags.set(BITINDEX, LENGTH, Val); } \ + TYPE get##NAME() const { return SymFlags.get(BITINDEX, LENGTH); } + + GOFF_SYMBOL_FLAG(FillBytePresence, bool, 0, 1) + GOFF_SYMBOL_FLAG(Mangled, bool, 1, 1) + GOFF_SYMBOL_FLAG(Renameable, bool, 2, 1) + GOFF_SYMBOL_FLAG(RemovableClass, bool, 3, 1) + GOFF_SYMBOL_FLAG(ReservedQwords, ESDReserveQwords, 5, 3) + +#undef GOFF_SYMBOL_FLAG + + constexpr operator uint8_t() const { return static_cast(SymFlags); } +}; + +// Structure for the behavioral attributes. See +// https://www.ibm.com/docs/en/zos/3.1.0?topic=record-external-symbol-definition-behavioral-attributes +// for the definition. +struct BehavioralAttributes { + Flags Attr[10]; + +#define GOFF_BEHAVIORAL_ATTRIBUTE(NAME, TYPE, ATTRIDX, BITINDEX, LENGTH) \ + void set##NAME(TYPE Val) { Attr[ATTRIDX].set(BITINDEX, LENGTH, Val); } \ + TYPE get##NAME() const { return Attr[ATTRIDX].get(BITINDEX, LENGTH); } + + GOFF_BEHAVIORAL_ATTRIBUTE(Amode, GOFF::ESDAmode, 0, 0, 8) + GOFF_BEHAVIORAL_ATTRIBUTE(Rmode, GOFF::ESDRmode, 1, 0, 8) + GOFF_BEHAVIORAL_ATTRIBUTE(TextStyle, GOFF::ESDTextStyle, 2, 0, 4) + GOFF_BEHAVIORAL_ATTRIBUTE(BindingAlgorithm, GOFF::ESDBindingAlgorithm, 2, 4, + 4) + GOFF_BEHAVIORAL_ATTRIBUTE(TaskingBehavior, GOFF::ESDTaskingBehavior, 3, 0, 3) + GOFF_BEHAVIORAL_ATTRIBUTE(ReadOnly, bool, 3, 4, 1) + GOFF_BEHAVIORAL_ATTRIBUTE(Executable, GOFF::ESDExecutable, 3, 5, 3) + GOFF_BEHAVIORAL_ATTRIBUTE(DuplicateSymbolSeverity, + GOFF::ESDDuplicateSymbolSeverity, 4, 2, 2) + GOFF_BEHAVIORAL_ATTRIBUTE(BindingStrength, GOFF::ESDBindingStrength, 4, 4, 4) + GOFF_BEHAVIORAL_ATTRIBUTE(LoadingBehavior, GOFF::ESDLoadingBehavior, 5, 0, 2) + GOFF_BEHAVIORAL_ATTRIBUTE(COMMON, bool, 5, 2, 1) + GOFF_BEHAVIORAL_ATTRIBUTE(IndirectReference, bool, 5, 3, 1) + GOFF_BEHAVIORAL_ATTRIBUTE(BindingScope, GOFF::ESDBindingScope, 5, 4, 4) + GOFF_BEHAVIORAL_ATTRIBUTE(LinkageType, GOFF::ESDLinkageType, 6, 2, 1) + GOFF_BEHAVIORAL_ATTRIBUTE(Alignment, GOFF::ESDAlignment, 6, 3, 5) + +#undef GOFF_BEHAVIORAL_ATTRIBUTE +}; } // end namespace GOFF } // end namespace llvm diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 00e681e6bf53e..fe450b3c1a3a2 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -316,10 +316,15 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile { }; class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile { + std::string DefaultRootSDName; + std::string DefaultADAPRName; + public: TargetLoweringObjectFileGOFF(); ~TargetLoweringObjectFileGOFF() override = default; + void getModuleMetadata(Module &M) override; + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const override; MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h index 76a750db3fa17..50085c436c63c 100644 --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -19,8 +19,10 @@ #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCAsmMacro.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCGOFFAttributes.h" #include "llvm/MC/MCPseudoProbe.h" #include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionGOFF.h" #include "llvm/MC/MCSymbolTableEntry.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/Allocator.h" @@ -54,7 +56,6 @@ class MCSection; class MCSectionCOFF; class MCSectionDXContainer; class MCSectionELF; -class MCSectionGOFF; class MCSectionMachO; class MCSectionSPIRV; class MCSectionWasm; @@ -356,6 +357,10 @@ class MCContext { MCSymbolXCOFF *createXCOFFSymbolImpl(const MCSymbolTableEntry *Name, bool IsTemporary); + template + MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name, + TAttr SDAttributes, MCSection *Parent); + /// Map of currently defined macros. StringMap MacroMap; @@ -606,9 +611,12 @@ class MCContext { getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags, unsigned EntrySize); - LLVM_ABI MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind, - MCSection *Parent, - uint32_t Subsection = 0); + MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name, + GOFF::SDAttr SDAttributes); + MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name, + GOFF::EDAttr EDAttributes, MCSection *Parent); + MCSectionGOFF *getGOFFSection(SectionKind Kind, StringRef Name, + GOFF::PRAttr PRAttributes, MCSection *Parent); LLVM_ABI MCSectionCOFF * getCOFFSection(StringRef Section, unsigned Characteristics, diff --git a/llvm/include/llvm/MC/MCGOFFAttributes.h b/llvm/include/llvm/MC/MCGOFFAttributes.h new file mode 100644 index 0000000000000..c996f0cae2c69 --- /dev/null +++ b/llvm/include/llvm/MC/MCGOFFAttributes.h @@ -0,0 +1,92 @@ +//===- MCGOFFAttributes.h - Attributes of GOFF symbols --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines the various attribute collections defining GOFF symbols. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCGOFFATTRIBUTES_H +#define LLVM_MC_MCGOFFATTRIBUTES_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/GOFF.h" +#include + +namespace llvm { +namespace GOFF { +// An "External Symbol Definition" in the GOFF file has a type, and depending on +// the type a different subset of the fields is used. +// +// Unlike other formats, a 2 dimensional structure is used to define the +// location of data. For example, the equivalent of the ELF .text section is +// made up of a Section Definition (SD) and a class (Element Definition; ED). +// The name of the SD symbol depends on the application, while the class has the +// predefined name C_CODE/C_CODE64 in AMODE31 and AMODE64 respectively. +// +// Data can be placed into this structure in 2 ways. First, the data (in a text +// record) can be associated with an ED symbol. To refer to data, a Label +// Definition (LD) is used to give an offset into the data a name. When binding, +// the whole data is pulled into the resulting executable, and the addresses +// given by the LD symbols are resolved. +// +// The alternative is to use a Part Definition (PR). In this case, the data (in +// a text record) is associated with the part. When binding, only the data of +// referenced PRs is pulled into the resulting binary. +// +// Both approaches are used. SD, ED, and PR elements are modelled by nested +// MCSectionGOFF instances, while LD elements are associated with MCSymbolGOFF +// instances. + +// Attributes for SD symbols. +struct SDAttr { + GOFF::ESDTaskingBehavior TaskingBehavior = GOFF::ESD_TA_Unspecified; + GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified; +}; + +// Attributes for ED symbols. +struct EDAttr { + bool IsReadOnly = false; + GOFF::ESDRmode Rmode; + GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_NormalName; + GOFF::ESDTextStyle TextStyle = GOFF::ESD_TS_ByteOriented; + GOFF::ESDBindingAlgorithm BindAlgorithm = GOFF::ESD_BA_Concatenate; + GOFF::ESDLoadingBehavior LoadBehavior = GOFF::ESD_LB_Initial; + GOFF::ESDReserveQwords ReservedQwords = GOFF::ESD_RQ_0; + GOFF::ESDAlignment Alignment = GOFF::ESD_ALIGN_Doubleword; + uint8_t FillByteValue = 0; +}; + +// Attributes for LD symbols. +struct LDAttr { + bool IsRenamable = false; + GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified; + GOFF::ESDBindingStrength BindingStrength = GOFF::ESD_BST_Strong; + GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink; + GOFF::ESDAmode Amode; + GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified; +}; + +// Attributes for PR symbols. +struct PRAttr { + bool IsRenamable = false; + GOFF::ESDExecutable Executable = GOFF::ESD_EXE_Unspecified; + GOFF::ESDLinkageType Linkage = GOFF::ESD_LT_XPLink; + GOFF::ESDBindingScope BindingScope = GOFF::ESD_BSC_Unspecified; + uint32_t SortKey = 0; +}; + +// Predefined GOFF class names. +constexpr StringLiteral CLASS_CODE = "C_CODE64"; +constexpr StringLiteral CLASS_WSA = "C_WSA64"; +constexpr StringLiteral CLASS_DATA = "C_DATA64"; +constexpr StringLiteral CLASS_PPA2 = "C_@@QPPA2"; + +} // namespace GOFF +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h index 28202f634f95a..b89d516e1452b 100644 --- a/llvm/include/llvm/MC/MCGOFFStreamer.h +++ b/llvm/include/llvm/MC/MCGOFFStreamer.h @@ -16,6 +16,7 @@ namespace llvm { class GOFFObjectWriter; class MCGOFFStreamer : public MCObjectStreamer { + public: MCGOFFStreamer(MCContext &Context, std::unique_ptr MAB, std::unique_ptr OW, @@ -25,6 +26,8 @@ class MCGOFFStreamer : public MCObjectStreamer { ~MCGOFFStreamer() override; + void changeSection(MCSection *Section, uint32_t Subsection = 0) override; + GOFFObjectWriter &getWriter(); bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h index 20c819bdfd961..5ce58ae0a836f 100644 --- a/llvm/include/llvm/MC/MCObjectFileInfo.h +++ b/llvm/include/llvm/MC/MCObjectFileInfo.h @@ -231,8 +231,6 @@ class LLVM_ABI MCObjectFileInfo { MCSection *GLJMPSection = nullptr; // GOFF specific sections. - MCSection *PPA1Section = nullptr; - MCSection *PPA2Section = nullptr; MCSection *PPA2ListSection = nullptr; MCSection *ADASection = nullptr; MCSection *IDRLSection = nullptr; @@ -439,8 +437,6 @@ class LLVM_ABI MCObjectFileInfo { MCSection *getGLJMPSection() const { return GLJMPSection; } // GOFF specific sections. - MCSection *getPPA1Section() const { return PPA1Section; } - MCSection *getPPA2Section() const { return PPA2Section; } MCSection *getPPA2ListSection() const { return PPA2ListSection; } MCSection *getADASection() const { return ADASection; } MCSection *getIDRLSection() const { return IDRLSection; } diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h index 11c0f95364037..b8b8cf112a34d 100644 --- a/llvm/include/llvm/MC/MCSectionGOFF.h +++ b/llvm/include/llvm/MC/MCSectionGOFF.h @@ -16,7 +16,9 @@ #define LLVM_MC_MCSECTIONGOFF_H #include "llvm/BinaryFormat/GOFF.h" +#include "llvm/MC/MCGOFFAttributes.h" #include "llvm/MC/MCSection.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -24,26 +26,85 @@ namespace llvm { class MCExpr; class MCSectionGOFF final : public MCSection { -private: - MCSection *Parent; - uint32_t Subsection; + // Parent of this section. Implies that the parent is emitted first. + MCSectionGOFF *Parent; + + // The attributes of the GOFF symbols. + union { + GOFF::SDAttr SDAttributes; + GOFF::EDAttr EDAttributes; + GOFF::PRAttr PRAttributes; + }; + + // The type of this section. + GOFF::ESDSymbolType SymbolType; + + // Indicates that the PR symbol needs to set the length of the section to a + // non-zero value. This is only a problem with the ADA PR - the binder will + // generate an error in this case. + unsigned RequiresNonZeroLength : 1; + + // Set to true if the section definition was already emitted. + mutable unsigned Emitted : 1; friend class MCContext; - MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, uint32_t Sub) + friend class MCSymbolGOFF; + + MCSectionGOFF(StringRef Name, SectionKind K, GOFF::SDAttr SDAttributes, + MCSectionGOFF *Parent) + : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr), + Parent(Parent), SDAttributes(SDAttributes), + SymbolType(GOFF::ESD_ST_SectionDefinition), RequiresNonZeroLength(0), + Emitted(0) {} + + MCSectionGOFF(StringRef Name, SectionKind K, GOFF::EDAttr EDAttributes, + MCSectionGOFF *Parent) + : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr), + Parent(Parent), EDAttributes(EDAttributes), + SymbolType(GOFF::ESD_ST_ElementDefinition), RequiresNonZeroLength(0), + Emitted(0) {} + + MCSectionGOFF(StringRef Name, SectionKind K, GOFF::PRAttr PRAttributes, + MCSectionGOFF *Parent) : MCSection(SV_GOFF, Name, K.isText(), /*IsVirtual=*/false, nullptr), - Parent(P), Subsection(Sub) {} + Parent(Parent), PRAttributes(PRAttributes), + SymbolType(GOFF::ESD_ST_PartReference), RequiresNonZeroLength(0), + Emitted(0) {} public: void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, - uint32_t /*Subsection*/) const override { - OS << "\t.section\t\"" << getName() << "\"\n"; - } + uint32_t Subsection) const override; bool useCodeAlign() const override { return false; } - MCSection *getParent() const { return Parent; } - uint32_t getSubsection() const { return Subsection; } + // Return the parent section. + MCSectionGOFF *getParent() const { return Parent; } + + // Returns the type of this section. + GOFF::ESDSymbolType getSymbolType() const { return SymbolType; } + + bool isSD() const { return SymbolType == GOFF::ESD_ST_SectionDefinition; } + bool isED() const { return SymbolType == GOFF::ESD_ST_ElementDefinition; } + bool isPR() const { return SymbolType == GOFF::ESD_ST_PartReference; } + + // Accessors to the attributes. + GOFF::SDAttr getSDAttributes() const { + assert(isSD() && "Not a SD section"); + return SDAttributes; + } + GOFF::EDAttr getEDAttributes() const { + assert(isED() && "Not a ED section"); + return EDAttributes; + } + GOFF::PRAttr getPRAttributes() const { + assert(isPR() && "Not a PR section"); + return PRAttributes; + } + + bool requiresNonZeroLength() const { return RequiresNonZeroLength; } + + void setName(StringRef SectionName) { Name = SectionName; } static bool classof(const MCSection *S) { return S->getVariant() == SV_GOFF; } }; diff --git a/llvm/include/llvm/MC/MCSymbolGOFF.h b/llvm/include/llvm/MC/MCSymbolGOFF.h index 9ca53a5653108..d8c570d2de240 100644 --- a/llvm/include/llvm/MC/MCSymbolGOFF.h +++ b/llvm/include/llvm/MC/MCSymbolGOFF.h @@ -13,15 +13,41 @@ #ifndef LLVM_MC_MCSYMBOLGOFF_H #define LLVM_MC_MCSYMBOLGOFF_H +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/MC/MCGOFFAttributes.h" +#include "llvm/MC/MCSectionGOFF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolTableEntry.h" namespace llvm { class MCSymbolGOFF : public MCSymbol { + // Associated data area of the section. Needs to be emitted first. + MCSectionGOFF *ADA; + + GOFF::LDAttr LDAttributes; + + enum SymbolFlags : uint16_t { + SF_LD = 0x01, // LD attributes are set. + }; + public: MCSymbolGOFF(const MCSymbolTableEntry *Name, bool IsTemporary) : MCSymbol(SymbolKindGOFF, Name, IsTemporary) {} + + void setLDAttributes(GOFF::LDAttr Attr) { + modifyFlags(SF_LD, SF_LD); + LDAttributes = Attr; + } + GOFF::LDAttr getLDAttributes() const { return LDAttributes; } + bool hasLDAttributes() const { return getFlags() & SF_LD; } + + void setADA(MCSectionGOFF *AssociatedDataArea) { + ADA = AssociatedDataArea; + AssociatedDataArea->RequiresNonZeroLength = true; + } + MCSectionGOFF *getADA() const { return ADA; } + static bool classof(const MCSymbol *S) { return S->isGOFF(); } }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index c804a179d8865..5454cd475f5ed 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -19,6 +19,7 @@ #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/GOFF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/CodeGen/BasicBlockSectionUtils.h" @@ -47,6 +48,7 @@ #include "llvm/MC/MCAsmInfoDarwin.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCGOFFAttributes.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionGOFF.h" @@ -56,6 +58,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCSymbolGOFF.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/SectionKind.h" #include "llvm/ProfileData/InstrProf.h" @@ -64,6 +67,7 @@ #include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/TargetParser/Triple.h" @@ -2775,6 +2779,29 @@ MCSection *TargetLoweringObjectFileXCOFF::getSectionForLSDA( //===----------------------------------------------------------------------===// TargetLoweringObjectFileGOFF::TargetLoweringObjectFileGOFF() = default; +void TargetLoweringObjectFileGOFF::getModuleMetadata(Module &M) { + // Construct the default names for the root SD and the ADA PR symbol. + StringRef FileName = sys::path::stem(M.getSourceFileName()); + if (FileName.size() > 1 && FileName.starts_with('<') && + FileName.ends_with('>')) + FileName = FileName.substr(1, FileName.size() - 2); + DefaultRootSDName = Twine(FileName).concat("#C").str(); + DefaultADAPRName = Twine(FileName).concat("#S").str(); + MCSectionGOFF *RootSD = + static_cast(TextSection)->getParent(); + MCSectionGOFF *ADAPR = static_cast(ADASection); + RootSD->setName(DefaultRootSDName); + ADAPR->setName(DefaultADAPRName); + // Initialize the label for the text section. + MCSymbolGOFF *TextLD = static_cast( + getContext().getOrCreateSymbol(RootSD->getName())); + TextLD->setLDAttributes(GOFF::LDAttr{ + false, GOFF::ESD_EXE_CODE, GOFF::ESD_BST_Strong, GOFF::ESD_LT_XPLink, + GOFF::ESD_AMODE_64, GOFF::ESD_BSC_Section}); + TextLD->setADA(ADAPR); + TextSection->setBeginSymbol(TextLD); +} + MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { return SelectSectionForGlobal(GO, Kind, TM); @@ -2783,15 +2810,56 @@ MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal( MCSection *TargetLoweringObjectFileGOFF::getSectionForLSDA( const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const { std::string Name = ".gcc_exception_table." + F.getName().str(); - return getContext().getGOFFSection(Name, SectionKind::getData(), nullptr, 0); + + MCSectionGOFF *WSA = getContext().getGOFFSection( + SectionKind::getMetadata(), GOFF::CLASS_WSA, + GOFF::EDAttr{false, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts, + GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge, + GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0, + GOFF::ESD_ALIGN_Fullword, 0}, + static_cast(TextSection)->getParent()); + return getContext().getGOFFSection(SectionKind::getData(), Name, + GOFF::PRAttr{true, GOFF::ESD_EXE_DATA, + GOFF::ESD_LT_XPLink, + GOFF::ESD_BSC_Section, 0}, + WSA); } MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { auto *Symbol = TM.getSymbol(GO); - if (Kind.isBSS()) - return getContext().getGOFFSection(Symbol->getName(), SectionKind::getBSS(), - nullptr, 0); - return getContext().getObjectFileInfo()->getTextSection(); + if (Kind.isBSS() || Kind.isData()) { + GOFF::ESDBindingScope PRBindingScope = + GO->hasExternalLinkage() + ? (GO->hasDefaultVisibility() ? GOFF::ESD_BSC_ImportExport + : GOFF::ESD_BSC_Library) + : GOFF::ESD_BSC_Section; + GOFF::ESDBindingScope SDBindingScope = + PRBindingScope == GOFF::ESD_BSC_Section ? GOFF::ESD_BSC_Section + : GOFF::ESD_BSC_Unspecified; + MaybeAlign Alignment; + if (auto *F = dyn_cast(GO)) + Alignment = F->getAlign(); + else if (auto *V = dyn_cast(GO)) + Alignment = V->getAlign(); + GOFF::ESDAlignment Align = + Alignment ? static_cast(Log2(*Alignment)) + : GOFF::ESD_ALIGN_Doubleword; + MCSectionGOFF *SD = getContext().getGOFFSection( + SectionKind::getMetadata(), Symbol->getName(), + GOFF::SDAttr{GOFF::ESD_TA_Unspecified, SDBindingScope}); + MCSectionGOFF *ED = getContext().getGOFFSection( + SectionKind::getMetadata(), GOFF::CLASS_WSA, + GOFF::EDAttr{false, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts, + GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge, + GOFF::ESD_LB_Deferred, GOFF::ESD_RQ_0, Align, 0}, + SD); + return getContext().getGOFFSection(Kind, Symbol->getName(), + GOFF::PRAttr{false, GOFF::ESD_EXE_DATA, + GOFF::ESD_LT_XPLink, + PRBindingScope, 0}, + ED); + } + return TextSection; } diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt index f49f14c848b90..d662c42c522fc 100644 --- a/llvm/lib/MC/CMakeLists.txt +++ b/llvm/lib/MC/CMakeLists.txt @@ -46,6 +46,7 @@ add_llvm_component_library(LLVMMC MCSectionCOFF.cpp MCSectionDXContainer.cpp MCSectionELF.cpp + MCSectionGOFF.cpp MCSectionMachO.cpp MCSectionWasm.cpp MCSectionXCOFF.cpp diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp index dd249d3608566..1f3c131289b49 100644 --- a/llvm/lib/MC/GOFFObjectWriter.cpp +++ b/llvm/lib/MC/GOFFObjectWriter.cpp @@ -12,8 +12,13 @@ #include "llvm/BinaryFormat/GOFF.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCGOFFAttributes.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/raw_ostream.h" @@ -23,44 +28,13 @@ using namespace llvm; #define DEBUG_TYPE "goff-writer" namespace { - -// The standard System/390 convention is to name the high-order (leftmost) bit -// in a byte as bit zero. The Flags type helps to set bits in a byte according -// to this numeration order. -class Flags { - uint8_t Val; - - constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value, - uint8_t OldValue) { - assert(BitIndex < 8 && "Bit index out of bounds!"); - assert(Length + BitIndex <= 8 && "Bit length too long!"); - - uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length); - Value = Value << (8 - BitIndex - Length); - assert((Value & Mask) == Value && "Bits set outside of range!"); - - return (OldValue & ~Mask) | Value; - } - -public: - constexpr Flags() : Val(0) {} - constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value) - : Val(bits(BitIndex, Length, Value, 0)) {} - - void set(uint8_t BitIndex, uint8_t Length, uint8_t Value) { - Val = bits(BitIndex, Length, Value, Val); - } - - constexpr operator uint8_t() const { return Val; } -}; - // Common flag values on records. // Flag: This record is continued. -constexpr uint8_t RecContinued = Flags(7, 1, 1); +constexpr uint8_t RecContinued = GOFF::Flags(7, 1, 1); // Flag: This record is a continuation. -constexpr uint8_t RecContinuation = Flags(6, 1, 1); +constexpr uint8_t RecContinuation = GOFF::Flags(6, 1, 1); // The GOFFOstream is responsible to write the data into the fixed physical // records of the format. A user of this class announces the begin of a new @@ -223,19 +197,160 @@ void GOFFOstream::finalizeRecord() { } namespace { +// A GOFFSymbol holds all the data required for writing an ESD record. +class GOFFSymbol { +public: + std::string Name; + uint32_t EsdId; + uint32_t ParentEsdId; + uint64_t Offset = 0; // Offset of the symbol into the section. LD only. + // Offset is only 32 bit, the larger type is used to + // enable error checking. + GOFF::ESDSymbolType SymbolType; + GOFF::ESDNameSpaceId NameSpace = GOFF::ESD_NS_ProgramManagementBinder; + + GOFF::BehavioralAttributes BehavAttrs; + GOFF::SymbolFlags SymbolFlags; + uint32_t SortKey = 0; + uint32_t SectionLength = 0; + uint32_t ADAEsdId = 0; + uint32_t EASectionEDEsdId = 0; + uint32_t EASectionOffset = 0; + uint8_t FillByteValue = 0; + + GOFFSymbol() : EsdId(0), ParentEsdId(0) {} + + GOFFSymbol(StringRef Name, uint32_t EsdID, const GOFF::SDAttr &Attr) + : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(0), + SymbolType(GOFF::ESD_ST_SectionDefinition) { + BehavAttrs.setTaskingBehavior(Attr.TaskingBehavior); + BehavAttrs.setBindingScope(Attr.BindingScope); + } + + GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID, + const GOFF::EDAttr &Attr) + : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID), + SymbolType(GOFF::ESD_ST_ElementDefinition) { + this->NameSpace = Attr.NameSpace; + // We always set a fill byte value. + this->FillByteValue = Attr.FillByteValue; + SymbolFlags.setFillBytePresence(1); + SymbolFlags.setReservedQwords(Attr.ReservedQwords); + // TODO Do we need/should set the "mangled" flag? + BehavAttrs.setReadOnly(Attr.IsReadOnly); + BehavAttrs.setRmode(Attr.Rmode); + BehavAttrs.setTextStyle(Attr.TextStyle); + BehavAttrs.setBindingAlgorithm(Attr.BindAlgorithm); + BehavAttrs.setLoadingBehavior(Attr.LoadBehavior); + BehavAttrs.setAlignment(Attr.Alignment); + } + + GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID, + GOFF::ESDNameSpaceId NameSpace, const GOFF::LDAttr &Attr) + : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID), + SymbolType(GOFF::ESD_ST_LabelDefinition), NameSpace(NameSpace) { + SymbolFlags.setRenameable(Attr.IsRenamable); + BehavAttrs.setExecutable(Attr.Executable); + BehavAttrs.setBindingStrength(Attr.BindingStrength); + BehavAttrs.setLinkageType(Attr.Linkage); + BehavAttrs.setAmode(Attr.Amode); + BehavAttrs.setBindingScope(Attr.BindingScope); + } + + GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID, + const GOFF::EDAttr &EDAttr, const GOFF::PRAttr &Attr) + : Name(Name.data(), Name.size()), EsdId(EsdID), ParentEsdId(ParentEsdID), + SymbolType(GOFF::ESD_ST_PartReference), NameSpace(EDAttr.NameSpace) { + SymbolFlags.setRenameable(Attr.IsRenamable); + BehavAttrs.setExecutable(Attr.Executable); + BehavAttrs.setLinkageType(Attr.Linkage); + BehavAttrs.setBindingScope(Attr.BindingScope); + BehavAttrs.setAlignment(EDAttr.Alignment); + } +}; + class GOFFWriter { GOFFOstream OS; + MCAssembler &Asm; void writeHeader(); + void writeSymbol(const GOFFSymbol &Symbol); void writeEnd(); + void defineSectionSymbols(const MCSectionGOFF &Section); + void defineLabel(const MCSymbolGOFF &Symbol); + void defineSymbols(); + public: - GOFFWriter(raw_pwrite_stream &OS); + GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm); uint64_t writeObject(); }; } // namespace -GOFFWriter::GOFFWriter(raw_pwrite_stream &OS) : OS(OS) {} +GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm) + : OS(OS), Asm(Asm) {} + +void GOFFWriter::defineSectionSymbols(const MCSectionGOFF &Section) { + if (Section.isSD()) { + GOFFSymbol SD(Section.getName(), Section.getOrdinal(), + Section.getSDAttributes()); + writeSymbol(SD); + } + + if (Section.isED()) { + GOFFSymbol ED(Section.getName(), Section.getOrdinal(), + Section.getParent()->getOrdinal(), Section.getEDAttributes()); + ED.SectionLength = Asm.getSectionAddressSize(Section); + writeSymbol(ED); + } + + if (Section.isPR()) { + MCSectionGOFF *Parent = Section.getParent(); + GOFFSymbol PR(Section.getName(), Section.getOrdinal(), Parent->getOrdinal(), + Parent->getEDAttributes(), Section.getPRAttributes()); + PR.SectionLength = Asm.getSectionAddressSize(Section); + if (Section.requiresNonZeroLength()) { + // We cannot have a zero-length section for data. If we do, + // artificially inflate it. Use 2 bytes to avoid odd alignments. Note: + // if this is ever changed, you will need to update the code in + // SystemZAsmPrinter::emitCEEMAIN and SystemZAsmPrinter::emitCELQMAIN to + // generate -1 if there is no ADA + if (!PR.SectionLength) + PR.SectionLength = 2; + } + writeSymbol(PR); + } +} + +void GOFFWriter::defineLabel(const MCSymbolGOFF &Symbol) { + MCSectionGOFF &Section = static_cast(Symbol.getSection()); + GOFFSymbol LD(Symbol.getName(), Symbol.getIndex(), Section.getOrdinal(), + Section.getEDAttributes().NameSpace, Symbol.getLDAttributes()); + if (Symbol.getADA()) + LD.ADAEsdId = Symbol.getADA()->getOrdinal(); + writeSymbol(LD); +} + +void GOFFWriter::defineSymbols() { + unsigned Ordinal = 0; + // Process all sections. + for (MCSection &S : Asm) { + auto &Section = cast(S); + Section.setOrdinal(++Ordinal); + defineSectionSymbols(Section); + } + + // Process all symbols + for (const MCSymbol &Sym : Asm.symbols()) { + if (Sym.isTemporary()) + continue; + auto &Symbol = cast(Sym); + if (Symbol.hasLDAttributes()) { + Symbol.setIndex(++Ordinal); + defineLabel(Symbol); + } + } +} void GOFFWriter::writeHeader() { OS.newRecord(GOFF::RT_HDR); @@ -251,6 +366,45 @@ void GOFFWriter::writeHeader() { OS.write_zeros(6); // Reserved } +void GOFFWriter::writeSymbol(const GOFFSymbol &Symbol) { + if (Symbol.Offset >= (((uint64_t)1) << 31)) + report_fatal_error("ESD offset out of range"); + + // All symbol names are in EBCDIC. + SmallString<256> Name; + ConverterEBCDIC::convertToEBCDIC(Symbol.Name, Name); + + // Check length here since this number is technically signed but we need uint + // for writing to records. + if (Name.size() >= GOFF::MaxDataLength) + report_fatal_error("Symbol max name length exceeded"); + uint16_t NameLength = Name.size(); + + OS.newRecord(GOFF::RT_ESD); + OS.writebe(Symbol.SymbolType); // Symbol Type + OS.writebe(Symbol.EsdId); // ESDID + OS.writebe(Symbol.ParentEsdId); // Parent or Owning ESDID + OS.writebe(0); // Reserved + OS.writebe( + static_cast(Symbol.Offset)); // Offset or Address + OS.writebe(0); // Reserved + OS.writebe(Symbol.SectionLength); // Length + OS.writebe(Symbol.EASectionEDEsdId); // Extended Attribute ESDID + OS.writebe(Symbol.EASectionOffset); // Extended Attribute Offset + OS.writebe(0); // Reserved + OS.writebe(Symbol.NameSpace); // Name Space ID + OS.writebe(Symbol.SymbolFlags); // Flags + OS.writebe(Symbol.FillByteValue); // Fill-Byte Value + OS.writebe(0); // Reserved + OS.writebe(Symbol.ADAEsdId); // ADA ESDID + OS.writebe(Symbol.SortKey); // Sort Priority + OS.writebe(0); // Reserved + for (auto F : Symbol.BehavAttrs.Attr) + OS.writebe(F); // Behavioral Attributes + OS.writebe(NameLength); // Name Length + OS.write(Name.data(), NameLength); // Name +} + void GOFFWriter::writeEnd() { uint8_t F = GOFF::END_EPR_None; uint8_t AMODE = 0; @@ -259,9 +413,9 @@ void GOFFWriter::writeEnd() { // TODO Set Flags/AMODE/ESDID for entry point. OS.newRecord(GOFF::RT_END); - OS.writebe(Flags(6, 2, F)); // Indicator flags - OS.writebe(AMODE); // AMODE - OS.write_zeros(3); // Reserved + OS.writebe(GOFF::Flags(6, 2, F)); // Indicator flags + OS.writebe(AMODE); // AMODE + OS.write_zeros(3); // Reserved // The record count is the number of logical records. In principle, this value // is available as OS.logicalRecords(). However, some tools rely on this field // being zero. @@ -271,6 +425,9 @@ void GOFFWriter::writeEnd() { uint64_t GOFFWriter::writeObject() { writeHeader(); + + defineSymbols(); + writeEnd(); // Make sure all records are written. @@ -289,7 +446,7 @@ GOFFObjectWriter::GOFFObjectWriter( GOFFObjectWriter::~GOFFObjectWriter() {} uint64_t GOFFObjectWriter::writeObject() { - uint64_t Size = GOFFWriter(OS).writeObject(); + uint64_t Size = GOFFWriter(OS, *Asm).writeObject(); return Size; } diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp index 99c74f6f5c978..f3bb5aa88e8fb 100644 --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/GOFF.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCAsmInfo.h" @@ -720,22 +721,46 @@ MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags, : std::nullopt; } -MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind, - MCSection *Parent, - uint32_t Subsection) { +template +MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name, + TAttr Attributes, MCSection *Parent) { + std::string UniqueName(Name); + if (Parent) { + UniqueName.append("/").append(Parent->getName()); + if (auto *P = static_cast(Parent)->getParent()) + UniqueName.append("/").append(P->getName()); + } // Do the lookup. If we don't have a hit, return a new section. - auto [Iter, Inserted] = GOFFUniquingMap.try_emplace(Section.str()); - if (!Inserted) + auto IterBool = GOFFUniquingMap.insert(std::make_pair(UniqueName, nullptr)); + auto Iter = IterBool.first; + if (!IterBool.second) return Iter->second; - StringRef CachedName = Iter->first; - MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate()) - MCSectionGOFF(CachedName, Kind, Parent, Subsection); + StringRef CachedName = StringRef(Iter->first.c_str(), Name.size()); + MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate()) MCSectionGOFF( + CachedName, Kind, Attributes, static_cast(Parent)); Iter->second = GOFFSection; allocInitialFragment(*GOFFSection); return GOFFSection; } +MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name, + GOFF::SDAttr SDAttributes) { + return getGOFFSection(Kind, Name, SDAttributes, nullptr); +} + +MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name, + GOFF::EDAttr EDAttributes, + MCSection *Parent) { + return getGOFFSection(Kind, Name, EDAttributes, Parent); +} + +MCSectionGOFF *MCContext::getGOFFSection(SectionKind Kind, StringRef Name, + GOFF::PRAttr PRAttributes, + MCSection *Parent) { + return getGOFFSection(Kind, Name, PRAttributes, Parent); +} + MCSectionCOFF *MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, StringRef COMDATSymName, int Selection, diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp index c9e4c21c857ce..b7021915e7b70 100644 --- a/llvm/lib/MC/MCGOFFStreamer.cpp +++ b/llvm/lib/MC/MCGOFFStreamer.cpp @@ -26,6 +26,21 @@ GOFFObjectWriter &MCGOFFStreamer::getWriter() { return static_cast(getAssembler().getWriter()); } +// Make sure that all section are registered in the correct order. +static void registerSectionHierarchy(MCAssembler &Asm, MCSectionGOFF *Section) { + if (Section->isRegistered()) + return; + if (Section->getParent()) + registerSectionHierarchy(Asm, Section->getParent()); + Asm.registerSection(*Section); +} + +void MCGOFFStreamer::changeSection(MCSection *Section, uint32_t Subsection) { + registerSectionHierarchy(getAssembler(), + static_cast(Section)); + MCObjectStreamer::changeSection(Section, Subsection); +} + MCStreamer *llvm::createGOFFStreamer(MCContext &Context, std::unique_ptr &&MAB, std::unique_ptr &&OW, diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp index 9ad56aaf05bc5..0069d12dce396 100644 --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -13,6 +13,7 @@ #include "llvm/BinaryFormat/Wasm.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCGOFFAttributes.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionDXContainer.h" @@ -546,18 +547,51 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { } void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) { - TextSection = Ctx->getGOFFSection(".text", SectionKind::getText(), nullptr); - BSSSection = Ctx->getGOFFSection(".bss", SectionKind::getBSS(), nullptr); - PPA1Section = Ctx->getGOFFSection(".ppa1", SectionKind::getMetadata(), - TextSection, GOFF::SK_PPA1); - PPA2Section = Ctx->getGOFFSection(".ppa2", SectionKind::getMetadata(), - TextSection, GOFF::SK_PPA2); - - PPA2ListSection = - Ctx->getGOFFSection(".ppa2list", SectionKind::getData(), nullptr); - - ADASection = Ctx->getGOFFSection(".ada", SectionKind::getData(), nullptr); - IDRLSection = Ctx->getGOFFSection("B_IDRL", SectionKind::getData(), nullptr); + MCSectionGOFF *RootSDSection = Ctx->getGOFFSection( + SectionKind::getMetadata(), "#C", + GOFF::SDAttr{GOFF::ESD_TA_Rent, GOFF::ESD_BSC_Section}); + + MCSectionGOFF *ADAEDSection = Ctx->getGOFFSection( + SectionKind::getMetadata(), GOFF::CLASS_WSA, + GOFF::EDAttr{false, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts, + GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge, + GOFF::ESD_LB_Deferred, GOFF::ESD_RQ_1, + GOFF::ESD_ALIGN_Quadword, 0}, + RootSDSection); + ADASection = Ctx->getGOFFSection(SectionKind::getData(), "#S", + GOFF::PRAttr{false, GOFF::ESD_EXE_DATA, + GOFF::ESD_LT_XPLink, + GOFF::ESD_BSC_Section, 0}, + ADAEDSection); + + TextSection = Ctx->getGOFFSection( + SectionKind::getText(), GOFF::CLASS_CODE, + GOFF::EDAttr{true, GOFF::ESD_RMODE_64, GOFF::ESD_NS_NormalName, + GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Concatenate, + GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0, + GOFF::ESD_ALIGN_Doubleword, 0}, + RootSDSection); + + MCSectionGOFF *PPA2ListEDSection = Ctx->getGOFFSection( + SectionKind::getMetadata(), GOFF::CLASS_PPA2, + GOFF::EDAttr{true, GOFF::ESD_RMODE_64, GOFF::ESD_NS_Parts, + GOFF::ESD_TS_ByteOriented, GOFF::ESD_BA_Merge, + GOFF::ESD_LB_Initial, GOFF::ESD_RQ_0, + GOFF::ESD_ALIGN_Doubleword, 0}, + RootSDSection); + PPA2ListSection = Ctx->getGOFFSection(SectionKind::getData(), ".&ppa2", + GOFF::PRAttr{true, GOFF::ESD_EXE_DATA, + GOFF::ESD_LT_OS, + GOFF::ESD_BSC_Section, 0}, + PPA2ListEDSection); + + IDRLSection = Ctx->getGOFFSection( + SectionKind::getData(), "B_IDRL", + GOFF::EDAttr{true, GOFF::ESD_RMODE_64, GOFF::ESD_NS_NormalName, + GOFF::ESD_TS_Structured, GOFF::ESD_BA_Concatenate, + GOFF::ESD_LB_NoLoad, GOFF::ESD_RQ_0, + GOFF::ESD_ALIGN_Doubleword, 0}, + RootSDSection); } void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { diff --git a/llvm/lib/MC/MCSectionGOFF.cpp b/llvm/lib/MC/MCSectionGOFF.cpp new file mode 100644 index 0000000000000..8163e5bbd632b --- /dev/null +++ b/llvm/lib/MC/MCSectionGOFF.cpp @@ -0,0 +1,143 @@ +//===- MCSectionGOFF.cpp - GOFF Code Section Representation ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSectionGOFF.h" +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static void emitCATTR(raw_ostream &OS, StringRef Name, GOFF::ESDRmode Rmode, + GOFF::ESDAlignment Alignment, + GOFF::ESDLoadingBehavior LoadBehavior, + GOFF::ESDExecutable Executable, bool IsReadOnly, + uint32_t SortKey, uint8_t FillByteValue, + StringRef PartName) { + OS << Name << " CATTR "; + OS << "ALIGN(" << static_cast(Alignment) << ")," + << "FILL(" << static_cast(FillByteValue) << ")"; + switch (LoadBehavior) { + case GOFF::ESD_LB_Deferred: + OS << ",DEFLOAD"; + break; + case GOFF::ESD_LB_NoLoad: + OS << ",NOLOAD"; + break; + default: + break; + } + switch (Executable) { + case GOFF::ESD_EXE_CODE: + OS << ",EXECUTABLE"; + break; + case GOFF::ESD_EXE_DATA: + OS << ",NOTEXECUTABLE"; + break; + default: + break; + } + if (IsReadOnly) + OS << ",READONLY"; + if (Rmode != GOFF::ESD_RMODE_None) { + OS << ','; + OS << "RMODE("; + switch (Rmode) { + case GOFF::ESD_RMODE_24: + OS << "24"; + break; + case GOFF::ESD_RMODE_31: + OS << "31"; + break; + case GOFF::ESD_RMODE_64: + OS << "64"; + break; + case GOFF::ESD_RMODE_None: + break; + } + OS << ')'; + } + if (SortKey) + OS << ",PRIORITY(" << SortKey << ")"; + if (!PartName.empty()) + OS << ",PART(" << PartName << ")"; + OS << '\n'; +} + +static void emitXATTR(raw_ostream &OS, StringRef Name, + GOFF::ESDLinkageType Linkage, + GOFF::ESDExecutable Executable, + GOFF::ESDBindingScope BindingScope) { + OS << Name << " XATTR "; + OS << "LINKAGE(" << (Linkage == GOFF::ESD_LT_OS ? "OS" : "XPLINK") << "),"; + if (Executable != GOFF::ESD_EXE_Unspecified) + OS << "REFERENCE(" << (Executable == GOFF::ESD_EXE_CODE ? "CODE" : "DATA") + << "),"; + if (BindingScope != GOFF::ESD_BSC_Unspecified) { + OS << "SCOPE("; + switch (BindingScope) { + case GOFF::ESD_BSC_Section: + OS << "SECTION"; + break; + case GOFF::ESD_BSC_Module: + OS << "MODULE"; + break; + case GOFF::ESD_BSC_Library: + OS << "LIBRARY"; + break; + case GOFF::ESD_BSC_ImportExport: + OS << "EXPORT"; + break; + default: + break; + } + OS << ')'; + } + OS << '\n'; +} + +void MCSectionGOFF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, + uint32_t Subsection) const { + switch (SymbolType) { + case GOFF::ESD_ST_SectionDefinition: { + OS << Name << " CSECT\n"; + Emitted = true; + break; + } + case GOFF::ESD_ST_ElementDefinition: { + getParent()->printSwitchToSection(MAI, T, OS, Subsection); + if (!Emitted) { + emitCATTR(OS, Name, EDAttributes.Rmode, EDAttributes.Alignment, + EDAttributes.LoadBehavior, GOFF::ESD_EXE_Unspecified, + EDAttributes.IsReadOnly, 0, EDAttributes.FillByteValue, + StringRef()); + Emitted = true; + } else + OS << Name << " CATTR\n"; + break; + } + case GOFF::ESD_ST_PartReference: { + MCSectionGOFF *ED = getParent(); + ED->getParent()->printSwitchToSection(MAI, T, OS, Subsection); + if (!Emitted) { + emitCATTR(OS, ED->getName(), ED->getEDAttributes().Rmode, + ED->EDAttributes.Alignment, ED->EDAttributes.LoadBehavior, + PRAttributes.Executable, ED->EDAttributes.IsReadOnly, + PRAttributes.SortKey, ED->EDAttributes.FillByteValue, Name); + emitXATTR(OS, Name, PRAttributes.Linkage, PRAttributes.Executable, + PRAttributes.BindingScope); + ED->Emitted = true; + Emitted = true; + } else + OS << ED->getName() << " CATTR PART(" << Name << ")\n"; + break; + } + default: + llvm_unreachable("Wrong section type"); + } +} \ No newline at end of file diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp index 6f9d25c050b71..eb0365d1f1893 100644 --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -21,6 +21,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" @@ -1254,7 +1255,8 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() { OutStreamer->emitLabel(FnEndSym); OutStreamer->pushSection(); - OutStreamer->switchSection(getObjFileLowering().getPPA1Section()); + OutStreamer->switchSection(getObjFileLowering().getTextSection(), + GOFF::SK_PPA1); emitPPA1(FnEndSym); OutStreamer->popSection(); @@ -1559,7 +1561,8 @@ void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) { void SystemZAsmPrinter::emitPPA2(Module &M) { OutStreamer->pushSection(); - OutStreamer->switchSection(getObjFileLowering().getPPA2Section()); + OutStreamer->switchSection(getObjFileLowering().getTextSection(), + GOFF::SK_PPA2); MCContext &OutContext = OutStreamer->getContext(); // Make CELQSTRT symbol. const char *StartSymbolName = "CELQSTRT"; diff --git a/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll b/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll index 068b56d8cef8b..d6aa99b5634d7 100644 --- a/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll +++ b/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll @@ -55,7 +55,9 @@ entry: declare signext i32 @callout(i32 signext) -; CHECK: .section ".ada" +; CHECK: stdin#C CSECT +; CHECK: C_WSA64 CATTR ALIGN(4),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(stdin#S) +; CHECK: stdin#S XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(SECTION) ; CHECK: .set L#DoFunc@indirect0, DoFunc ; CHECK: .indirect_symbol L#DoFunc@indirect0 ; CHECK: .quad V(L#DoFunc@indirect0) * Offset 0 pointer to function descriptor DoFunc diff --git a/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll b/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll index b1f0c9e5b8e54..c963d85d60f1c 100644 --- a/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll +++ b/llvm/test/CodeGen/SystemZ/zos-intrinsics.ll @@ -30,7 +30,9 @@ declare double @llvm.sin.f64(double) declare fp128 @llvm.exp2.f128(fp128) ; Check the calls in the ADA. -; CHECK: .section ".ada" +; CHECK: stdin#C CSECT +; CHECK: C_WSA64 CATTR ALIGN(4),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(stdin#S) +; CHECK: stdin#S XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(SECTION) ; Check that there is no call to sqrt. ; CHECK-NOT: .quad R(@@WSQT@B) diff --git a/llvm/test/CodeGen/SystemZ/zos-landingpad.ll b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll index 63c332eb423e3..307f280617619 100644 --- a/llvm/test/CodeGen/SystemZ/zos-landingpad.ll +++ b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll @@ -37,5 +37,7 @@ lpad: ; CHECK: Personality routine ; CHECK: LSDA location ; Check that the exception table is emitted into .lsda section. -; CHECK: .section ".gcc_exception_table.test1" +; CHECK: stdin#C CSECT +; CHECK: C_WSA64 CATTR ALIGN(2),FILL(0),NOTEXECUTABLE,RMODE(64),PART(.gcc_exception_table.test1) +; CHECK: .gcc_exception_table.test1 XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(SECTION) ; CHECK: GCC_except_table0: diff --git a/llvm/test/MC/GOFF/ppa1.ll b/llvm/test/CodeGen/SystemZ/zos-ppa1.ll similarity index 97% rename from llvm/test/MC/GOFF/ppa1.ll rename to llvm/test/CodeGen/SystemZ/zos-ppa1.ll index fe2dc77bba2f5..fc51e9c5eccc5 100644 --- a/llvm/test/MC/GOFF/ppa1.ll +++ b/llvm/test/CodeGen/SystemZ/zos-ppa1.ll @@ -12,7 +12,8 @@ ; CHECK: * Bit 1: 1 = Leaf function ; CHECK: * Bit 2: 0 = Does not use alloca ; CHECK: L#func_end0: -; CHECK: .section ".ppa1" +; CHECK: stdin#C CSECT +; CHECK: C_CODE64 CATTR ; CHECK: L#PPA1_void_test_0: * PPA1 ; CHECK: .byte 2 * Version ; CHECK: .byte 206 * LE Signature X'CE' diff --git a/llvm/test/CodeGen/SystemZ/zos-ppa2.ll b/llvm/test/CodeGen/SystemZ/zos-ppa2.ll index 07025091fb240..8f3847da32e31 100644 --- a/llvm/test/CodeGen/SystemZ/zos-ppa2.ll +++ b/llvm/test/CodeGen/SystemZ/zos-ppa2.ll @@ -1,6 +1,6 @@ ; RUN: llc -mtriple s390x-ibm-zos -mcpu=z15 -asm-verbose=true < %s | FileCheck %s -; CHECK: .section ".ppa2" +; CHECK: C_CODE64 CATTR ; CHECK: L#PPA2: ; CHECK: .byte 3 ; CHECK: .byte 231 @@ -19,7 +19,7 @@ ; CHECK: .quad L#PPA2-CELQSTRT * A(PPA2-CELQSTRT) ; CHECK: L#PPA1_void_test_0: ; CHECK: .long L#PPA2-L#PPA1_void_test_0 * Offset to PPA2 -; CHECK: .section "B_IDRL" +; CHECK: B_IDRL CATTR ; CHECK: .byte 0 ; CHECK: .byte 3 ; CHECK: .short 30 diff --git a/llvm/test/CodeGen/SystemZ/zos-section-1.ll b/llvm/test/CodeGen/SystemZ/zos-section-1.ll new file mode 100644 index 0000000000000..ea9bc4ce95174 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/zos-section-1.ll @@ -0,0 +1,112 @@ +; RUN: llc <%s --mtriple s390x-ibm-zos --filetype=obj | \ +; RUN: od -Ax -tx1 -v | FileCheck --ignore-case %s + +source_filename = "test.ll" + +declare void @other(...) + +define void @me() { +entry: + tail call void @other() + ret void +} + +; Header record: +; 03 is prefix byte +; f. is header type +; .0 is flag +; 00 is version +; The 1 at offset 0x33 is the architecture level. +; CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +; ESD record, type SD. +; 03 is prefix byte +; 0. is header type +; .0 is flag +; 00 is version +; 00 is type = SD +; The 01 at offset 0x57 is the id of the symbol. +; The 60 at offset 0x89 is the tasking behavior. +; The 01 at offset 0x91 is the binding scope. +; The name begins at offset 0x97, and is test#C. +; CHECK-NEXT: 000050 03 00 00 00 [[ROOTSD:00 00 00 01]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 +; CHECK-NEXT: 000090 00 01 00 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00 + +; ESD record, type ED. +; The name is C_CODE64. +; The regular expression matches the low byte of the length. +; CHECK-NEXT: 0000a0 03 00 00 01 [[C_CODE64:00 00 00 02]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 0000b0 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00 +; CHECK-NEXT: 0000c0 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00 +; CHECK-NEXT: 0000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 08 +; CHECK-NEXT: 0000e0 00 00 03 00 00 00 00 08 c3 6d c3 d6 c4 c5 f6 f4 + +; ESD record, type ED. +; The name is C_@@QPPA2. +; This record has a continuation, therefore the falg at offset 0xf1 is set. +; CHECK-NEXT: 0000f0 03 01 00 01 [[C_QPPA2:00 00 00 03]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000110 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00 +; CHECK-NEXT: 000120 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 08 +; CHECK-NEXT: 000130 00 00 03 00 00 00 00 09 c3 6d 7c 7c d8 d7 d7 c1 +; +; Continuation: +; CHECK-NEXT: 000140 03 02 00 f2 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +; ESD record, type PR. +; The name is .&ppa2. +; CHECK-NEXT: 000190 03 00 00 03 [[PPA2:00 00 00 04]] [[C_QPPA2]] 00 00 00 00 +; CHECK-NEXT: 0001a0 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 +; CHECK-NEXT: 0001b0 00 00 00 00 00 00 00 00 03 20 00 00 00 00 00 00 +; CHECK-NEXT: 0001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 +; CHECK-NEXT: 0001d0 00 01 03 00 00 00 00 06 4b 50 97 97 81 f2 00 00 + +; ESD record, type ED. +; The name is C_WSA64. +; CHECK-NEXT: 0001e0 03 00 00 01 [[C_WSA64:00 00 00 05]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 0001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000200 00 00 00 00 00 00 00 00 03 81 00 00 00 00 00 00 +; CHECK-NEXT: 000210 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00 +; CHECK-NEXT: 000220 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + +; ESD record, type PR. +; The name is test#S. +; CHECK-NEXT: 000230 03 00 00 03 [[TESTS:00 00 00 06]] [[C_WSA64]] 00 00 00 00 +; CHECK-NEXT: 000240 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00 +; CHECK-NEXT: 000250 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 +; CHECK-NEXT: 000260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 +; CHECK-NEXT: 000270 00 01 24 00 00 00 00 06 a3 85 a2 a3 7b e2 00 00 + +; ESD record, type ED. +; The name is B_IDRL. +; CHECK-NEXT: 000280 03 00 00 01 [[BIDRL:00 00 00 07]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 000290 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00 +; CHECK-NEXT: 0002a0 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00 +; CHECK-NEXT: 0002b0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 10 08 +; CHECK-NEXT: 0002c0 00 80 03 00 00 00 00 06 c2 6d c9 c4 d9 d3 00 00 + +; ESD record, type LD. +; The name is test#C. +; CHECK-NEXT: 0002d0 03 00 00 02 [[TESTC:00 00 00 08]] [[C_CODE64]] 00 00 00 00 +; CHECK-NEXT: 0002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0002f0 00 00 00 00 00 00 00 00 01 00 00 00 [[TESTS]] +; CHECK-NEXT: 000300 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 +; CHECK-NEXT: 000310 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00 + +; End record. +; CHECK-NEXT: 000320 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/llvm/test/CodeGen/SystemZ/zos-section-2.ll b/llvm/test/CodeGen/SystemZ/zos-section-2.ll new file mode 100644 index 0000000000000..472517acc4a45 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/zos-section-2.ll @@ -0,0 +1,155 @@ +; RUN: llc <%s --mtriple s390x-ibm-zos --filetype=obj | \ +; RUN: od -Ax -tx1 -v | FileCheck --ignore-case %s + +source_filename = "test.ll" + +@data = hidden global i32 42, align 4 +@bss = hidden global i64 0, align 8 + +; Header record: +; 03 is prefix byte +; f. is header type +; .0 is flag +; 00 is version +; The 1 at offset 0x33 is the architecture level. +; CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +; ESD record, type SD. +; 03 is prefix byte +; 0. is header type +; .0 is flag +; 00 is version +; 00 is type = SD +; The 01 at offset 0x57 is the id of the symbol. +; The 60 at offset 0x89 is the tasking behavior. +; The 01 at offset 0x91 is the binding scope. +; The name begins at offset 0x97, and is test#C. +; CHECK-NEXT: 000050 03 00 00 00 [[ROOTSD:00 00 00 01]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 +; CHECK-NEXT: 000090 00 01 00 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00 + +; ESD record, type ED. +; The name is C_CODE64. +; The regular expression matches the low byte of the length. +; CHECK-NEXT: 0000a0 03 00 00 01 [[C_CODE64:00 00 00 02]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 0000b0 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00 +; CHECK-NEXT: 0000c0 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00 +; CHECK-NEXT: 0000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 08 +; CHECK-NEXT: 0000e0 00 00 03 00 00 00 00 08 c3 6d c3 d6 c4 c5 f6 f4 + +; ESD record, type ED. +; The name is C_@@QPPA2. +; This record has a continuation, therefore the falg at offset 0xf1 is set. +; CHECK-NEXT: 0000f0 03 01 00 01 [[C_QPPA2:00 00 00 03]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000110 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00 +; CHECK-NEXT: 000120 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 08 +; CHECK-NEXT: 000130 00 00 03 00 00 00 00 09 c3 6d 7c 7c d8 d7 d7 c1 +; +; Continuation: +; CHECK-NEXT: 000140 03 02 00 f2 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +; ESD record, type PR. +; The name is .&ppa2. +; CHECK-NEXT: 000190 03 00 00 03 [[PPA2:00 00 00 04]] [[C_QPPA2]] 00 00 00 00 +; CHECK-NEXT: 0001a0 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 +; CHECK-NEXT: 0001b0 00 00 00 00 00 00 00 00 03 20 00 00 00 00 00 00 +; CHECK-NEXT: 0001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 +; CHECK-NEXT: 0001d0 00 01 03 00 00 00 00 06 4b 50 97 97 81 f2 00 00 + +; ESD record, type SD. +; The name is data. +; CHECK-NEXT: 0001e0 03 00 00 00 [[DATA:00 00 00 05]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000220 00 00 00 00 00 00 00 04 84 81 a3 81 00 00 00 00 + +; ESD record, type ED. +; The name is C_WSA64. +; CHECK-NEXT: 000230 03 00 00 01 [[DATA_WSA:00 00 00 06]] [[DATA]] 00 00 00 00 +; CHECK-NEXT: 000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000250 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00 +; CHECK-NEXT: 000260 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00 +; CHECK-NEXT: 000270 00 40 02 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + +; ESD record, type PR. +; The name is data. +; CHECK-NEXT: 000280 03 00 00 03 [[DATA_PR:00 00 00 07]] [[DATA_WSA]] 00 00 00 00 +; CHECK-NEXT: 000290 00 00 00 00 00 00 00 00 [[DATA_LEN:00 00 00 04]] 00 00 00 00 +; CHECK-NEXT: 0002a0 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 +; CHECK-NEXT: 0002b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 +; CHECK-NEXT: 0002c0 00 03 22 00 00 00 00 04 84 81 a3 81 00 00 00 00 + +; ESD record, type SD. +; The name is bss. +; CHECK-NEXT: 0002d0 03 00 00 00 [[BSS:00 00 00 08]] 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0002f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000310 00 00 00 00 00 00 00 03 82 a2 a2 00 00 00 00 00 + +; ESD record, type ED. +; The name is C_WSA64. +; CHECK-NEXT: 000320 03 00 00 01 [[BSS_WSA:00 00 00 09]] [[BSS]] 00 00 00 00 +; CHECK-NEXT: 000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000340 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00 +; CHECK-NEXT: 000350 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00 +; CHECK-NEXT: 000360 00 40 03 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + +; ESD record, type PR. +; The name is bss. +; CHECK-NEXT: 000370 03 00 00 03 [[BSS_PR:00 00 00 0a]] [[BSS_WSA]] 00 00 00 00 +; CHECK-NEXT: 000380 00 00 00 00 00 00 00 00 [[BSS_LEN:00 00 00 08]] 00 00 00 00 +; CHECK-NEXT: 000390 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 +; CHECK-NEXT: 0003a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 +; CHECK-NEXT: 0003b0 00 03 23 00 00 00 00 03 82 a2 a2 00 00 00 00 00 + +; ESD record, type ED. +; The name is C_WSA64. +; CHECK-NEXT: 0003c0 03 00 00 01 [[C_WSA64:00 00 00 0b]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 0003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0003e0 00 00 00 00 00 00 00 00 03 81 00 00 00 00 00 00 +; CHECK-NEXT: 0003f0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 00 +; CHECK-NEXT: 000400 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + +; ESD record, type PR. +; The name is test#S. +; CHECK-NEXT: 000410 03 00 00 03 [[TESTS:00 00 00 0c]] [[C_WSA64]] 00 00 00 00 +; CHECK-NEXT: 000420 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00 +; CHECK-NEXT: 000430 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 +; CHECK-NEXT: 000440 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 +; CHECK-NEXT: 000450 00 01 24 00 00 00 00 06 a3 85 a2 a3 7b e2 00 00 + +; ESD record, type ED. +; The name is B_IDRL. +; CHECK-NEXT: 000460 03 00 00 01 [[BIDRL:00 00 00 0d]] [[ROOTSD]] 00 00 00 00 +; CHECK-NEXT: 000470 00 00 00 00 00 00 00 00 00 00 00 {{..}} 00 00 00 00 +; CHECK-NEXT: 000480 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00 +; CHECK-NEXT: 000490 00 00 00 00 00 00 00 00 00 00 00 00 00 04 10 08 +; CHECK-NEXT: 0004a0 00 80 03 00 00 00 00 06 c2 6d c9 c4 d9 d3 00 00 + +; ESD record, type LD. +; The name is test#C. +; CHECK-NEXT: 0004b0 03 00 00 02 [[TESTC:00 00 00 0e]] [[C_CODE64]] 00 00 00 00 +; CHECK-NEXT: 0004c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 0004d0 00 00 00 00 00 00 00 00 01 00 00 00 [[TESTS]] +; CHECK-NEXT: 0004e0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 +; CHECK-NEXT: 0004f0 00 01 20 00 00 00 00 06 a3 85 a2 a3 7b c3 00 00 + +; End record. +; CHECK-NEXT: 000500 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000520 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK-NEXT: 000540 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/llvm/test/CodeGen/SystemZ/zos-simple-test.ll b/llvm/test/CodeGen/SystemZ/zos-simple-test.ll index a46079818b130..f1f7cee8268f7 100644 --- a/llvm/test/CodeGen/SystemZ/zos-simple-test.ll +++ b/llvm/test/CodeGen/SystemZ/zos-simple-test.ll @@ -5,9 +5,13 @@ @a = global i32 0, align 4 define signext i32 @main() { -; CHECK: .section ".text" +; CHECK: stdin#C CSECT +; CHECK: C_CODE64 CATTR ALIGN(3),FILL(0),READONLY,RMODE(64) ; CHECK: main: -; CHECK: .section "a" +; CHECK: stdin#C CSECT +; CHECK: C_WSA64 CATTR ALIGN(2),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(a) +; CHECK: a XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(EXPORT) +; CHECK: a: entry: ret i32 0 } diff --git a/llvm/test/MC/GOFF/empty-goff.s b/llvm/test/MC/GOFF/empty-goff.s index f6d402863d71c..ba1b0e0a49077 100644 --- a/llvm/test/MC/GOFF/empty-goff.s +++ b/llvm/test/MC/GOFF/empty-goff.s @@ -17,8 +17,8 @@ * 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 +* CHECK: {{([[:xdigit:]]{6})}} 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: {{([[:xdigit:]]{6})}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00