Index: llvm/include/llvm/BinaryFormat/GOFF.h =================================================================== --- llvm/include/llvm/BinaryFormat/GOFF.h +++ llvm/include/llvm/BinaryFormat/GOFF.h @@ -67,9 +67,7 @@ enum ESDReserveQwords : uint8_t { ESD_RQ_0 = 0, - ESD_RQ_1 = 1, - ESD_RQ_2 = 2, - ESD_RQ_3 = 3 + ESD_RQ_1 = 1 }; enum ESDAmode : uint8_t { @@ -157,6 +155,12 @@ 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, Index: llvm/include/llvm/MC/MCAssembler.h =================================================================== --- llvm/include/llvm/MC/MCAssembler.h +++ llvm/include/llvm/MC/MCAssembler.h @@ -134,6 +134,9 @@ /// List of declared file names std::vector> FileNames; + /// GOFF Csect names. + std::pair CsectNames; + MCDwarfLineTableParams LTParams; /// The set of function symbols for which a .thumb_func directive has @@ -483,6 +486,8 @@ FileNames.emplace_back(std::string(FileName), Symbols.size()); } + std::pair 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, Index: llvm/include/llvm/MC/MCContext.h =================================================================== --- llvm/include/llvm/MC/MCContext.h +++ llvm/include/llvm/MC/MCContext.h @@ -621,7 +621,8 @@ 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, Index: llvm/include/llvm/MC/MCGOFFObjectWriter.h =================================================================== --- llvm/include/llvm/MC/MCGOFFObjectWriter.h +++ llvm/include/llvm/MC/MCGOFFObjectWriter.h @@ -10,6 +10,7 @@ #define LLVM_MC_MCGOFFOBJECTWRITER_H #include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/Casting.h" namespace llvm { class MCObjectWriter; Index: llvm/include/llvm/MC/MCGOFFStreamer.h =================================================================== --- llvm/include/llvm/MC/MCGOFFStreamer.h +++ llvm/include/llvm/MC/MCGOFFStreamer.h @@ -24,9 +24,13 @@ ~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 {} Index: llvm/include/llvm/MC/MCSymbolGOFF.h =================================================================== --- llvm/include/llvm/MC/MCSymbolGOFF.h +++ llvm/include/llvm/MC/MCSymbolGOFF.h @@ -18,10 +18,50 @@ 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. + }; + + enum { + // Shift value for GOFF::ESDExecutable. 3 possible values. 2 bits. + GOFF_Executable_Shift = 6, + GOFF_Executable_Bitmask = 0x3, + }; + public: MCSymbolGOFF(const StringMapEntry *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( + (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 Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2672,6 +2672,10 @@ 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); Index: llvm/lib/MC/GOFFObjectWriter.cpp =================================================================== --- llvm/lib/MC/GOFFObjectWriter.cpp +++ llvm/lib/MC/GOFFObjectWriter.cpp @@ -13,8 +13,12 @@ #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/ConvertEBCDIC.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" @@ -78,10 +82,8 @@ /// The remaining size of this logical record, including fill bytes. size_t RemainingSize; -#ifndef NDEBUG /// The number of bytes needed to fill up the last physical record. size_t Gap = 0; -#endif /// The number of logical records emitted to far. uint32_t LogicalRecords; @@ -156,9 +158,6 @@ fillRecord(); CurrentType = Type; RemainingSize = Size; -#ifdef NDEBUG - size_t Gap; -#endif Gap = (RemainingSize % GOFF::RecordContentLength); if (Gap) { Gap = GOFF::RecordContentLength - Gap; @@ -216,13 +215,121 @@ } } +/// \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(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> SymbolListType; + typedef DenseMap SymbolMapType; + typedef std::vector> SectionListType; + typedef DenseMap SectionMapType; + // The target specific GOFF writer instance. std::unique_ptr 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 MOTW, raw_pwrite_stream &OS) @@ -230,20 +337,349 @@ ~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(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(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 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(Ctx.lookupSymbol(SectionName)); + + if (Sym) { + GOFFSymbol *ED = createWSASymbol(SD->EsdId); + GOFFSymbol *PR = createPRSymbol(SectionName, ED->EsdId); + ED->Alignment = + std::max(static_cast(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(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(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(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 @@ -258,6 +694,268 @@ 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(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, 69 + NameLength); + 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(Offset); // Offset or Address + OS.writeBE(0); // Reserved + OS.writeBE(Length); // Length + OS.writeBE(Symbol.EASectionEsdId); // Extended Attribute ESDID + OS.writeBE(Symbol.EASectionOffset); // Extended Attribute Offset + OS.writeBE(0); // Reserved + OS.writeBE(NameSpaceId); // Name Space ID + OS.writeBE(SymbolFlags); // Flags + OS.writeBE(FillByteValue); // Fill-Byte Value + OS.writeBE(0); // Reserved + OS.writeBE(AdaEsdId); // ADA ESDID + OS.writeBE(SortPriority); // Sort Priority + OS.writeBE(0); // Reserved + for (auto F : BehavAttrs) + OS.writeBE(F); // Behavioral Attributes + OS.writeBE(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::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, 21 + ToWriteLength); + OS.writeBE(Flags(4, 4, RecordStyle)); // Text Record Style + OS.writeBE(EsdId); // Element ESDID + OS.writeBE(0); // Reserved + OS.writeBE(static_cast(Offset)); // Offset + OS.writeBE(0); // Text Field True Length + OS.writeBE(0); // Text Encoding + OS.writeBE(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; @@ -282,10 +980,12 @@ 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."); - return OS.tell() - StartOffset; } Index: llvm/lib/MC/MCGOFFStreamer.cpp =================================================================== --- llvm/lib/MC/MCGOFFStreamer.cpp +++ 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 @@ 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(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(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; +} Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.h =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ llvm/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -113,6 +113,8 @@ } void emitFunctionEntryLabel() override; void emitFunctionBodyEnd() override; + void emitGlobalVariable(const GlobalVariable *GV) override; + const MCExpr *lowerConstant(const Constant *CV) override; private: void emitCallInformation(CallType CT); Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ 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,41 @@ 4); } +void SystemZAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { + if (TM.getTargetTriple().isOSzOS()) { + auto *Sym = cast(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(CV); + const GlobalVariable *GV = dyn_cast(CV); + const Function *FV = dyn_cast(CV); + bool IsFunc = !GV && (FV || (GA && isa(GA->getAliaseeObject()))); + MCSymbolGOFF *Sym = NULL; + + if (GA) + Sym = cast(getSymbol(GA)); + else if (IsFunc) + Sym = cast(getSymbol(FV)); + else if (GV) + Sym = cast(getSymbol(GV)); + + if (IsFunc) { + } else if (Sym) { + Sym->setExecutable(GOFF::ESD_EXE_DATA); + return MCSymbolRefExpr::create(Sym, OutContext); + } + } + + return AsmPrinter::lowerConstant(CV); +} + void SystemZAsmPrinter::emitFunctionEntryLabel() { const SystemZSubtarget &Subtarget = MF->getSubtarget(); Index: llvm/test/MC/GOFF/basic-goff-64.ll =================================================================== --- /dev/null +++ llvm/test/MC/GOFF/basic-goff-64.ll @@ -0,0 +1,242 @@ +; RUN: llc %s -mtriple s390x-ibm-zos -filetype=obj -o - | od -v -Ax -tx1 | FileCheck --ignore-case %s + +@x = global i32 0, align 4 +@y = internal global i32 1, align 4 +@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 Index: llvm/test/MC/GOFF/empty-goff.s =================================================================== --- llvm/test/MC/GOFF/empty-goff.s +++ llvm/test/MC/GOFF/empty-goff.s @@ -16,8 +16,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: 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