diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/GOFF.h @@ -0,0 +1,241 @@ +//===-- llvm/BinaryFormat/GOFF.h - GOFF definitions ---------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains common, non-processor-specific data structures and +// constants for the GOFF file format. +// +// The details of the GOFF32 bits in this file are largely based on the Tool +// Interface Standard (TIS) Executable and Linking Format (GOFF) Specification +// Version 1.2, May 1995. The GOFF64 specifics are based on GOFF-64 Object File +// Format +// Version 1.5, Draft 2, May 1998 as well as OpenBSD header files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BINARYFORMAT_GOFF_H +#define LLVM_BINARYFORMAT_GOFF_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { + +namespace GOFF { + +constexpr uint8_t RecordLength = 80; + +/// \brief Maximum data length before starting a new card for RLD and TXT data. +/// +/// The maximum number of bytes that can be included in an RLD or TXT record and +/// their continuations is a SIGNED 16 bit int despite what the spec says. The +/// number of bytes we allow ourselves to attach to a card is thus arbitrarily +/// limited to 16K bytes. +const uint16_t MaxDataLength = 16 * 1024; + +// Prefix byte on every record. This indicates GOFF format. +enum { PTVPrefix = 0x03 }; + +enum RecordType { + RT_ESD = 0, + RT_TXT = 1, + RT_RLD = 2, + RT_LEN = 3, + RT_END = 4, + RT_HDR = 15, +}; + +enum ESDSymbolType { + ESD_ST_SectionDefinition = 0, + ESD_ST_ElementDefinition = 1, + ESD_ST_LabelDefinition = 2, + ESD_ST_PartReference = 3, + ESD_ST_ExternalReference = 4, +}; + +enum ESDNameSpaceId { + ESD_NS_ProgramManagementBinder = 0, + ESD_NS_NormalName = 1, + ESD_NS_PseudoRegister = 2, + ESD_NS_Parts = 3 +}; + +enum ESDReserveQwords { + ESD_RQ_0 = 0, + ESD_RQ_1 = 1, + ESD_RQ_2 = 2, + ESD_RQ_3 = 3 +}; + +enum ESDERSymbolType { + ESD_ES_None = 0, + ESD_ES_Section = 1, + ESD_ES_Label = 2, + ESD_ES_Class = 3, + ESD_ES_Part = 4 +}; + +enum ESDAmode { + ESD_AMODE_None = 0, + ESD_AMODE_24 = 1, + ESD_AMODE_31 = 2, + ESD_AMODE_ANY = 3, + ESD_AMODE_64 = 4, + ESD_AMODE_MIN = 16, +}; + +enum ESDRmode { + ESD_RMODE_None = 0, + ESD_RMODE_24 = 1, + ESD_RMODE_31 = 3, + ESD_RMODE_64 = 4, +}; + +enum ESDTextStyle { + ESD_TS_ByteOriented = 0, + ESD_TS_Structured = 1, + ESD_TS_Unstructured = 2, +}; + +enum ESDBindingAlgorithm { + ESD_BA_Concatenate = 0, + ESD_BA_Merge = 1, +}; + +enum ESDTaskingBehavior { + ESD_TA_Unspecified = 0, + ESD_TA_NonReus = 1, + ESD_TA_Reus = 2, + ESD_TA_Rent = 3, +}; + +enum ESDExecutable { + ESD_EXE_Unspecified = 0, + ESD_EXE_DATA = 1, + ESD_EXE_CODE = 2, +}; + +enum ESDDuplicateSymbolSeverity { + ESD_DSS_NoWarning = 0, + ESD_DSS_Warning = 1, + ESD_DSS_Error = 2, + ESD_DSS_Reserved = 3, +}; + +enum ESDBindingStrength { + ESD_BST_Strong = 0, + ESD_BST_Weak = 1, +}; + +enum ESDLoadingBehavior { + ESD_LB_Initial = 0, + ESD_LB_Deferred = 1, + ESD_LB_NoLoad = 2, + ESD_LB_Reserved = 3, +}; + +enum ESDBindingScope { + ESD_BSC_Unspecified = 0, + ESD_BSC_Section = 1, + ESD_BSC_Module = 2, + ESD_BSC_Library = 3, + ESD_BSC_ImportExport = 4, +}; + +enum ESDLinkageType { ESD_LT_OS = 0, ESD_LT_XPLink = 1 }; + +enum ESDAlignment { + ESD_ALIGN_Byte = 0, + ESD_ALIGN_Halfword = 1, + ESD_ALIGN_Fullword = 2, + ESD_ALIGN_Doubleword = 3, + ESD_ALIGN_Quadword = 4, + ESD_ALIGN_32byte = 5, + ESD_ALIGN_64byte = 6, + ESD_ALIGN_128byte = 7, + ESD_ALIGN_256byte = 8, + ESD_ALIGN_512byte = 9, + ESD_ALIGN_1024byte = 10, + ESD_ALIGN_2Kpage = 11, + ESD_ALIGN_4Kpage = 12, +}; + +enum TXTRecordStyle { + TXT_RS_Byte = 0, + TXT_RS_Structured = 1, + TXT_RS_Unstructured = 2, +}; + +// RLDRelocationType is internal use only and these values not put +// in GOFF format +enum RLDRelocationType { + Reloc_Type_Adcon = 0, + Reloc_Type_Vcon = 1, + Reloc_Type_Qcon = 2, + Reloc_Type_Len = 3, + Reloc_Type_Ada = 4, + Reloc_Type_Rel_Imm = 5, + Reloc_Type_Rel = 6, + Reloc_Type_Long_Disp = 7, + Reloc_Type_Cond_Vcon = 8 +}; + +enum RLDReferenceType { + RLD_RT_RAddress = 0, + RLD_RT_ROffset = 1, + RLD_RT_RLength = 2, + RLD_RT_RRelativeImmediate = 6, + RLD_RT_RTypeConstant = 7, + RLD_RT_RLongDisplacement = 9, +}; + +enum RLDReferentType { + RLD_RO_Label = 0, + RLD_RO_Element = 1, + RLD_RO_Class = 2, + RLD_RO_Part = 3, +}; + +enum RLDAction { + RLD_ACT_Multiply = 4, + RLD_ACT_Div4Quotient = 6, + RLD_ACT_Div4Remainder = 7, + RLD_ACT_And = 8, + RLD_ACT_Or = 9, + RLD_ACT_Xor = 10, + RLD_ACT_Move = 16 +}; + +enum RLDFetchStore { RLD_FS_Fetch = 0, RLD_FS_Store = 1 }; + +enum ENDEntryPointRequest { + END_EPR_None = 0, + END_EPR_EsdidOffset = 1, + END_EPR_ExternalName = 2, + END_EPR_Reserved = 3, +}; + +// \brief Represent the different types of objects that can be referenced from +// the associated data area (ADA) of a compilation unit. +enum ADASlotKind { +#define ADASLOT(SLOT, MO, V) SLOT = V, +#include "llvm/BinaryFormat/GOFFAda.def" +}; + +// \brief Subsections of the primary C_CODE section in the object file. +enum SubsectionKind { + SK_ReadOnly = 1, + SK_PPA1 = 2, + SK_JumpTable = 3, + SK_PPA2 = 4, +}; + +} // end namespace GOFF + +} // end namespace llvm + +#endif // LLVM_BINARYFORMAT_GOFF_H diff --git a/llvm/include/llvm/BinaryFormat/GOFFAda.def b/llvm/include/llvm/BinaryFormat/GOFFAda.def new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/GOFFAda.def @@ -0,0 +1,40 @@ +//===-- GOFFAda.def ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file centralizes the ADA definitions used by GOFF and XPLINK. +// +//===----------------------------------------------------------------------===// + +#ifndef ADASLOT +#define ADASLOT(SLOT, MO, V) +#endif + +/// ADASLOT(SLOT, MO, V) +/// +/// \param SLOT - ADA slot kind in file +/// \param MO - Corresponding machine operand kind +/// \param V - Enumeration value + +// The address of a non-function (data) symbol. +ADASLOT(ADA_DataSymbolAddr, MO_ADA_DATA_SYMBOL_ADDR, 1) +// The address of a function descriptor. +ADASLOT(ADA_IndirectFuncDesc, MO_ADA_INDIRECT_FUNC_DESC, 2) +// A function descriptor. Contains the address of the ADA for a function and +// the address of the function. +ADASLOT(ADA_DirectFuncDesc, MO_ADA_DIRECT_FUNC_DESC, 3) +// The address of the ADA for a function. Part of a function descriptor. +ADASLOT(ADA_DirectFuncDescADA, MO_ADA_DIRECT_FUNC_DESC_ADA, 4) +// The address of a function. Part of a function descriptor. +ADASLOT(ADA_DirectFuncDescAddr, MO_ADA_DIRECT_FUNC_DESC_EPA, 5) +// The address of a data symbol's handle, that is, the address of the symbol +// referenced. This is how external data is referenced. +ADASLOT(ADA_DataSymbolHandle, MO_ADA_DATA_SYMBOL_ADDR_VIA_HANDLE, 6) +// Access ADA entry containing pointer to internal data symbol. +ADASLOT(ADA_InternalDataSymbolAddr, MO_ADA_INTERNAL_DATA_SYMBOL_ADDR, 7) + +#undef ADASLOT diff --git a/llvm/include/llvm/BinaryFormat/Magic.h b/llvm/include/llvm/BinaryFormat/Magic.h --- a/llvm/include/llvm/BinaryFormat/Magic.h +++ b/llvm/include/llvm/BinaryFormat/Magic.h @@ -49,6 +49,7 @@ xcoff_object_64, ///< 64-bit XCOFF object file wasm_object, ///< WebAssembly Object file pdb, ///< Windows PDB debug info file + goff_object, ///< GOFF object file tapi_file, ///< Text-based Dynamic Library Stub file }; diff --git a/llvm/include/llvm/Object/Binary.h b/llvm/include/llvm/Object/Binary.h --- a/llvm/include/llvm/Object/Binary.h +++ b/llvm/include/llvm/Object/Binary.h @@ -67,6 +67,7 @@ ID_MachO64L, // MachO 64-bit, little endian ID_MachO64B, // MachO 64-bit, big endian + ID_GOFF, ID_Wasm, ID_EndObjects @@ -139,6 +140,8 @@ return TypeID == ID_IR; } + bool isGOFF() const { return TypeID == ID_GOFF; } + bool isMinidump() const { return TypeID == ID_Minidump; } bool isTapiFile() const { return TypeID == ID_TapiFile; } @@ -157,6 +160,8 @@ return Triple::MachO; if (isELF()) return Triple::ELF; + if (isGOFF()) + return Triple::GOFF; return Triple::UnknownObjectFormat; } diff --git a/llvm/include/llvm/Object/GOFF.h b/llvm/include/llvm/Object/GOFF.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Object/GOFF.h @@ -0,0 +1,566 @@ +//===- GOFF.h - GOFF object file implementation -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the GOFFObjectFile class. +// Record classes and derivatives are also declared and implemented. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_GOFF_H +#define LLVM_OBJECT_GOFF_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +struct GOFFRelocationEntry { + const uint32_t REsdId; + const uint32_t PEsdId; + const uint64_t POffset; + + const GOFF::RLDReferenceType ReferenceType; + const GOFF::RLDReferentType ReferentType; + const GOFF::RLDAction Action; + const bool NoFetchTarget; + const uint32_t TargetLength; + + GOFFRelocationEntry(uint32_t REsdId_, uint32_t PEsdId_, uint64_t POffset_, + GOFF::RLDReferenceType ReferenceType_, + GOFF::RLDReferentType ReferentType_, + GOFF::RLDAction Action_, bool NoFetchTarget_, + uint32_t TargetLength_) + : REsdId(REsdId_), PEsdId(PEsdId_), POffset(POffset_), + ReferenceType(ReferenceType_), ReferentType(ReferentType_), + Action(Action_), NoFetchTarget(NoFetchTarget_), + TargetLength(TargetLength_) {} +}; + +namespace object { + +/// \brief Represents a GOFF physical record. +/// +/// Specifies protected member functions to manipulate the record. These should +/// be called from deriving classes to change values as that record specifies. +class Record { + SmallVector Bytes; + +public: + Record() : Bytes(GOFF::RecordLength, (char)0x00) { + set8(0, GOFF::PTVPrefix); + }; + + // Set PTV fields common to all records + void setRecordType(GOFF::RecordType RecordType) { + setBits(1, 0, 4, RecordType); + } + + void setContinuation(bool Continuation) { + uint8_t Value = Continuation ? 1 : 0; + setBits(1, 6, 1, Value); + } + + void setContinued(bool Continued) { + uint8_t Value = Continued ? 1 : 0; + setBits(1, 7, 1, Value); + } + + const SmallVectorImpl &getBytes() const { return Bytes; } + +protected: + /// \brief Set bit field of specified byte. + /// + /// Used to pack bit fields into one byte. Fields are packed LEFT TO RIGHT. + /// Bit index zero is the MOST SIGNIFICANT BIT of the byte. + /// + /// \param ByteIndex index of byte the field is in + /// \param BitIndex index of first bit of field + /// \param Length length of bit field + /// \param Value new value of bit field + void setBits(uint8_t ByteIndex, uint8_t BitIndex, uint8_t Length, + uint8_t Value) { + assert(ByteIndex < GOFF::RecordLength && "Byte index out of bounds!"); + assert(BitIndex < 8 && "Bit index out of bounds!"); + assert(Length + BitIndex <= 8 && "Bit length too long!"); + + uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length); + Value = Value << (8 - BitIndex - Length); + assert((Value & Mask) == Value && "Bits set outside of range!"); + + Bytes[ByteIndex] &= ~Mask; // Clear bits to set + Bytes[ByteIndex] |= Value; + } + + /// \brief Set byte of record + void set8(uint8_t ByteIndex, uint8_t Value) { + assert(ByteIndex < GOFF::RecordLength && "Byte index out of bounds!"); + Bytes[ByteIndex] = static_cast(Value); + } + + /// \brief Set two bytes of record, accounting for endianness + void set16(uint8_t ByteIndex, uint16_t Value) { + assert(ByteIndex + 1 < GOFF::RecordLength && "Byte index out of bounds!"); + + for (int I = 0; I < 2; ++I) { + uint16_t Temp = (Value >> (8 * I)) & 0xFF; + Bytes[ByteIndex + 1 - I] = static_cast(Temp); + } + } + + /// \brief Set four bytes of record, accounting for endianness + void set32(uint8_t ByteIndex, uint32_t Value) { + assert(ByteIndex + 3 < GOFF::RecordLength && "Byte index out of bounds!"); + + for (int I = 0; I < 4; ++I) { + uint32_t Temp = (Value >> (8 * I)) & 0xFF; + Bytes[ByteIndex + 3 - I] = static_cast(Temp); + } + } + + // Get routine + static void getBits(const uint8_t *Bytes, uint8_t ByteIndex, uint8_t BitIndex, + uint8_t Length, uint8_t &Value) { + assert(ByteIndex < GOFF::RecordLength && "Byte index out of bounds!"); + assert(BitIndex < 8 && "Bit index out of bounds!"); + assert(Length + BitIndex <= 8 && "Bit length too long!"); + + uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length); + Value = Bytes[ByteIndex] & Mask; + Value = Value >> (8 - BitIndex - Length); + } + + static void get8(const uint8_t *Bytes, uint8_t ByteIndex, uint8_t &Value) { + assert(ByteIndex < GOFF::RecordLength && "Byte index out of bounds!"); + Value = Bytes[ByteIndex]; + } + + static void get16(const uint8_t *Bytes, uint8_t ByteIndex, uint16_t &Value) { + assert(ByteIndex + 1 < GOFF::RecordLength && "Byte index out of bounds!"); + + Value = *reinterpret_cast(&Bytes[ByteIndex]); + } + + static void get32(const uint8_t *Bytes, uint8_t ByteIndex, uint32_t &Value) { + assert(ByteIndex + 3 < GOFF::RecordLength && "Byte index out of bounds!"); + + Value = *reinterpret_cast(&Bytes[ByteIndex]); + } +}; + +class HDRRecord : public Record { +public: + HDRRecord() : Record() { + setRecordType(GOFF::RT_HDR); + setArchitectureLevel(1); + } + + void setArchitectureLevel(uint32_t Level) { set32(48, Level); } +}; + +class TXTRecord : public Record { +public: + /// \brief Maximum length of data; any more must go in continuation. + static const uint8_t TXTMaxDataLength = 56; + +public: + TXTRecord() : Record() { setRecordType(GOFF::RT_TXT); } + + void setRecordStyle(GOFF::TXTRecordStyle Style) { setBits(3, 4, 4, Style); } + + void setElementEsdId(uint32_t EsdId) { set32(4, EsdId); } + + void setOffset(uint32_t Offset) { set32(12, Offset); } + + void setDataLength(uint16_t Length) { set16(22, Length); } + + void setData(const SmallVectorImpl::const_iterator &Data, + uint8_t Length) { + assert(Length <= TXTMaxDataLength && "Data too long for TXT Record"); + + for (int I = 0; I < Length; ++I) + set8(24 + I, Data[I]); + } + + // Get routines + static void getElementEsdId(const uint8_t *Record, uint32_t &EsdId) { + get32(Record, 4, EsdId); + } + + static void getOffset(const uint8_t *Record, uint32_t &Offset) { + get32(Record, 12, Offset); + } + + static void getDataLength(const uint8_t *Record, uint16_t &Length) { + get16(Record, 22, Length); + } +}; + +class ESDRecord : public Record { +public: + /// \brief Number of bytes for name; any more must go in continuation. + /// This is the number of bytes that can fit into the data field of an ESD + /// record. + static const uint8_t ESDMaxNameLength = 8; + + /// \brief Maximum name length for ESD records and continuations. + /// This is the number of bytes that can fit into the data field of an ESD + /// record AND following continuations. This is limited fundamentally by the + /// 16 bit SIGNED length field. + static const uint16_t MaxNameLength = 32 * 1024; + +public: + ESDRecord() : Record() { setRecordType(GOFF::RT_ESD); } + + void setSymbolType(GOFF::ESDSymbolType SymbolType) { set8(3, SymbolType); } + + void setEsdId(uint32_t EsdId) { set32(4, EsdId); } + + void setParentEsdId(uint32_t EsdId) { set32(8, EsdId); } + + void setOffset(uint32_t Offset) { set32(16, Offset); } + + void setLength(uint32_t Length) { set32(24, Length); } + + void setNameSpaceId(GOFF::ESDNameSpaceId Id) { set8(40, Id); } + + void setFillBytePresent(bool Present) { setBits(41, 0, 1, Present); } + + void setNameMangled(bool Mangled) { setBits(41, 1, 1, Mangled); } + + void setRenamable(bool Renamable) { setBits(41, 2, 1, Renamable); } + + void setRemovable(bool Removable) { setBits(41, 3, 1, Removable); } + + void setReserveQwords(GOFF::ESDReserveQwords Reserve) { + setBits(41, 5, 3, Reserve); + } + + // This intentionally uses the same field as above + void setERSymbolType(GOFF::ESDERSymbolType Type) { setBits(41, 5, 3, Type); } + + void setFillByteValue(uint8_t Fill) { set8(42, Fill); } + + void setAdaEsdId(uint32_t EsdId) { set32(44, EsdId); } + + void setSortPriority(uint32_t Priority) { set32(48, Priority); } + + void setAmode(GOFF::ESDAmode Amode) { set8(60, Amode); } + + void setRmode(GOFF::ESDRmode Rmode) { set8(61, Rmode); } + + void setTextStyle(GOFF::ESDTextStyle Style) { setBits(62, 0, 4, Style); } + + void setBindingAlgorithm(GOFF::ESDBindingAlgorithm Algorithm) { + setBits(62, 4, 4, Algorithm); + } + + void setTaskingBehavior(GOFF::ESDTaskingBehavior TaskingBehavior) { + setBits(63, 0, 3, TaskingBehavior); + } + + void setReadOnly(bool ReadOnly) { + uint8_t Value = ReadOnly ? 1 : 0; + setBits(63, 4, 1, Value); + } + + void setExecutable(GOFF::ESDExecutable Executable) { + setBits(63, 5, 3, Executable); + } + + void setDuplicateSeverity(GOFF::ESDDuplicateSymbolSeverity DSS) { + setBits(64, 2, 2, DSS); + } + + void setBindingStrength(GOFF::ESDBindingStrength Strength) { + setBits(64, 4, 4, Strength); + } + + void setLoadingBehavior(GOFF::ESDLoadingBehavior Behavior) { + setBits(65, 0, 2, Behavior); + } + + void setIndirectReference(bool Indirect) { + uint8_t Value = Indirect ? 1 : 0; + setBits(65, 3, 1, Value); + } + + void setBindingScope(GOFF::ESDBindingScope Scope) { + setBits(65, 4, 4, Scope); + } + + void setLinkageType(GOFF::ESDLinkageType Type) { setBits(66, 2, 1, Type); } + + void setAlignment(GOFF::ESDAlignment Alignment) { + setBits(66, 3, 5, Alignment); + } + + void setNameLength(uint16_t Length) { set16(70, Length); } + + void setName(const StringRef::const_iterator &Data, uint8_t Length) { + assert(Length <= ESDMaxNameLength && "Data too long for ESD Record"); + + for (int I = 0; I < Length; ++I) + set8(72 + I, Data[I]); + } + + // ESD Get routines + static void getSymbolType(const uint8_t *Record, + GOFF::ESDSymbolType &SymbolType) { + uint8_t Value; + get8(Record, 3, Value); + SymbolType = (GOFF::ESDSymbolType)Value; + } + + static void getEsdId(const uint8_t *Record, uint32_t &EsdId) { + get32(Record, 4, EsdId); + } + + static void getParentEsdId(const uint8_t *Record, uint32_t &EsdId) { + get32(Record, 8, EsdId); + } + + static void getOffset(const uint8_t *Record, uint32_t &Offset) { + get32(Record, 16, Offset); + } + + static void getLength(const uint8_t *Record, uint32_t &Length) { + get32(Record, 24, Length); + } + + static void getNameSpaceId(const uint8_t *Record, GOFF::ESDNameSpaceId &Id) { + uint8_t Value; + get8(Record, 40, Value); + Id = (GOFF::ESDNameSpaceId)Value; + } + + static void getFillBytePresent(const uint8_t *Record, bool &Present) { + uint8_t Value; + getBits(Record, 41, 0, 1, Value); + Present = (bool)Value; + } + + static void getNameMangled(const uint8_t *Record, bool &Mangled) { + uint8_t Value; + getBits(Record, 41, 1, 1, Value); + Mangled = (bool)Value; + } + + static void getRenamable(const uint8_t *Record, bool &Renamable) { + uint8_t Value; + getBits(Record, 41, 2, 1, Value); + Renamable = (bool)Value; + } + + static void getRemovable(const uint8_t *Record, bool &Removable) { + uint8_t Value; + getBits(Record, 41, 3, 1, Value); + Removable = (bool)Value; + } + + // This intentionally uses the same field as above + static void getERSymbolType(const uint8_t *Record, + GOFF::ESDERSymbolType &Type) { + uint8_t Value; + getBits(Record, 41, 5, 3, Value); + Type = (GOFF::ESDERSymbolType)Value; + } + + static void getFillByteValue(const uint8_t *Record, uint8_t &Fill) { + get8(Record, 42, Fill); + } + + static void getAdaEsdId(const uint8_t *Record, uint32_t &EsdId) { + get32(Record, 44, EsdId); + } + + static void getSortPriority(const uint8_t *Record, uint32_t &Priority) { + get32(Record, 48, Priority); + } + + static void getAmode(const uint8_t *Record, GOFF::ESDAmode &Amode) { + uint8_t Value; + get8(Record, 60, Value); + Amode = (GOFF::ESDAmode)Value; + } + + static void getRmode(const uint8_t *Record, GOFF::ESDRmode &Rmode) { + uint8_t Value; + get8(Record, 61, Value); + Rmode = (GOFF::ESDRmode)Value; + } + + static void getTextStyle(const uint8_t *Record, GOFF::ESDTextStyle &Style) { + uint8_t Value; + getBits(Record, 62, 0, 4, Value); + Style = (GOFF::ESDTextStyle)Value; + } + + static void getBindingAlgorithm(const uint8_t *Record, + GOFF::ESDBindingAlgorithm &Algorithm) { + uint8_t Value; + getBits(Record, 62, 4, 4, Value); + Algorithm = (GOFF::ESDBindingAlgorithm)Value; + } + + static void getTaskingBehavior(const uint8_t *Record, + GOFF::ESDTaskingBehavior &TaskingBehavior) { + uint8_t Value; + getBits(Record, 63, 0, 3, Value); + TaskingBehavior = (GOFF::ESDTaskingBehavior)Value; + } + + static void getReadOnly(const uint8_t *Record, bool &ReadOnly) { + uint8_t Value; + getBits(Record, 63, 4, 1, Value); + ReadOnly = (bool)Value; + } + + static void getExecutable(const uint8_t *Record, + GOFF::ESDExecutable &Executable) { + uint8_t Value; + getBits(Record, 63, 5, 3, Value); + Executable = (GOFF::ESDExecutable)Value; + } + + static void getDuplicateSeverity(const uint8_t *Record, + GOFF::ESDDuplicateSymbolSeverity &DSS) { + uint8_t Value; + getBits(Record, 64, 2, 2, Value); + DSS = (GOFF::ESDDuplicateSymbolSeverity)Value; + } + + static void getBindingStrength(const uint8_t *Record, + GOFF::ESDBindingStrength &Strength) { + uint8_t Value; + getBits(Record, 64, 4, 4, Value); + Strength = (GOFF::ESDBindingStrength)Value; + } + + static void getLoadingBehavior(const uint8_t *Record, + GOFF::ESDLoadingBehavior &Behavior) { + uint8_t Value; + getBits(Record, 65, 0, 2, Value); + Behavior = (GOFF::ESDLoadingBehavior)Value; + } + + static void getIndirectReference(const uint8_t *Record, bool &Indirect) { + uint8_t Value; + getBits(Record, 65, 3, 1, Value); + Indirect = (bool)Value; + } + + static void getBindingScope(const uint8_t *Record, + GOFF::ESDBindingScope &Scope) { + uint8_t Value; + getBits(Record, 65, 4, 4, Value); + Scope = (GOFF::ESDBindingScope)Value; + } + + static void getLinkageType(const uint8_t *Record, + GOFF::ESDLinkageType &Type) { + uint8_t Value; + getBits(Record, 66, 2, 1, Value); + Type = (GOFF::ESDLinkageType)Value; + } + + static void getAlignment(const uint8_t *Record, + GOFF::ESDAlignment &Alignment) { + uint8_t Value; + getBits(Record, 66, 3, 5, Value); + Alignment = (GOFF::ESDAlignment)Value; + } +}; + +class RLDRecord : public Record { +public: + /// \brief Maximum length of data; any more must go in another continuation. + static const uint8_t RLDMaxDataLength = 74; + + /// \brief Lenght in bytes of one full relocation entry. We don't pack EsdIds. + static const uint8_t DataEntryLength = 20; + +public: + RLDRecord() : Record() { setRecordType(GOFF::RT_RLD); } + + void setLength(uint16_t Length) { set16(4, Length); } + + void setData(const GOFFRelocationEntry &Ent, uint8_t Index) { + assert(Index < 2 && "Can only store two entries per RLD Record"); + + uint8_t Offset = 6 + DataEntryLength * Index; + + setBits(Offset + 1, 0, 4, Ent.ReferenceType); + setBits(Offset + 1, 4, 4, Ent.ReferentType); + setBits(Offset + 2, 0, 7, Ent.Action); + if (Ent.NoFetchTarget) + setBits(Offset + 2, 7, 1, 1); + else + setBits(Offset + 2, 7, 1, 0); + set8(Offset + 4, Ent.TargetLength); + set32(Offset + 8, Ent.REsdId); + set32(Offset + 12, Ent.PEsdId); + set32(Offset + 16, Ent.POffset); + } + + // RLD Get routines + static void getLength(const uint8_t *Record, uint16_t &Length) { + get16(Record, 4, Length); + } +}; + +class ContinuationRecord : public Record { +public: + /// \brief Maximum length of data; any more must go in another continuation. + static const uint8_t ContinuationMaxDataLength = 77; + +public: + ContinuationRecord(GOFF::RecordType Type) : Record() { + setRecordType(Type); + setContinuation(true); + } + + // As it stands we call this function with both of these iterators and they + // both just happen to be typedef'd to char*. If the underlying implementation + // ever changes then these overloads should be used. + // void setData(const SmallVectorImpl::const_iterator &Data, + // uint8_t Length); + // void setData(const StringRef::const_iterator &Data, uint8_t Length); + void setData(const char *Data, uint8_t Length) { + assert(Length <= ContinuationMaxDataLength && + "Data too long for Continuation Record"); + + for (int I = 0; I < Length; ++I) + set8(3 + I, Data[I]); + } +}; + +class ENDRecord : public Record { +public: + ENDRecord() : Record() { + setRecordType(GOFF::RT_END); + setEntryPointRequestType(GOFF::END_EPR_None); // TODO Always None for now + } + + void setEntryPointRequestType(GOFF::ENDEntryPointRequest Eprt) { + setBits(3, 6, 2, Eprt); + } + + void setEntryAmode(GOFF::ESDAmode Amode) { set8(4, Amode); } + + void setEntryEsdId(uint32_t EsdId) { set32(12, EsdId); } + + void setRecordCount(uint32_t RecordCount) { set32(8, RecordCount); } +}; + +} // end namespace object +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/Object/GOFFObjectFile.h b/llvm/include/llvm/Object/GOFFObjectFile.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Object/GOFFObjectFile.h @@ -0,0 +1,179 @@ +//===- GOFF.h - GOFF object file implementation -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the GOFFObjectFile class. +// Record classes and derivatives are also declared and implemented. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_GOFFOBJECTFILE_H +#define LLVM_OBJECT_GOFFOBJECTFILE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/CharSet.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +namespace object { + +class GOFFObjectFile : public ObjectFile { + + IndexedMap EsdPtrs; // indexed by EsdId + SmallVector TextPtrs; + SmallVector RldPtrs; + + mutable DenseMap EsdNames; + + typedef DataRefImpl SectionEntryImpl; + // (EDID, 0) code, r/o data section + // (EDID,PRID) r/w data section + SmallVector SectionList; + mutable DenseMap SectionData; + + std::string RelocationData; + + CharSetConverter Converter; + +protected: + // SymbolRef + Expected getSymbolName(DataRefImpl Symb) const override; + Expected getSymbolAddress(DataRefImpl Symb) const override; + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + Expected getSymbolFlags(DataRefImpl Symb) const override; + Expected getSymbolType(DataRefImpl Symb) const override; + Expected getSymbolSection(DataRefImpl Symb) const override; + + // GOFF specific +public: + DataRefImpl getAdaSymbolOfSymbol(DataRefImpl Symb) const; + std::error_code getSymbolName(SymbolRef Symbol, StringRef &Res) const; + +private: + const uint8_t *getSymbolEsdRecord(DataRefImpl Symb) const; + bool isSymbolUnresolved(DataRefImpl Symb) const; + bool isSymbolIndirect(DataRefImpl Symb) const; + +protected: + // SectionRef + void moveSectionNext(DataRefImpl &Sec) const override; + virtual Expected getSectionName(DataRefImpl Sec) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + virtual Expected> + getSectionContents(DataRefImpl Sec) const override; + uint64_t getSectionIndex(DataRefImpl Sec) const override; + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + + // GOFF specific +public: + bool isSectionNoLoad(DataRefImpl Sec) const; + bool isSectionReadOnlyData(DataRefImpl Sec) const; + bool isSectionZeroInit(DataRefImpl Sec) const; + +private: + const uint8_t *getSectionEdEsdRecord(DataRefImpl &Sec) const; + const uint8_t *getSectionPrEsdRecord(DataRefImpl &Sec) const; + const uint8_t *getSectionEdEsdRecord(uint32_t SectionIndex) const; + const uint8_t *getSectionPrEsdRecord(uint32_t SectionIndex) const; + uint32_t getSectionDefEsdId(DataRefImpl &Sec) const; + + typedef struct { + //// == common output + DataRefImpl Sec; // section containing relocation + uint64_t PosOffset; // offset of relocation in Sec + DataRefImpl RefSymb; // symbol referred to + uint64_t RelocationType; // type of relocation + + //// === fields used when processing relocations from object file + uint32_t RelocationDataOffset; + uint16_t CurrentRldSize; + + uint32_t SectionDefId; + + // Optional RLD fields whose value is inherited from a previous RLD item + uint32_t OReferenceId; + uint32_t OPositionId; + uint64_t OOffset; + + //// === fields when processing relocations for manufactured function + /// descriptor section + uint32_t FunctionDescriptorIndex; + bool DoingFuncSymb; + } RelocationIteratorState_t; + +protected: + // RelocationRef + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl &Result) const override; + // GOFF specific +public: + static GOFF::RLDReferenceType getRLDReferenceType(uint64_t RelocationType); + static GOFF::RLDAction getRLDAction(uint64_t RelocationType); // +,-,... + static GOFF::RLDFetchStore getRLDFetchStore(uint64_t RelocationType); + static uint16_t getRLDBitLength(uint64_t RelocationType); + static uint8_t getRLDBitOffset(uint64_t RelocationType); + static bool + getRLDSymbolIsIndirect(uint64_t RelocationType); // function descriptor ref + static bool getRLDIsWeak(uint64_t RelocationType); // weak ref + static bool + getRLDIsCodeAddressReference(uint64_t RelocationType); // function code ref + static uint32_t getNormalRelocationType(uint8_t PointerSizeInBytes); + + static uint8_t getBytesInFunctionDescriptor() { return 16; } // XPLink 64 + +private: + void getRelocationData(); + +protected: +public: + GOFFObjectFile(MemoryBufferRef Object, std::error_code &EC); + static inline bool classof(const Binary *V) { return V->isGOFF(); } + section_iterator section_begin() const override; + section_iterator section_end() const override; + + uint8_t getBytesInAddress() const override { return 8; } + + StringRef getFileFormatName() const override { return "GOFF-SystemZ"; } + + Triple::ArchType getArch() const override { return Triple::systemz; } + + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + + bool isRelocatableObject() const override { return true; } + + void moveSymbolNext(DataRefImpl &Symb) const override; + basic_symbol_iterator symbol_begin() const override; + basic_symbol_iterator symbol_end() const override; +}; + +} // namespace object + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -374,6 +374,9 @@ uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0); + static Expected> + createGOFFObjectFile(MemoryBufferRef Object); + static Expected> createWasmObjectFile(MemoryBufferRef Object); }; diff --git a/llvm/lib/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp --- a/llvm/lib/BinaryFormat/Magic.cpp +++ b/llvm/lib/BinaryFormat/Magic.cpp @@ -83,7 +83,10 @@ if (startswith(Magic, "!\n") || startswith(Magic, "!\n")) return file_magic::archive; break; - + case 0x03: + if (startswith(Magic, "\x03\xF0\x00")) + return file_magic::goff_object; + break; case '\177': if (startswith(Magic, "\177ELF") && Magic.size() >= 18) { bool Data2MSB = Magic[5] == 2; diff --git a/llvm/lib/Object/Binary.cpp b/llvm/lib/Object/Binary.cpp --- a/llvm/lib/Object/Binary.cpp +++ b/llvm/lib/Object/Binary.cpp @@ -68,6 +68,7 @@ case file_magic::macho_kext_bundle: case file_magic::coff_object: case file_magic::coff_import_library: + case file_magic::goff_object: case file_magic::pecoff_executable: case file_magic::bitcode: case file_magic::xcoff_object_32: diff --git a/llvm/lib/Object/CMakeLists.txt b/llvm/lib/Object/CMakeLists.txt --- a/llvm/lib/Object/CMakeLists.txt +++ b/llvm/lib/Object/CMakeLists.txt @@ -9,6 +9,7 @@ ELF.cpp ELFObjectFile.cpp Error.cpp + GOFFObjectFile.cpp IRObjectFile.cpp IRSymtab.cpp MachOObjectFile.cpp diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Object/GOFFObjectFile.cpp @@ -0,0 +1,867 @@ +//===- GOFFObjectFile.cpp - GOFF object file implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the GOFFObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/GOFFObjectFile.h" +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/Object/GOFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#ifndef DEBUG_TYPE +#define DEBUG_TYPE "goff" +#endif + +using namespace llvm; +using namespace object; + +Expected> +ObjectFile::createGOFFObjectFile(MemoryBufferRef Object) { + std::error_code EC; + std::unique_ptr Ret(new GOFFObjectFile(Object, EC)); + if (EC) + return make_error("Unexpected EOF", EC); + return std::move(Ret); +} + +GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, std::error_code &EC) + : ObjectFile(Binary::ID_GOFF, Object), + Converter(cantFail(errorOrToExpected(CharSetConverter::create( + CharSetConverter::CP_IBM1047, CharSetConverter::CP_UTF8)))) { + // Object file isn't the right size, bail out early + if ((Object.getBufferSize() % GOFF::RecordLength) != 0) { + EC = make_error_code(object_error::unexpected_eof); + return; + } + + SectionEntryImpl DummySection; + SectionList.emplace_back(DummySection); // dummy entry at index 0 + + const uint8_t *End = reinterpret_cast(Data.getBufferEnd()); + for (const uint8_t *I = base(); I < End; I += GOFF::RecordLength) { + uint8_t RecordType = (I[1] & 0xF0) >> 4; + bool IsContinuation = I[1] & 0x02; + + // Don't parse continuations records, they've already been handled by + // a previous record parse call + if (IsContinuation) + continue; + + for (size_t J = 0; J < GOFF::RecordLength; ++J) { + const uint8_t *P = I + J; + if (J % 8 == 0) + LLVM_DEBUG(dbgs() << " "); + + LLVM_DEBUG(dbgs() << format("%02hhX", *P)); + } + switch (RecordType) { + case GOFF::RT_ESD: { + // Save ESD record + uint32_t EsdId; + ESDRecord::getEsdId(I, EsdId); + EsdPtrs.grow(EsdId); + EsdPtrs[EsdId] = reinterpret_cast(I); + + // Determine and save the "sections" in GOFF. + // A section is saved as a tuple of the form + // case (1): (ED,child PR) + // - where the PR must be have non-zero length. + // case (2a) (ED,0) + // - where the ED is of non-zero length + // case (2b) (ED,0) + // - where the ED is zero length but + // but contains a label (LD) + GOFF::ESDSymbolType SymbolType; + ESDRecord::getSymbolType(I, SymbolType); + SectionEntryImpl Section; + uint32_t Length; + ESDRecord::getLength(I, Length); + if (SymbolType == GOFF::ESD_ST_ElementDefinition) { + // case (2a) + if (Length != 0) { + Section.d.a = EsdId; + SectionList.emplace_back(Section); + } + } else if (SymbolType == GOFF::ESD_ST_PartReference) { + // case (1) + if (Length != 0) { + uint32_t SymEdId; + ESDRecord::getParentEsdId(I, SymEdId); + Section.d.a = SymEdId; + Section.d.b = EsdId; + SectionList.emplace_back(Section); + } + } else if (SymbolType == GOFF::ESD_ST_LabelDefinition) { + // case (2b) + uint32_t SymEdId; + ESDRecord::getParentEsdId(I, SymEdId); + const uint8_t *SymEdRecord = + reinterpret_cast(EsdPtrs[SymEdId]); + uint32_t EdLength; + ESDRecord::getLength(SymEdRecord, EdLength); + if (!EdLength) { // [ EDID, PRID ] + // LD child of a zero length parent ED + // Add the section ED which was previously ignored + Section.d.a = SymEdId; + SectionList.emplace_back(Section); + } + } + LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n"); + break; + } + case GOFF::RT_TXT: + // Save TXT records + TextPtrs.emplace_back(reinterpret_cast(I)); + LLVM_DEBUG(dbgs() << " -- TXT\n"); + break; + case GOFF::RT_RLD: + // Save RLD records + RldPtrs.emplace_back(reinterpret_cast(I)); + LLVM_DEBUG(dbgs() << " -- RLD\n"); + break; + case GOFF::RT_LEN: + LLVM_DEBUG(dbgs() << " -- LEN (GOFF record type) unhandled\n"); + break; + case GOFF::RT_END: + LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n"); + break; + case GOFF::RT_HDR: + LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n"); + break; + default: + llvm_unreachable("Unknown record type"); + } + } + + getRelocationData(); +} + +// SymbolRef +DataRefImpl GOFFObjectFile::getAdaSymbolOfSymbol(DataRefImpl Symb) const { + const uint8_t *EsdRecord = getSymbolEsdRecord(Symb); + uint32_t AdaId; + ESDRecord::getAdaEsdId(EsdRecord, AdaId); // use as function indicator + DataRefImpl AdaSymb; + AdaSymb.d.a = AdaId; + return AdaSymb; +} +const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const { + const uint8_t *EsdRecord = + reinterpret_cast(EsdPtrs[Symb.d.a]); + return EsdRecord; +} +Expected GOFFObjectFile::getSymbolName(DataRefImpl Symb) const { + if (EsdNames.count(Symb.d.a)) + return EsdNames[Symb.d.a]; + + const char *Record = (const char *)getSymbolEsdRecord(Symb); + + // TODO: This could probably be changed to extract the length of the symbol + // name and then grab only that many characters but for now this works fine + uint16_t Continuations = 0; + while (true) { + // Is the record continued in the next record + const char *ContinuationByte = + Record + (Continuations * GOFF::RecordLength) + 1; + bool IsContinued = *ContinuationByte & 0x01; + + if (IsContinued) + ++Continuations; + else + break; + } + + SmallString<256> SymbolName(Record + 72, Record + GOFF::RecordLength); + + // This assumes that we always emit 80 byte records even if the rest of the + // data in a record is nulls + for (uint16_t I = 0; I < Continuations; ++I) { + const char *ContRecord = Record + (GOFF::RecordLength * (I + 1)); + SymbolName.append(ContRecord + 3, ContRecord + GOFF::RecordLength); + } + + SmallString<256> SymbolNameConverted; + if (auto EC = Converter.convert(SymbolName, SymbolNameConverted)) + return errorCodeToError(EC); + EsdNames[Symb.d.a].assign(SymbolNameConverted.c_str()); + return EsdNames[Symb.d.a]; +} + +std::error_code GOFFObjectFile::getSymbolName(SymbolRef Symbol, + StringRef &Res) const { + Expected NameOrErr = getSymbolName(Symbol.getRawDataRefImpl()); + if (NameOrErr) { + Res = *NameOrErr; + return std::error_code(); + } + return errorToErrorCode(NameOrErr.takeError()); +} + +Expected GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { + uint32_t Offset; + const uint8_t *EsdRecord = getSymbolEsdRecord(Symb); + ESDRecord::getOffset(EsdRecord, Offset); + return static_cast(Offset); +} + +uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + uint32_t Offset; + const uint8_t *EsdRecord = getSymbolEsdRecord(Symb); + ESDRecord::getOffset(EsdRecord, Offset); + return static_cast(Offset); +} + +uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { + return 0; +} + +bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const { + const uint8_t *Record = getSymbolEsdRecord(Symb); + GOFF::ESDSymbolType SymbolType; + ESDRecord::getSymbolType(Record, SymbolType); + + if (SymbolType == GOFF::ESD_ST_ExternalReference) + return true; + if (SymbolType == GOFF::ESD_ST_PartReference) { + uint32_t Length; + ESDRecord::getLength(Record, Length); + if (Length == 0) + return true; + } + return false; +} + +bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const { + const uint8_t *Record = getSymbolEsdRecord(Symb); + bool Indirect; + ESDRecord::getIndirectReference(Record, Indirect); + return Indirect; +} + +Expected GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { + uint32_t Flags = 0; + if (isSymbolUnresolved(Symb)) + Flags |= SymbolRef::SF_Undefined; + + const uint8_t *Record = getSymbolEsdRecord(Symb); + + GOFF::ESDBindingStrength BindingStrength; + ESDRecord::getBindingStrength(Record, BindingStrength); + if (BindingStrength == GOFF::ESD_BST_Weak) + Flags |= SymbolRef::SF_Weak; + + GOFF::ESDBindingScope BindingScope; + ESDRecord::getBindingScope(Record, BindingScope); + + if (BindingScope != GOFF::ESD_BSC_Section) { + Expected Name = getSymbolName(Symb); + if (Name && !Name->equals(" ")) { // blank name is local + Flags |= SymbolRef::SF_Global; + if (BindingScope == GOFF::ESD_BSC_ImportExport) + Flags |= SymbolRef::SF_Exported; + else if (!(Flags & SymbolRef::SF_Undefined)) + Flags |= SymbolRef::SF_Hidden; + } + } + + return Flags; +} + +Expected +GOFFObjectFile::getSymbolType(DataRefImpl Symb) const { + const uint8_t *Record = getSymbolEsdRecord(Symb); + GOFF::ESDSymbolType SymbolType; + ESDRecord::getSymbolType(Record, SymbolType); + GOFF::ESDExecutable Executable; + ESDRecord::getExecutable(Record, Executable); + + assert((SymbolType == GOFF::ESD_ST_SectionDefinition || + SymbolType == GOFF::ESD_ST_ElementDefinition || + SymbolType == GOFF::ESD_ST_LabelDefinition || + SymbolType == GOFF::ESD_ST_PartReference || + SymbolType == GOFF::ESD_ST_ExternalReference) && + "SymbolType must be SectionDef/ElemDef/LabelDef/PartRef/ExtRef"); + + switch (SymbolType) { + case GOFF::ESD_ST_SectionDefinition: + case GOFF::ESD_ST_ElementDefinition: + return SymbolRef::ST_Other; + case GOFF::ESD_ST_LabelDefinition: + case GOFF::ESD_ST_PartReference: + case GOFF::ESD_ST_ExternalReference: + assert((Executable == GOFF::ESD_EXE_CODE || + Executable == GOFF::ESD_EXE_DATA || + Executable == GOFF::ESD_EXE_Unspecified) && + "Executable must be CODE/DATA/Unspecified"); + switch (Executable) { + case GOFF::ESD_EXE_CODE: + return SymbolRef::ST_Function; + case GOFF::ESD_EXE_DATA: + return SymbolRef::ST_Data; + case GOFF::ESD_EXE_Unspecified: + return SymbolRef::ST_Unknown; + } + } +} + +Expected +GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { + DataRefImpl Sec; + + if (isSymbolUnresolved(Symb)) + return section_iterator(SectionRef(Sec, this)); + + const uint8_t *SymEsdRecord = + reinterpret_cast(EsdPtrs[Symb.d.a]); + uint32_t SymEdId; + ESDRecord::getParentEsdId(SymEsdRecord, SymEdId); + const uint8_t *SymEdRecord = + reinterpret_cast(EsdPtrs[SymEdId]); + + for (size_t I = 0; I < SectionList.size(); ++I) { + bool Found; + const uint8_t *SectionPrRecord = getSectionPrEsdRecord(I); + if (SectionPrRecord) { + Found = SymEsdRecord == SectionPrRecord; + } else { + const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I); + Found = SymEdRecord == SectionEdRecord; + } + + if (Found) { + Sec.d.a = I; + return section_iterator(SectionRef(Sec, this)); + } + } + llvm_unreachable("unable to get symbol section"); + return section_iterator(SectionRef(Sec, this)); +} + +// SectionRef +const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const { + SectionEntryImpl EsdIds = SectionList[Sec.d.a]; + const uint8_t *EsdRecord = + reinterpret_cast(EsdPtrs[EsdIds.d.a]); + return EsdRecord; +} + +const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const { + SectionEntryImpl EsdIds = SectionList[Sec.d.a]; + const uint8_t *EsdRecord = NULL; + if (EsdIds.d.b) + EsdRecord = reinterpret_cast(EsdPtrs[EsdIds.d.b]); + return EsdRecord; +} +const uint8_t * +GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const { + DataRefImpl Sec; + Sec.d.a = SectionIndex; + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + return EsdRecord; +} +const uint8_t * +GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const { + DataRefImpl Sec; + Sec.d.a = SectionIndex; + const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec); + return EsdRecord; +} + +uint32_t GOFFObjectFile::getSectionDefEsdId(DataRefImpl &Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + uint32_t Length; + ESDRecord::getLength(EsdRecord, Length); + if (Length == 0) { + const uint8_t *PrEsdRecord = getSectionPrEsdRecord(Sec); + if (PrEsdRecord) + EsdRecord = PrEsdRecord; + } + + uint32_t DefEsdId; + ESDRecord::getEsdId(EsdRecord, DefEsdId); + LLVM_DEBUG(dbgs() << "Got def EsdId: " << DefEsdId << '\n'); + return DefEsdId; +} + +void GOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { + if ((Sec.d.a + 1) >= SectionList.size()) + Sec.d.a = 0; // section_end + else + Sec.d.a++; +} + +Expected GOFFObjectFile::getSectionName(DataRefImpl Sec) const { + DataRefImpl EdSym; + SectionEntryImpl EsdIds = SectionList[Sec.d.a]; + EdSym.d.a = EsdIds.d.a; + Expected Name = getSymbolName(EdSym); + if (Name) { + StringRef Res = *Name; + LLVM_DEBUG(dbgs() << "Got section: " << Res << '\n'); + if (Res.equals("C___clangast")) + Res = "__clangast"; + else if (Res.equals("C_autolink")) + Res = ".swift1_autolink_entries"; + LLVM_DEBUG(dbgs() << "Final section name: " << Res << '\n'); + Name = Res; + } + return Name; +} + +uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { + uint32_t Offset; + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + ESDRecord::getOffset(EsdRecord, Offset); + return Offset; +} + +uint64_t GOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { + return Sec.d.a; +} + +uint64_t GOFFObjectFile::getSectionSize(DataRefImpl Sec) const { + uint32_t Length; + uint32_t DefEsdId = getSectionDefEsdId(Sec); + const uint8_t *EsdRecord = + reinterpret_cast(EsdPtrs[DefEsdId]); + ESDRecord::getLength(EsdRecord, Length); + LLVM_DEBUG(dbgs() << "Got section size: " << Length << '\n'); + return static_cast(Length); +} + +// Unravel TXT records and expand fill characters to produce +// a contiguous sequence of bytes +Expected> +GOFFObjectFile::getSectionContents(DataRefImpl Sec) const { + if (SectionData.count(Sec.d.a)) { + StringRef Res = StringRef(SectionData[Sec.d.a]); + return arrayRefFromStringRef(Res); + } + + uint64_t SectionSize = getSectionSize(Sec); + uint32_t DefEsdId = getSectionDefEsdId(Sec); + + const uint8_t *EdEsdRecord = getSectionEdEsdRecord(Sec); + bool FillBytePresent; + ESDRecord::getFillBytePresent(EdEsdRecord, FillBytePresent); + uint8_t FillByte = '\0'; + if (FillBytePresent) + ESDRecord::getFillByteValue(EdEsdRecord, FillByte); + + // Initialize section with fill byte + + std::string &Data = SectionData[Sec.d.a]; + Data.reserve(SectionSize); + Data.insert(0, SectionSize, FillByte); + + // Replace section with context from text records + + std::vector TxtRecords; + for (uintptr_t TxtRecordInt : TextPtrs) { + const uint8_t *TxtRecordPtr = + reinterpret_cast(TxtRecordInt); + uint32_t TxtEsdId; + TXTRecord::getElementEsdId(TxtRecordPtr, TxtEsdId); + LLVM_DEBUG(dbgs() << "Got txt EsdId: " << TxtEsdId << '\n'); + + if (TxtEsdId == DefEsdId) + TxtRecords.push_back(TxtRecordInt); + } + LLVM_DEBUG(dbgs() << "Found " << TxtRecords.size() << " matching records\n"); + + for (uintptr_t TxtRecordInt : TxtRecords) { + const uint8_t *TxtRecordPtr = + reinterpret_cast(TxtRecordInt); + uint32_t TxtDataOffset; + TXTRecord::getOffset(TxtRecordPtr, TxtDataOffset); + LLVM_DEBUG(dbgs() << "Got record data offset: " << TxtDataOffset << '\n'); + uint32_t CurrentOffset = TxtDataOffset; + + uint16_t TxtDataSize; + TXTRecord::getDataLength(TxtRecordPtr, TxtDataSize); + LLVM_DEBUG(dbgs() << "Got record data size: " << TxtDataSize << '\n'); + + // Need char* from here on + char *ChrPtr = reinterpret_cast(TxtRecordInt); + if (TxtDataSize < TXTRecord::TXTMaxDataLength) { + Data.replace(CurrentOffset, TxtDataSize, ChrPtr + 24, TxtDataSize); + CurrentOffset += TxtDataSize; + } else { + Data.replace(CurrentOffset, TXTRecord::TXTMaxDataLength, ChrPtr + 24, + TXTRecord::TXTMaxDataLength); + CurrentOffset += TXTRecord::TXTMaxDataLength; + ChrPtr += GOFF::RecordLength; // Advance record + + // Consume continuation records + uint16_t ConsumedCounter = TXTRecord::TXTMaxDataLength; // Start at offset + while (ConsumedCounter < TxtDataSize) { + uint16_t Diff = TxtDataSize - ConsumedCounter; + if (Diff < ContinuationRecord::ContinuationMaxDataLength) { + Data.replace(CurrentOffset, Diff, ChrPtr + 3, Diff); + CurrentOffset += Diff; + ConsumedCounter += Diff; + assert(ConsumedCounter == TxtDataSize && + "Should have consumed all bytes from logical record"); + } else { + Data.replace( + CurrentOffset, ContinuationRecord::ContinuationMaxDataLength, + ChrPtr + 3, ContinuationRecord::ContinuationMaxDataLength); + CurrentOffset += ContinuationRecord::ContinuationMaxDataLength; + ConsumedCounter += ContinuationRecord::ContinuationMaxDataLength; + ChrPtr += GOFF::RecordLength; // Advance record + } + } + } + } + + StringRef Res = StringRef(Data); + return arrayRefFromStringRef(Res); +} + +uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDAlignment Pow2Alignment; + ESDRecord::getAlignment(EsdRecord, Pow2Alignment); + uint64_t ByteAlignment = 1 << (uint64_t)Pow2Alignment; + return ByteAlignment; +} + +bool GOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { + return false; +} + +bool GOFFObjectFile::isSectionText(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDExecutable Executable; + ESDRecord::getExecutable(EsdRecord, Executable); + bool IsSectionText = (Executable == GOFF::ESD_EXE_CODE); + return IsSectionText; +} + +bool GOFFObjectFile::isSectionData(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDExecutable Executable; + ESDRecord::getExecutable(EsdRecord, Executable); + bool IsSectionData = (Executable == GOFF::ESD_EXE_DATA); + return IsSectionData; +} + +bool GOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; } + +bool GOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; } + +bool GOFFObjectFile::isSectionNoLoad(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDLoadingBehavior LoadingBehavior; + ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior); + bool Result = LoadingBehavior == GOFF::ESD_LB_NoLoad; + return Result; +} + +bool GOFFObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const { + bool Result; + if (isSectionData(Sec)) { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDLoadingBehavior LoadingBehavior; + ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior); + Result = LoadingBehavior == GOFF::ESD_LB_Initial; + } else { + Result = false; + } + return Result; +} + +bool GOFFObjectFile::isSectionZeroInit(DataRefImpl Sec) const { + // GOFF uses fill characters and fill characters are applied + // on getSectionContents() - so we say false to zero init + bool Result = false; + return Result; +} + +relocation_iterator GOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { + DataRefImpl Rel; + RelocationIteratorState_t *RIS = + (RelocationIteratorState_t *)calloc(1, sizeof(RelocationIteratorState_t)); + RIS->Sec = Sec; + RIS->SectionDefId = getSectionDefEsdId(Sec); + Rel.p = reinterpret_cast(RIS); + moveRelocationNext(Rel); + return relocation_iterator(RelocationRef(Rel, this)); +} + +relocation_iterator GOFFObjectFile::section_rel_end(DataRefImpl Sec) const { + DataRefImpl Rel; + return relocation_iterator(RelocationRef(Rel, this)); +} + +// RelocationRef +void GOFFObjectFile::getRelocationData() { + if (RelocationData.size()) + return; + + // Calculate total length of relocation items from all records + uint32_t RelocationDataSize = 0; + uint16_t RldLengthField; + for (uint32_t I = 0; I < RldPtrs.size(); I++) { + const uint8_t *RldRecord = reinterpret_cast(RldPtrs[I]); + RLDRecord::getLength(RldRecord, RldLengthField); + RelocationDataSize += RldLengthField; + } + + RelocationData.reserve(RelocationDataSize); + + // Populate RelocationData with relocation items from all records + for (uint32_t I = 0; I < RldPtrs.size(); I++) { + const uint8_t *RldRecord = reinterpret_cast(RldPtrs[I]); + RLDRecord::getLength(RldRecord, RldLengthField); + uint16_t Remainder = RldLengthField; + + uint32_t AppendLength = Remainder < (GOFF::RecordLength - 6) + ? Remainder + : (GOFF::RecordLength - 6); + const char *ChrPtr = reinterpret_cast(RldRecord); + RelocationData.append(ChrPtr + 6, AppendLength); // copy from initial record + Remainder -= AppendLength; + ChrPtr += GOFF::RecordLength; + while (Remainder > 0) { + AppendLength = Remainder < (GOFF::RecordLength - 3) + ? Remainder + : (GOFF::RecordLength - 3); + RelocationData.append(ChrPtr + 3, AppendLength); // copy from continuation + Remainder -= AppendLength; + ChrPtr += GOFF::RecordLength; + } + } +} + +void GOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { + RelocationIteratorState_t *RIS = (RelocationIteratorState_t *)Rel.p; + if (!RIS) + return; + +#define F_SAME_R_ID 0x80 +#define F_SAME_P_ID 0x40 +#define F_SAME_OFFSET 0x20 +#define F_EXT_ATTR_PRESENT 0x04 +#define F_8_BYTE_OFFSET 0x02 + + // In GOFF, relocations are not ordered by section so + // we search to find the next relevent relocation + // for the section. Also, we keep state information as a relocations + // can be compact and inherit values from a prior relocation. + // In addition, a "relocation type" encodes a lot of information + // such as type, size and bit offsets, actions, and some symbol + // flags (such as weak and indirect). This makes the "relocation + // type" type detailed enough to support MCJIT resolution + // and relocation phases. The getRLDx() routines below + // are to be used to extract particular information. + const uint8_t *Data = + reinterpret_cast(RelocationData.data()); + while (RIS->RelocationDataOffset < RelocationData.size()) { + RIS->RelocationDataOffset += RIS->CurrentRldSize; + const uint8_t *Rld = Data + RIS->RelocationDataOffset; + uint8_t Flags0 = Rld[0]; + + int32_t CurrOffset = 8; + if (!(Flags0 & F_SAME_R_ID)) { + RIS->OReferenceId = support::endian::read32be(&Rld[CurrOffset]); + CurrOffset += 4; + } + if (!(Flags0 & F_SAME_P_ID)) { + RIS->OPositionId = support::endian::read32be(&Rld[CurrOffset]); + CurrOffset += 4; + } + if (!(Flags0 & F_SAME_OFFSET)) { + if (Flags0 & F_8_BYTE_OFFSET) { + RIS->OOffset = support::endian::read64be(&Rld[CurrOffset]); + CurrOffset += 8; + } else { + RIS->OOffset = support::endian::read32be(&Rld[CurrOffset]); + CurrOffset += 4; + } + } + if (Flags0 & F_EXT_ATTR_PRESENT) + CurrOffset += 8; + + RIS->CurrentRldSize = CurrOffset; + + if (RIS->OPositionId == RIS->SectionDefId) { + RIS->PosOffset = RIS->OOffset; + RIS->RefSymb.d.a = RIS->OReferenceId; + const uint8_t *Data = + reinterpret_cast(RelocationData.data()); + const uint8_t *Rld = Data + RIS->RelocationDataOffset; + // === length & bit offset === = type action/fetch = + RIS->RelocationType = + (Rld[4] << 24) + (Rld[5] << 16) + (Rld[1] << 8) + Rld[2]; + // Note: we encode indirect, weak, and code address flags in the high + // word of RelocationType. +#define RLD_INDIRECT_FLAG 0x400000000 +#define RLD_CODE_ADDR_FLAG 0x200000000 +#define RLD_WEAK_FLAG 0x100000000 + if (isSymbolIndirect(RIS->RefSymb)) { + RIS->RelocationType |= RLD_INDIRECT_FLAG; + } else if (getRLDReferenceType(RIS->RelocationType) != + GOFF::RLD_RT_RTypeConstant) { + // A reference to a function could refer to the functions descriptor + // (via indirect indicator) or to the ADA of the function + // (via reference type of RLD_RT_RTypeConstant) or to the executable + // code address of the function. Add an indicator this relocation + // refers to the code address of the function. These 3 flags make + // relocation processing easier + auto SymTypeOrErr = getSymbolType(RIS->RefSymb); + if (SymTypeOrErr) { + SymbolRef::Type SymType = *SymTypeOrErr; + if (SymType == SymbolRef::ST_Function) + RIS->RelocationType |= RLD_CODE_ADDR_FLAG; + } + } + uint32_t Flags = cantFail(getSymbolFlags(RIS->RefSymb)); + if (Flags & SymbolRef::SF_Weak) + RIS->RelocationType |= RLD_WEAK_FLAG; + return; + } + } + + free((void *)Rel.p); + Rel.p = 0; +} + +uint64_t GOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { + RelocationIteratorState_t *RIS = (RelocationIteratorState_t *)Rel.p; + if (RIS) { + return RIS->PosOffset; + } else { + llvm_unreachable("invalid call to getRelocationOffset"); + return 0; + } +} + +symbol_iterator GOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { + RelocationIteratorState_t *RIS = (RelocationIteratorState_t *)Rel.p; + if (!RIS) + llvm_unreachable("invalid call to getRelocationSymbol"); + return basic_symbol_iterator(SymbolRef(RIS->RefSymb, this)); +} + +uint64_t GOFFObjectFile::getRelocationType(DataRefImpl Rel) const { + RelocationIteratorState_t *RIS = (RelocationIteratorState_t *)Rel.p; + uint64_t RelocationType = 0; + if (RIS) + RelocationType = RIS->RelocationType; + else + llvm_unreachable("invalid call to getRelocationType"); + return RelocationType; +} + +void GOFFObjectFile::getRelocationTypeName( + DataRefImpl Rel, SmallVectorImpl &Result) const { + RelocationIteratorState_t *RIS = (RelocationIteratorState_t *)Rel.p; + if (RIS) { + uint64_t RelocationType = getRelocationType(Rel); + char Buff[16]; + sprintf(Buff, "R-%1x:%4.4x:%4.4x", + (uint16_t)((RelocationType >> 32) & 0x0003), + (uint16_t)((RelocationType >> 16) & 0xFFFF), + (uint16_t)(RelocationType & 0xFFFF)); + Result.append(Buff, Buff + strlen(Buff)); + } else { + llvm_unreachable("invalid call to getRelocationTypeName"); + } +} + +// Utility routines which extract details about the relocation from +// the relocation type. +GOFF::RLDFetchStore GOFFObjectFile::getRLDFetchStore(uint64_t RelocationType) { + GOFF::RLDFetchStore RFS = (GOFF::RLDFetchStore)(RelocationType & 0x00000001); + return RFS; +} +GOFF::RLDAction GOFFObjectFile::getRLDAction(uint64_t RelocationType) { + GOFF::RLDAction RA = (GOFF::RLDAction)((RelocationType & 0x000000FE) >> 1); + return RA; +} +GOFF::RLDReferenceType +GOFFObjectFile::getRLDReferenceType(uint64_t RelocationType) { + GOFF::RLDReferenceType RRT = + (GOFF::RLDReferenceType)((RelocationType & 0x0000F000) >> 12); + return RRT; +} +uint8_t GOFFObjectFile::getRLDBitOffset(uint64_t RelocationType) { + uint16_t RBO = ((RelocationType & 0x00070000) >> 16); + return RBO; +} +uint16_t GOFFObjectFile::getRLDBitLength(uint64_t RelocationType) { + uint16_t RBL = ((RelocationType & 0xFFE00000) >> 21); + return RBL; +} +bool GOFFObjectFile::getRLDIsCodeAddressReference(uint64_t RelocationType) { + bool IsCodeAddrReference = (RelocationType & RLD_CODE_ADDR_FLAG) != 0; + return IsCodeAddrReference; +} +bool GOFFObjectFile::getRLDSymbolIsIndirect(uint64_t RelocationType) { + bool IsIndirect = (RelocationType & RLD_INDIRECT_FLAG) != 0; + return IsIndirect; +} +bool GOFFObjectFile::getRLDIsWeak(uint64_t RelocationType) { + bool IsWeak = (RelocationType & RLD_WEAK_FLAG) != 0; + return IsWeak; +} + +// The following is used to help construct a relocation +uint32_t GOFFObjectFile::getNormalRelocationType(uint8_t PointerSizeInBytes) { + // === length & bit offset === = types/action/fetch = + uint8_t P = PointerSizeInBytes; + uint32_t RelocType = (P << 24) + (0 << 16) + (GOFF::RLD_RT_RAddress << 8) + 0; + return RelocType; +} + +section_iterator GOFFObjectFile::section_begin() const { + DataRefImpl Sec; + moveSectionNext(Sec); + return section_iterator(SectionRef(Sec, this)); +} + +section_iterator GOFFObjectFile::section_end() const { + DataRefImpl Sec; + return section_iterator(SectionRef(Sec, this)); +} + +void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { + for (uint32_t I = Symb.d.a + 1; I < EsdPtrs.size(); ++I) { + if (EsdPtrs[I]) { + const uint8_t *EsdRecord = reinterpret_cast(EsdPtrs[I]); + GOFF::ESDSymbolType SymbolType; + ESDRecord::getSymbolType(EsdRecord, SymbolType); + // Skip EDs - i.e. section symbols + bool IgnoreSpecialGOFFSymbols = true; + bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) || + (SymbolType == GOFF::ESD_ST_SectionDefinition)) && + IgnoreSpecialGOFFSymbols; + if (!SkipSymbol) { + Symb.d.a = I; + return; + } + } + } + Symb.d.a = 0; // symbol_end +} + +basic_symbol_iterator GOFFObjectFile::symbol_begin() const { + DataRefImpl Symb; + moveSymbolNext(Symb); + return basic_symbol_iterator(SymbolRef(Symb, this)); +} + +basic_symbol_iterator GOFFObjectFile::symbol_end() const { + DataRefImpl Symb; + return basic_symbol_iterator(SymbolRef(Symb, this)); +} diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp --- a/llvm/lib/Object/ObjectFile.cpp +++ b/llvm/lib/Object/ObjectFile.cpp @@ -126,6 +126,9 @@ // XCOFF implies AIX. TheTriple.setOS(Triple::AIX); TheTriple.setObjectFormat(Triple::XCOFF); + } else if (isGOFF()) { + TheTriple.setOS(Triple::ZOS); + TheTriple.setObjectFormat(Triple::GOFF); } return TheTriple; @@ -167,6 +170,8 @@ case file_magic::macho_dsym_companion: case file_magic::macho_kext_bundle: return createMachOObjectFile(Object); + case file_magic::goff_object: + return createGOFFObjectFile(Object); case file_magic::coff_object: case file_magic::coff_import_library: case file_magic::pecoff_executable: diff --git a/llvm/lib/Object/SymbolicFile.cpp b/llvm/lib/Object/SymbolicFile.cpp --- a/llvm/lib/Object/SymbolicFile.cpp +++ b/llvm/lib/Object/SymbolicFile.cpp @@ -64,6 +64,7 @@ case file_magic::macho_dsym_companion: case file_magic::macho_kext_bundle: case file_magic::pecoff_executable: + case file_magic::goff_object: case file_magic::xcoff_object_32: case file_magic::xcoff_object_64: case file_magic::wasm_object: