diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h --- a/llvm/include/llvm/BinaryFormat/GOFF.h +++ b/llvm/include/llvm/BinaryFormat/GOFF.h @@ -72,6 +72,14 @@ ESD_RQ_3 = 3 }; +enum ESDERSymbolType : uint8_t { + ESD_ES_None = 0, + ESD_ES_Section = 1, + ESD_ES_Label = 2, + ESD_ES_Class = 3, + ESD_ES_Part = 4 +}; + enum ESDAmode : uint8_t { ESD_AMODE_None = 0, ESD_AMODE_24 = 1, @@ -157,6 +165,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, diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h --- a/llvm/include/llvm/MC/MCAssembler.h +++ b/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,12 @@ FileNames.emplace_back(std::string(FileName), Symbols.size()); } + std::pair getCsectNames() { return CsectNames; } + + void setCsectNames(std::pair Names) { + CsectNames = Names; + } + /// Write the necessary bundle padding to \p OS. /// Expects a fragment \p F containing instructions and its size \p FSize. void writeFragmentPadding(raw_ostream &OS, const MCEncodedFragment &F, diff --git a/llvm/include/llvm/MC/MCGOFFObjectWriter.h b/llvm/include/llvm/MC/MCGOFFObjectWriter.h --- a/llvm/include/llvm/MC/MCGOFFObjectWriter.h +++ b/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; diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h --- a/llvm/include/llvm/MC/MCGOFFStreamer.h +++ b/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 {} diff --git a/llvm/include/llvm/MC/MCSymbolGOFF.h b/llvm/include/llvm/MC/MCSymbolGOFF.h --- a/llvm/include/llvm/MC/MCSymbolGOFF.h +++ b/llvm/include/llvm/MC/MCSymbolGOFF.h @@ -18,10 +18,50 @@ namespace llvm { class MCSymbolGOFF : public MCSymbol { + mutable 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) const { 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 diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp --- a/llvm/lib/MC/GOFFObjectWriter.cpp +++ b/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 *MC; + 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), + MC(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; + GOFFSymbol *Rptr; + GOFFSymbol *SD; + const MCSectionGOFF *MC; + bool IsStructured; + + GOFFSection(GOFFSymbol *Pptr, GOFFSymbol *Rptr, GOFFSymbol *SD, + const MCSectionGOFF *MC) + : Pptr(Pptr), Rptr(Rptr), SD(SD), MC(MC), IsStructured(false) {} + GOFFSection() + : Pptr(nullptr), Rptr(nullptr), SD(nullptr), MC(nullptr), + 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; + SmallVector SectionTextBuffer; + size_t SectionTextOffset = 0; // Logical offset of first byte of buffer + size_t SectionWrittenLength = 0; // Logical number of bytes written. + public: GOFFObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS) @@ -230,20 +337,347 @@ ~GOFFObjectWriter() override {} +private: // Write GOFF records. void writeHeader(); + + void writeSymbol(const GOFFSymbol &Symbol, const MCAsmLayout &Layout); + void writeText(const GOFFSection &Section, MCAssembler &Asm, + const MCAsmLayout &Layout); + void bufferText(const GOFFSection &Section, size_t SectionOffset, + const SmallVectorImpl &Data); + void flushText(const GOFFSection &Section, bool EndSection = false); + void writePhysicalText(const GOFFSection &Section, size_t SectionOffset, + const SmallVectorImpl &Data); + 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(MCAssembler &Asm, const MCSectionGOFF &Section, + const MCAsmLayout &Layout); + void processSymbolDefinedInModule(const MCSymbolGOFF &Symbol, + MCAssembler &Asm, + const MCAsmLayout &Layout); + void processSymbolDeclaredInModule(const MCSymbolGOFF &Symbol); + + uint32_t EsdCounter = 1; + + GOFFSymbol *RootSD = nullptr; + GOFFSymbol *CodeLD = nullptr; + GOFFSymbol *ADA = nullptr; + bool HasADA = false; }; } // 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) { + auto S = createGOFFSymbol(Name, GOFF::ESD_ST_PartReference, ParentEsdId); + return S; +} + +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 = 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; + 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(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 (Kind.isBSS() || Kind.isData()) { + // Statics and globals that are defined. + std::string SectionName = Section.getName().str(); + 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 &Symbol, + MCAssembler &Asm, + const MCAsmLayout &Layout) { + MCSection &Section = Symbol.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 = Symbol.getName(); + // If it's a text section, then create a label for it. + if (Kind.isText()) { + GOFFSymbol *LD = createLDSymbol(SymbolName, GSectionSym->EsdId); + LD->BindingStrength = Symbol.isWeak() + ? GOFF::ESDBindingStrength::ESD_BST_Weak + : GOFF::ESDBindingStrength::ESD_BST_Strong; + + // If we don't know if it is code or data, assume it is code. + LD->Executable = Symbol.getExecutable(); + if (LD->isExecUnspecified()) + LD->Executable = GOFF::ESD_EXE_CODE; + + // Determine the binding scope. Please note that the combination + // !isExternal && isExported makes no sense. + LD->BindingScope = Symbol.isExternal() + ? (Symbol.isExported() + ? GOFF::ESD_BSC_ImportExport + : (LD->isExecutable() ? GOFF::ESD_BSC_Library + : GOFF::ESD_BSC_Module)) + : GOFF::ESD_BSC_Section; + + if (ADA && ADA->SectionLength > 0) + LD->ADAEsdId = ADA->EsdId; + else + LD->ADAEsdId = 0; + + GSectionSym->setMaxAlignment(Symbol.getAlignment()); + + LD->MC = &Symbol; + SymbolMap[&Symbol] = LD; + } else if (Kind.isBSS() || Kind.isData()) { + GSectionSym = GSection->Rptr; + GSectionSym->BindingScope = + Symbol.isExternal() ? (Symbol.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(Symbol.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->MC = &Symbol; + GSection->SD->MC = &Symbol; + SymbolMap[&Symbol] = 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->MC = &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->MC = &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 +692,338 @@ 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; + + struct { + Flags Attr[10]; + void setAmode(GOFF::ESDAmode Amode) { Attr[0].set(0, 8, Amode); } + void setRmode(GOFF::ESDRmode Rmode) { Attr[1].set(0, 8, Rmode); } + void setTextStyle(GOFF::ESDTextStyle Style) { Attr[2].set(0, 4, Style); } + void setBindingAlgorithm(GOFF::ESDBindingAlgorithm Algorithm) { + Attr[2].set(4, 4, Algorithm); + } + void setTaskingBehavior(GOFF::ESDTaskingBehavior TaskingBehavior) { + Attr[3].set(0, 3, TaskingBehavior); + } + void setReadOnly(bool ReadOnly) { Attr[3].set(4, 1, ReadOnly); } + void setExecutable(GOFF::ESDExecutable Executable) { + Attr[3].set(5, 3, Executable); + } + void setDuplicateSeverity(GOFF::ESDDuplicateSymbolSeverity DSS) { + Attr[4].set(2, 2, DSS); + } + void setBindingStrength(GOFF::ESDBindingStrength Strength) { + Attr[4].set(4, 4, Strength); + } + void setLoadingBehavior(GOFF::ESDLoadingBehavior Behavior) { + Attr[5].set(0, 2, Behavior); + } + void setIndirectReference(bool Indirect) { + uint8_t Value = Indirect ? 1 : 0; + Attr[5].set(3, 1, Value); + } + void setBindingScope(GOFF::ESDBindingScope Scope) { + Attr[5].set(4, 4, Scope); + } + void setLinkageType(GOFF::ESDLinkageType Type) { Attr[6].set(2, 1, Type); } + void setAlignment(GOFF::ESDAlignment Alignment) { + Attr[6].set(3, 5, Alignment); + } + } BehavAttr; + + uint32_t AdaEsdId = 0; + uint32_t SortPriority = 0; + + switch (Symbol.SymbolType) { + case GOFF::ESD_ST_SectionDefinition: { + if (Symbol.isExecutable()) // Unspecified otherwise + BehavAttr.setTaskingBehavior(GOFF::ESD_TA_Rent); + if (Symbol.BindingScope == GOFF::ESD_BSC_Section) + BehavAttr.setBindingScope(Symbol.BindingScope); + } break; + case GOFF::ESD_ST_ElementDefinition: { + SymbolFlags.set(3, 1, Symbol.isRemovable()); // Removable + if (Symbol.isExecutable()) { + BehavAttr.setExecutable(GOFF::ESD_EXE_CODE); + BehavAttr.setReadOnly(true); + } else { + if (Symbol.isExecUnspecified()) + BehavAttr.setExecutable(GOFF::ESD_EXE_Unspecified); + else + BehavAttr.setExecutable(GOFF::ESD_EXE_DATA); + + if (Symbol.isForceRent() || Symbol.isReadOnly()) // TODO + BehavAttr.setReadOnly(true); + } + Offset = 0; // TODO ED and SD are 1-1 for now + BehavAttr.setAlignment(Symbol.Alignment); + SymbolFlags.set(0, 1, 1); // Fill-Byte Value Presence Flag + FillByteValue = 0; + SymbolFlags.set(1, 1, 0); // Mangled Flag TODO ? + BehavAttr.setAmode(Symbol.Amode); + BehavAttr.setRmode(Symbol.Rmode); + BehavAttr.setTextStyle(Symbol.TextStyle); + BehavAttr.setBindingAlgorithm(Symbol.BindAlgorithm); + BehavAttr.setLoadingBehavior(Symbol.LoadBehavior); + SymbolFlags.set(5, 3, GOFF::ESD_RQ_0); // Reserved Qwords + if (Symbol.isForceRent()) + BehavAttr.setReadOnly(true); + NameSpaceId = Symbol.NameSpace; + Length = Symbol.SectionLength; + break; + } + case GOFF::ESD_ST_LabelDefinition: { + if (Symbol.isExecutable()) + BehavAttr.setExecutable(GOFF::ESD_EXE_CODE); + else + BehavAttr.setExecutable(GOFF::ESD_EXE_DATA); + BehavAttr.setBindingStrength(Symbol.BindingStrength); + BehavAttr.setLinkageType(Symbol.Linkage); + SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable; + BehavAttr.setAmode(Symbol.Amode); + NameSpaceId = Symbol.NameSpace; + BehavAttr.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 *MC = Symbol.MC) { + uint64_t Ofs = Layout.getSymbolOffset(*MC); + // 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: { + if (Symbol.isExecutable()) + BehavAttr.setExecutable(GOFF::ESD_EXE_CODE); + else + BehavAttr.setExecutable(GOFF::ESD_EXE_DATA); + BehavAttr.setBindingStrength(Symbol.BindingStrength); + BehavAttr.setLinkageType(Symbol.Linkage); + SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable; + BehavAttr.setIndirectReference(Symbol.Indirect); + Offset = 0; // ERs don't do offsets + NameSpaceId = Symbol.NameSpace; + SymbolFlags.set(5, 3, GOFF::ESD_ES_None); // TODO What is this for..? + BehavAttr.setBindingScope(Symbol.BindingScope); + BehavAttr.setAmode(Symbol.Amode); + break; + } + case GOFF::ESD_ST_PartReference: { + if (Symbol.isExecutable()) + BehavAttr.setExecutable(GOFF::ESD_EXE_CODE); + else + BehavAttr.setExecutable(GOFF::ESD_EXE_DATA); + NameSpaceId = Symbol.NameSpace; + BehavAttr.setAlignment(Symbol.Alignment); + BehavAttr.setAmode(Symbol.Amode); + BehavAttr.setLinkageType(Symbol.Linkage); + BehavAttr.setBindingScope(Symbol.BindingScope); + SymbolFlags.set(2, 1, Symbol.Renamable); // Renamable; + if (Symbol.isWeakRef()) + BehavAttr.setDuplicateSeverity(GOFF::ESD_DSS_NoWarning); + else + BehavAttr.setDuplicateSeverity(GOFF::ESD_DSS_Warning); + BehavAttr.setIndirectReference(Symbol.Indirect); + if (Symbol.ReadOnly) + BehavAttr.setReadOnly(true); + SortPriority = Symbol.SortKey; + + Length = Symbol.SectionLength; + break; + } + } // End switch + + StringRef Name; + SmallString<256> Res; + ConverterEBCDIC::convertToEBCDIC(Symbol.Name, Res); + 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 : BehavAttr.Attr) + OS.writeBE(F); // Behavioral Attributes + OS.writeBE(NameLength); // Name Length + OS.write(Name.data(), NameLength); // Name +} + +void GOFFObjectWriter::writeText(const GOFFSection &Section, MCAssembler &Asm, + const MCAsmLayout &Layout) { + auto *MC = Section.MC; + assert(MC && "No section associated with GOFF section"); + + for (auto &Fragment : *MC) { + LLVM_DEBUG(dbgs() << "Frag Kind: " + << static_cast(Fragment.getKind()) << '\n'); + switch (Fragment.getKind()) { + case MCFragment::FT_Data: { + const auto &DataFrag = static_cast(Fragment); + const SmallVectorImpl &Data = DataFrag.getContents(); + size_t SectionOffset = Layout.getFragmentOffset(&Fragment); + bufferText(Section, SectionOffset, Data); + break; + } + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment &OF = + cast(Fragment); + const SmallVectorImpl &Data = OF.getContents(); + size_t SectionOffset = Layout.getFragmentOffset(&Fragment); + bufferText(Section, SectionOffset, Data); + break; + } + case MCFragment::FT_Align: { + unsigned Size = Asm.computeFragmentSize(Layout, Fragment); + if (Size) { + size_t SectionOffset = Layout.getFragmentOffset(&Fragment); + SmallVector Data; + for (unsigned I = 0; I < Size; ++I) { + Data.append(1, '\0'); + } + bufferText(Section, SectionOffset, Data); + } + break; + } + case MCFragment::FT_Fill: { + const MCFillFragment &FF = cast(Fragment); + unsigned Size = Asm.computeFragmentSize(Layout, FF); + if (Size == 0) + break; + uint64_t V = FF.getValue(); + if (V == 0 && Size > 256) { + // Rely on ESD fill byte to zero out largish fill + flushText(Section); + SectionWrittenLength += Size; + break; + } + unsigned VSize = FF.getValueSize(); + unsigned NumValues = Size / VSize; + size_t SectionOffset = Layout.getFragmentOffset(&Fragment); + SmallVector Data; + unsigned MaxChunkSize = Data.capacity(); + for (unsigned I = 0; NumValues > 0; --NumValues) { + for (signed J = VSize - 1; J >= 0; --J) { + uint8_t B = uint8_t(V >> (J * 8)); + Data.append(1, B); + I++; + if (I == MaxChunkSize) { + bufferText(Section, SectionOffset, Data); + SectionOffset += MaxChunkSize; + Data.clear(); + I = 0; + } + } + } + bufferText(Section, SectionOffset, Data); + break; + } + case MCFragment::FT_LEB: { + const auto &DataFrag = static_cast(Fragment); + const SmallVectorImpl &Data = DataFrag.getContents(); + size_t SectionOffset = Layout.getFragmentOffset(&Fragment); + bufferText(Section, SectionOffset, Data); + break; + } + default: + llvm_unreachable("Unhandled fragment type"); + } + } + + flushText(Section, true /* EndSection */); +} + +void GOFFObjectWriter::bufferText(const GOFFSection &Section, + size_t SectionOffset, + const SmallVectorImpl &Data) { + assert(SectionOffset == (SectionWrittenLength + SectionTextBuffer.size())); + unsigned DataLength = Data.size(); + size_t MaxAppend = SectionTextBuffer.capacity() - SectionTextBuffer.size(); + if (DataLength > MaxAppend) { + if (SectionTextBuffer.size()) + flushText(Section); + if (DataLength >= SectionTextBuffer.capacity()) + writePhysicalText(Section, SectionOffset, Data); + else + bufferText(Section, SectionOffset, Data); + } else { + if (!SectionTextBuffer.size()) + SectionTextOffset = SectionOffset; + SectionTextBuffer.append(Data); + } +} + +void GOFFObjectWriter::flushText(const GOFFSection &Section, bool EndSection) { + if (SectionTextBuffer.size()) + writePhysicalText(Section, SectionTextOffset, SectionTextBuffer); + SectionTextOffset = 0; + SectionTextBuffer.clear(); + if (EndSection) + SectionWrittenLength = 0; +} + +void GOFFObjectWriter::writePhysicalText(const GOFFSection &Section, + size_t SectionOffset, + const SmallVectorImpl &Data) { + GOFF::TXTRecordStyle RecordStyle = + Section.IsStructured ? GOFF::TXT_RS_Structured : GOFF::TXT_RS_Byte; + const size_t DataLength = Data.size(); + size_t WrittenLength = 0; + + // Only have signed 32bits of offset + assert(SectionOffset + DataLength < (uint64_t)(1 << 31) && + "TXT offset out of range."); + + while (WrittenLength < DataLength) { + size_t ToWriteLength = std::min(DataLength - WrittenLength, + static_cast(GOFF::MaxDataLength)); + size_t Offset = SectionOffset + WrittenLength; + + OS.newRecord(GOFF::RT_TXT, 21 + ToWriteLength); + OS.writeBE(Flags(4, 4, RecordStyle)); // Text Record Style + // TODO: This assumes the ED. Is that correct? Probably not. + OS.writeBE(Section.Pptr->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(Data.data() + WrittenLength, ToWriteLength); // Data + + WrittenLength += ToWriteLength; + } + + SectionWrittenLength += WrittenLength; +} + void GOFFObjectWriter::writeEnd() { uint8_t F = GOFF::END_EPR_None; uint8_t AMODE = 0; @@ -282,10 +1048,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; } diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp --- a/llvm/lib/MC/MCGOFFStreamer.cpp +++ b/llvm/lib/MC/MCGOFFStreamer.cpp @@ -12,10 +12,16 @@ #include "llvm/MC/MCGOFFStreamer.h" #include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionGOFF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolGOFF.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Casting.h" using namespace llvm; @@ -32,3 +38,47 @@ 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; +} diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -69,6 +69,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); diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -17,6 +17,7 @@ #include "SystemZMCInstLower.h" #include "TargetInfo/SystemZTargetInfo.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" @@ -24,6 +25,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" using namespace llvm; @@ -1101,6 +1103,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(); diff --git a/llvm/test/MC/GOFF/basic-goff-64.ll b/llvm/test/MC/GOFF/basic-goff-64.ll new file mode 100644 --- /dev/null +++ b/llvm/test/MC/GOFF/basic-goff-64.ll @@ -0,0 +1,214 @@ +; RUN: llc %s -mtriple s390x-ibm-zos -filetype=obj -o - | od -v -An -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: 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +; 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: 03 01 00 00 00 00 00 01 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 +; CHECK: 00 01 00 00 00 00 00 0f 82 81 a2 89 83 60 87 96 +; CHECK: 03 02 00 86 86 60 f6 f4 7b c3 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 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: 03 00 00 01 00 00 00 02 00 00 00 01 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01 +; CHECK: 00 40 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). +; CHECK: 03 01 00 03 00 00 00 03 00 00 00 02 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01 +; CHECK: 10 01 24 00 00 00 00 0f 82 81 a2 89 83 60 87 96 +; CHECK: 03 02 00 86 86 60 f6 f4 7b e2 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +; Record for C_CODE64. +; Byte 3 is 0x01 to indicate SD (Element Definition). +; CHECK: 03 00 00 01 00 00 00 04 00 00 00 01 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 26 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 01 80 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 00 0a +; CHECK: 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: 03 01 00 02 00 00 00 05 00 00 00 04 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 +; CHECK: 00 01 20 00 00 00 00 0f 82 81 a2 89 83 60 87 96 +; CHECK: 03 02 00 86 86 60 f6 f4 7b c3 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 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: 03 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 01 a7 00 00 00 00 00 00 00 + +; Record for C_WSA64 belonging to Section for global variable x. +; Byte 3 is 0x01 to indicate ED. +; Bytes 8-11 indicate that Parent ESDID is 6. +; CHECK: 03 00 00 01 00 00 00 07 00 00 00 06 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01 +; CHECK: 00 40 04 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + +; Record for PR of global variable x. +; Byte 3 is 0x03 to indicate PR. +; Bytes 8-11 indicate that Parent ESDID is 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. +; CHECK: 03 00 00 03 00 00 00 08 00 00 00 07 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01 +; CHECK: 10 04 20 00 00 00 00 01 a7 00 00 00 00 00 00 00 + +; 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: 03 00 00 02 00 00 00 09 00 00 00 04 00 00 00 00 +; CHECK: 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 +; CHECK: 00 03 20 00 00 00 00 03 86 96 96 00 00 00 00 00 + +; Record for internal global variable y. This global variable +; is explicitly listed as internal to this compilation unit. +; It has the same ownership as the above record, however its binding +; scope is Section Scope. This means that this variable is only +; visible to functions in the same section (ie. not visible to any +; function in any other compilation unit). +; Byte 65 is 0x01 = 0b00000001. Bits 4-7 indicate the +; binding scope, which is section scope. +; CHECK: 03 00 00 02 00 00 00 0a 00 00 00 04 00 00 00 00 +; CHECK: 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01 +; CHECK: 00 01 20 00 00 00 00 01 a8 00 00 00 00 00 00 00 + +; Record for C_WSA64. Part of section basic-goff-64#C +; and contains externally defined global variables. +; CHECK: 03 00 00 01 00 00 00 0b 00 00 00 01 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 03 80 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 04 01 01 +; CHECK: 00 40 00 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + +; Record for external global variable z. This is NOT +; initialized in this compilation unit and so unlike +; global variable x, it lacks its own section definition. +; Byte 3 is 0x03 to indicate PR. +; Bytes 8-11 indicate that parent ESDID is 0b, which is +; above C_WSA64. +; CHECK: 03 00 00 03 00 00 00 0c 00 00 00 0b 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01 +; CHECK: 10 04 20 00 00 00 00 01 a9 00 00 00 00 00 00 00 + +; Record for externally defined function bar(). +; Byte 3 is 0x04 to indicate External Reference (ErWx). +; Bytes 8-11 indicate that parent ESDID is 01, the section +; definition for this module. (basic-goff-64#C). +; Byte 64 indicates that the binding scope is Import-Export +; Scope, since the definition may be something we dynamically +; link against. +; CHECK: 03 00 00 04 00 00 00 0d 00 00 00 01 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 01 +; CHECK: 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 2 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: 03 10 00 00 00 00 00 04 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 26 + +; 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: 03 10 00 00 00 00 00 08 00 00 00 00 00 00 00 00 +; CHECK: 00 00 00 00 00 00 00 04