diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h index f1a30e41b736b..061b1b83370c3 100644 --- a/llvm/include/llvm/BinaryFormat/GOFF.h +++ b/llvm/include/llvm/BinaryFormat/GOFF.h @@ -157,6 +157,33 @@ enum ESDAlignment : uint8_t { ESD_ALIGN_4Kpage = 12, }; +enum TXTRecordStyle : uint8_t { + TXT_RS_Byte = 0, + TXT_RS_Structured = 1, + TXT_RS_Unstructured = 2, +}; + +enum RLDReferenceType : uint8_t { + RLD_RT_RAddress = 0, + RLD_RT_ROffset = 1, + RLD_RT_RLength = 2, + RLD_RT_RRelativeImmediate = 6, + RLD_RT_RTypeConstant = 7, // XPLink ADA + RLD_RT_RLongDisplacement = 9, +}; + +enum RLDReferentType : uint8_t { + RLD_RO_Label = 0, + RLD_RO_Element = 1, + RLD_RO_Class = 2, + RLD_RO_Part = 3, +}; + +enum RLDAction : uint8_t { + RLD_ACT_Add = 0, + RLD_ACT_Subtract = 1, +}; + enum ENDEntryPointRequest : uint8_t { END_EPR_None = 0, END_EPR_EsdidOffset = 1, diff --git a/llvm/include/llvm/ObjectYAML/GOFFYAML.h b/llvm/include/llvm/ObjectYAML/GOFFYAML.h new file mode 100644 index 0000000000000..83173197e3e36 --- /dev/null +++ b/llvm/include/llvm/ObjectYAML/GOFFYAML.h @@ -0,0 +1,244 @@ +//===- GOFFYAML.h - GOFF YAMLIO implementation ------------------*- 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 declares classes for handling the YAML representation of GOFF. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_GOFFYAML_H +#define LLVM_OBJECTYAML_GOFFYAML_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/ObjectYAML/YAML.h" +#include +#include + +namespace llvm { + +namespace GOFF { + +enum ESDFlags { + ESD_FillByteValuePresent = 1 << 7, + ESD_SymbolDisplayFlag = 1 << 6, + ESD_SymbolRenamingFlag = 1 << 5, + ESD_RemovableClass = 1 << 4 +}; + +enum { + ESD_Mask_ERST = 0x07, + ESD_Mask_RQW = 0x07, + ESD_Mask_TextStyle = 0xf0, + ESD_Mask_BindingAlgorithm = 0x0f, +}; + +enum ESDBAFlags { + ESD_BA_Movable = 0x01, + ESD_BA_ReadOnly = 0x2, + ESD_BA_NoPrime = 0x4, + ESD_BA_COMMON = 0x8, + ESD_BA_Indirect = 0x10, +}; + +enum RLDFlags { + RLD_Same_RID = 0x80, + RLD_Same_PID = 0x40, + RLD_Same_Offset = 0x20, + RLD_EA_Present = 0x04, + RLD_Offset_Length = 0x02, + RLD_Adressing_Mode_Sensitivity = 0x01, + RLD_FetchStore = 0x100, +}; + +} // end namespace GOFF + +// The structure of the yaml files is not an exact 1:1 match to GOFF. In order +// to use yaml::IO, we use these structures which are closer to the source. +namespace GOFFYAML { + +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDSYMBOLTYPE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDNAMESPACEID) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDFlags) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDAMODE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDRMODE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDTEXTSTYLE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDBINDINGALGORITHM) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDTASKINGBEHAVIOR) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDEXECUTABLE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDLINKAGETYPE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDBINDINGSTRENGTH) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDLOADINGBEHAVIOR) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDBINDINGSCOPE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_ESDALIGNMENT) +LLVM_YAML_STRONG_TYPEDEF(uint64_t, GOFF_BAFLAGS) + +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_TEXTRECORDSTYLE) + +LLVM_YAML_STRONG_TYPEDEF(uint16_t, GOFF_RLDFLAGS) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_RLDREFERENCETYPE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_RLDREFERENTTYPE) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, GOFF_RLDACTION) + +struct RecordBase { + enum RecordBaseKind { RBK_Relocations, RBK_Symbol, RBK_Section }; + +private: + const RecordBaseKind Kind; + +protected: + RecordBase(RecordBaseKind Kind) : Kind(Kind) {} + +public: + RecordBaseKind getKind() const { return Kind; } +}; +typedef std::unique_ptr RecordPtr; + +struct Relocation { + GOFF_RLDFLAGS Flags; + GOFF_RLDREFERENCETYPE ReferenceType; + GOFF_RLDREFERENTTYPE ReferentType; + GOFF_RLDACTION Action; + uint32_t RPointer; + uint32_t PPointer; + uint64_t Offset; + uint32_t ExtAttrID; + uint32_t ExtAttrOffset; + uint8_t TargetFieldByteLength; + uint8_t BitLength; + uint8_t BitOffset; +}; + +struct Relocations : public RecordBase { + Relocations() : RecordBase(RBK_Relocations) {} + + std::vector Relocs; + + static bool classof(const RecordBase *Rec) { + return Rec->getKind() == RBK_Relocations; + } +}; + +struct Section : public RecordBase { + Section() : RecordBase(RBK_Section) {} + + StringRef SymbolName; + uint32_t SymbolID; + uint32_t Offset; + uint32_t TrueLength; + uint16_t TextEncoding; + uint16_t DataLength; + GOFF_TEXTRECORDSTYLE TextStyle; + + std::optional Data; + + static bool classof(const RecordBase *Rec) { + return Rec->getKind() == RBK_Section; + } +}; + +struct Symbol : public RecordBase { + Symbol() : RecordBase(RBK_Symbol) {} + + StringRef Name; + GOFF_ESDSYMBOLTYPE Type; + uint32_t ID; + uint32_t OwnerID; + uint32_t Address; + uint32_t Length; + uint32_t ExtAttrID; + uint32_t ExtAttrOffset; + GOFF_ESDNAMESPACEID NameSpace; + GOFF_ESDFlags Flags; + uint8_t FillByteValue; + uint32_t PSectID; + uint32_t Priority; + std::optional Signature; + GOFF_ESDAMODE Amode; + GOFF_ESDRMODE Rmode; + GOFF_ESDTEXTSTYLE TextStyle; + GOFF_ESDBINDINGALGORITHM BindingAlgorithm; + GOFF_ESDTASKINGBEHAVIOR TaskingBehavior; + GOFF_ESDEXECUTABLE Executable; + GOFF_ESDLINKAGETYPE LinkageType; + GOFF_ESDBINDINGSTRENGTH BindingStrength; + GOFF_ESDLOADINGBEHAVIOR LoadingBehavior; + GOFF_ESDBINDINGSCOPE BindingScope; + GOFF_ESDALIGNMENT Alignment; + GOFF_BAFLAGS BAFlags; + + static bool classof(const RecordBase *Rec) { + return Rec->getKind() == RBK_Symbol; + } +}; + +struct FileHeader { + uint32_t TargetEnvironment; + uint32_t TargetOperatingSystem; + uint16_t CCSID; + StringRef CharacterSetName; + StringRef LanguageProductIdentifier; + uint32_t ArchitectureLevel; + std::optional InternalCCSID; + std::optional TargetSoftwareEnvironment; +}; + +struct Object { + FileHeader Header; + std::vector Records; + + Object(); +}; + +} // end namespace GOFFYAML + +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(GOFFYAML::Relocation) +LLVM_YAML_IS_SEQUENCE_VECTOR(GOFFYAML::RecordPtr) + +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDSYMBOLTYPE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDNAMESPACEID) +LLVM_YAML_DECLARE_BITSET_TRAITS(GOFFYAML::GOFF_ESDFlags) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDAMODE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDRMODE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDTEXTSTYLE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDBINDINGALGORITHM) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDTASKINGBEHAVIOR) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDEXECUTABLE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDLINKAGETYPE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDBINDINGSTRENGTH) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDLOADINGBEHAVIOR) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDBINDINGSCOPE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_ESDALIGNMENT) +LLVM_YAML_DECLARE_BITSET_TRAITS(GOFFYAML::GOFF_BAFLAGS) + +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_TEXTRECORDSTYLE) + +LLVM_YAML_DECLARE_BITSET_TRAITS(GOFFYAML::GOFF_RLDFLAGS) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_RLDREFERENCETYPE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_RLDREFERENTTYPE) +LLVM_YAML_DECLARE_ENUM_TRAITS(GOFFYAML::GOFF_RLDACTION) + +LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Relocation) +LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Section) +LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Symbol) +LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::FileHeader) +LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Object) + +namespace llvm { +namespace yaml { + +template <> struct CustomMappingTraits { + static void inputOne(IO &IO, StringRef Key, GOFFYAML::RecordPtr &Elem); + static void output(IO &IO, GOFFYAML::RecordPtr &Elem); +}; + +} // end namespace yaml +} // end namespace llvm + +#endif // LLVM_OBJECTYAML_GOFFYAML_H diff --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h index b63607e6796b0..7fd15cf290f4a 100644 --- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h +++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h @@ -13,6 +13,7 @@ #include "llvm/ObjectYAML/COFFYAML.h" #include "llvm/ObjectYAML/DXContainerYAML.h" #include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/ObjectYAML/GOFFYAML.h" #include "llvm/ObjectYAML/MachOYAML.h" #include "llvm/ObjectYAML/MinidumpYAML.h" #include "llvm/ObjectYAML/OffloadYAML.h" @@ -30,6 +31,7 @@ struct YamlObjectFile { std::unique_ptr Arch; std::unique_ptr Elf; std::unique_ptr Coff; + std::unique_ptr Goff; std::unique_ptr MachO; std::unique_ptr FatMachO; std::unique_ptr Minidump; diff --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h index 000da077bb18c..3b458c3cd890b 100644 --- a/llvm/include/llvm/ObjectYAML/yaml2obj.h +++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h @@ -32,6 +32,10 @@ namespace ELFYAML { struct Object; } +namespace GOFFYAML { +struct Object; +} + namespace MinidumpYAML { struct Object; } @@ -64,6 +68,7 @@ using ErrorHandler = llvm::function_ref; bool yaml2archive(ArchYAML::Archive &Doc, raw_ostream &Out, ErrorHandler EH); bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); +bool yaml2goff(GOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); bool yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH, uint64_t MaxSize); bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH); diff --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt index c081009653d4f..b36974d47d9f8 100644 --- a/llvm/lib/ObjectYAML/CMakeLists.txt +++ b/llvm/lib/ObjectYAML/CMakeLists.txt @@ -13,6 +13,8 @@ add_llvm_component_library(LLVMObjectYAML DXContainerYAML.cpp ELFEmitter.cpp ELFYAML.cpp + GOFFEmitter.cpp + GOFFYAML.cpp MachOEmitter.cpp MachOYAML.cpp ObjectYAML.cpp diff --git a/llvm/lib/ObjectYAML/GOFFEmitter.cpp b/llvm/lib/ObjectYAML/GOFFEmitter.cpp new file mode 100644 index 0000000000000..a86d9e1900da6 --- /dev/null +++ b/llvm/lib/ObjectYAML/GOFFEmitter.cpp @@ -0,0 +1,453 @@ +//===- yaml2goff - Convert YAML to a GOFF object file ---------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// The GOFF component of yaml2obj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/IndexedMap.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/Support/ConvertEBCDIC.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +static const uint8_t TXTMaxDataLength = 56; + +// Common flag values on records. +enum { + // Flag: This record is continued. + Rec_Continued = 1, + + // Flag: This record is a continuation. + Rec_Continuation = 1 << (8 - 6 - 1), +}; + +template struct BinaryBeImpl { + ValueType Value; + BinaryBeImpl(ValueType V) : Value(V) {} +}; + +template +raw_ostream &operator<<(raw_ostream &OS, const BinaryBeImpl &BBE) { + char Buffer[sizeof(BBE.Value)]; + support::endian::write( + Buffer, BBE.Value); + OS.write(Buffer, sizeof(BBE.Value)); + return OS; +} + +template BinaryBeImpl binaryBe(ValueType V) { + return BinaryBeImpl(V); +} + +struct ZerosImpl { + size_t NumBytes; +}; + +raw_ostream &operator<<(raw_ostream &OS, const ZerosImpl &Z) { + OS.write_zeros(Z.NumBytes); + return OS; +} + +ZerosImpl zeros(const size_t NumBytes) { return ZerosImpl{NumBytes}; } + +raw_ostream &operator<<(raw_ostream &OS, const yaml::BinaryRef &Data) { + Data.writeAsBinary(OS); + return OS; +} + +// The GOFFOstream is responsible to write the data into the fixed physical +// records of the format. A user of this class announces the start of a new +// logical record and the size of its payload. While writing the payload, the +// physical records are created for the data. Possible fill bytes at the end of +// a physical record are written automatically. +class GOFFOstream : public raw_ostream { + +public: + explicit GOFFOstream(raw_ostream &OS) + : OS(OS), LogicalRecords(0), RemainingSize(0), NewLogicalRecord(false) { + SetBufferSize(GOFF::PayloadLength); + } + + ~GOFFOstream() { finalize(); } + + void newRecord(GOFF::RecordType Type, size_t Size); + + void finalize() { fillRecord(); } + + uint32_t logicalRecords() { return LogicalRecords; } + +private: + /// The underlying raw_ostream. + raw_ostream &OS; + + /// The number of logical records emitted so far. + uint32_t LogicalRecords; + + /// The remaining size of this logical record, including fill + /// bytes. + size_t RemainingSize; + + /// The type of the current (logical) record. + GOFF::RecordType CurrentType; + + /// Signals start of new record. + bool NewLogicalRecord; + + // Return the number of bytes left to write until next physical record. + // Please note that we maintain the total number of bytes left, not the + // written size. + size_t bytesToNextPhysicalRecord() { + size_t Bytes = RemainingSize % GOFF::PayloadLength; + return Bytes ? Bytes : GOFF::PayloadLength; + } + + /// Write the record prefix of a physical record, using the current record + /// type. + static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type, + size_t RemainingSize, + uint8_t Flags = Rec_Continuation); + + /// Fill the last physical record of a logical record with zero bytes. + void fillRecord(); + + /// See raw_ostream::write_impl. + void write_impl(const char *Ptr, size_t Size) override; + + /// Return the current position within the stream, not counting the bytes + /// currently in the buffer. + uint64_t current_pos() const override { return OS.tell(); } +}; + +void GOFFOstream::writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type, + size_t RemainingSize, uint8_t Flags) { + uint8_t TypeAndFlags = Flags | (Type << 4); + if (RemainingSize > GOFF::RecordLength) + TypeAndFlags |= Rec_Continued; + OS << binaryBe(static_cast(GOFF::PTVPrefix)) + << binaryBe(static_cast(TypeAndFlags)) + << binaryBe(static_cast(0)); +} + +void GOFFOstream::newRecord(GOFF::RecordType Type, size_t Size) { + fillRecord(); + CurrentType = Type; + RemainingSize = Size; + if (size_t Gap = (RemainingSize % GOFF::PayloadLength)) + RemainingSize += GOFF::PayloadLength - Gap; + NewLogicalRecord = true; + ++LogicalRecords; +} + +void GOFFOstream::fillRecord() { + assert((GetNumBytesInBuffer() <= RemainingSize) && + "More bytes in buffer than expected"); + size_t Remains = RemainingSize - GetNumBytesInBuffer(); + if (Remains) { + assert((Remains < GOFF::RecordLength) && + "Attempting to fill more than one physical record"); + raw_ostream::write_zeros(Remains); + } + flush(); + assert(RemainingSize == 0 && "Not fully flushed"); + assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty"); +} + +void GOFFOstream::write_impl(const char *Ptr, size_t Size) { + assert((RemainingSize >= Size) && "Attempt to write too much data"); + assert(RemainingSize && "Logical record overflow"); + if (!(RemainingSize % GOFF::PayloadLength)) { + writeRecordPrefix(OS, CurrentType, RemainingSize, + NewLogicalRecord ? 0 : Rec_Continuation); + NewLogicalRecord = false; + } + assert(!NewLogicalRecord && + "New logical record not on physical record boundary"); + + size_t Idx = 0; + while (Size > 0) { + size_t BytesToWrite = bytesToNextPhysicalRecord(); + if (BytesToWrite > Size) + BytesToWrite = Size; + OS.write(Ptr + Idx, BytesToWrite); + Idx += BytesToWrite; + Size -= BytesToWrite; + RemainingSize -= BytesToWrite; + if (Size) { + writeRecordPrefix(OS, CurrentType, RemainingSize); + } + } +} + +class GOFFState { + void writeHeader(GOFFYAML::FileHeader &FileHdr); + void writeEnd(); + void writeSymbol(GOFFYAML::Symbol Sym); + void writeSection(GOFFYAML::Section Sec); + void writeRelocationDirectory(GOFFYAML::Relocations Rel); + + void reportError(const Twine &Msg) { + ErrHandler(Msg); + HasError = true; + } + + GOFFState(raw_ostream &OS, GOFFYAML::Object &Doc, + yaml::ErrorHandler ErrHandler) + : GW(OS), Doc(Doc), ErrHandler(ErrHandler), SymbolID(0), HasError(false) { + } + + ~GOFFState() { GW.finalize(); } + + bool writeObject(); + +public: + static bool writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc, + yaml::ErrorHandler ErrHandler); + +private: + GOFFOstream GW; + GOFFYAML::Object &Doc; + yaml::ErrorHandler ErrHandler; + uint16_t SymbolID; + bool HasError; +}; + +void GOFFState::writeHeader(GOFFYAML::FileHeader &FileHdr) { + SmallString<16> CCSIDName; + if (std::error_code EC = + ConverterEBCDIC::convertToEBCDIC(FileHdr.CharacterSetName, CCSIDName)) + reportError("Conversion error on " + FileHdr.CharacterSetName); + if (CCSIDName.size() > 16) { + reportError("CharacterSetName too long"); + CCSIDName.resize(16); + } + SmallString<16> LangProd; + if (std::error_code EC = ConverterEBCDIC::convertToEBCDIC( + FileHdr.LanguageProductIdentifier, LangProd)) + reportError("Conversion error on " + FileHdr.LanguageProductIdentifier); + if (LangProd.size() > 16) { + reportError("LanguageProductIdentifier too long"); + LangProd.resize(16); + } + + GW.newRecord(GOFF::RT_HDR, GOFF::PayloadLength); + GW << binaryBe(FileHdr.TargetEnvironment) // TargetEnvironment + << binaryBe(FileHdr.TargetOperatingSystem) // TargetOperatingSystem + << zeros(2) // Reserved + << binaryBe(FileHdr.CCSID) // CCSID + << CCSIDName // CharacterSetName + << zeros(16 - CCSIDName.size()) // Fill bytes + << LangProd // LanguageProductIdentifier + << zeros(16 - LangProd.size()) // Fill bytes + << binaryBe(FileHdr.ArchitectureLevel); // ArchitectureLevel + // The module propties are optional. Figure out if we need to write them. + uint16_t ModPropLen = 0; + if (FileHdr.TargetSoftwareEnvironment) + ModPropLen = 3; + else if (FileHdr.InternalCCSID) + ModPropLen = 2; + if (ModPropLen) { + GW << binaryBe(ModPropLen) << zeros(6); + if (ModPropLen >= 2) + GW << binaryBe(FileHdr.InternalCCSID ? *FileHdr.InternalCCSID : 0); + if (ModPropLen >= 3) + GW << binaryBe(FileHdr.TargetSoftwareEnvironment + ? *FileHdr.TargetSoftwareEnvironment + : 0); + } +} + +void GOFFState::writeSymbol(GOFFYAML::Symbol Sym) { + if (Sym.ID != SymbolID + 1) + reportError("symbol IDs not monotonic " + Sym.Name); + else + ++SymbolID; + if (Sym.OwnerID >= SymbolID) + reportError("owner ID not defined " + Sym.Name); + SmallString<80> SymName; + if (std::error_code EC = ConverterEBCDIC::convertToEBCDIC(Sym.Name, SymName)) + reportError("conversion error on " + Sym.Name); + size_t SymLength = SymName.size(); + if (SymLength > GOFF::MaxDataLength) + reportError("symbol name is too long: " + Twine(SymLength)); + + GW.newRecord(GOFF::RT_ESD, 69 + SymLength); + GW << binaryBe(Sym.Type) // Symbol type + << binaryBe(Sym.ID) // ESDID + << binaryBe(Sym.OwnerID) // Owner ESDID + << binaryBe(uint32_t(0)) // Reserved + << binaryBe(Sym.Address) // Offset/Address + << binaryBe(uint32_t(0)) // Reserved + << binaryBe(Sym.Length) // Length + << binaryBe(Sym.ExtAttrID) // Extended attributes + << binaryBe(Sym.ExtAttrOffset) // Extended attributes data offset + << binaryBe(uint32_t(0)) // Reserved + << binaryBe(Sym.NameSpace) // Namespace ID + << binaryBe(Sym.Flags) // Flags + << binaryBe(Sym.FillByteValue) // Fill byte value + << binaryBe(uint8_t(0)) // Reserved + << binaryBe(Sym.PSectID) // PSECT ID + << binaryBe(Sym.Priority); // Priority + if (Sym.Signature) + GW << *Sym.Signature; // Signature + else + GW << zeros(8); +#define BIT(E, N) (Sym.BAFlags & GOFF::E ? 1 << (7 - N) : 0) + GW << binaryBe(Sym.Amode) // Behavioral attributes - Amode + << binaryBe(Sym.Rmode) // Behavioral attributes - Rmode + << binaryBe(uint8_t(Sym.TextStyle << 4 | Sym.BindingAlgorithm)) + << binaryBe(uint8_t(Sym.TaskingBehavior << 5 | BIT(ESD_BA_Movable, 3) | + BIT(ESD_BA_ReadOnly, 4) | Sym.Executable)) + << binaryBe(uint8_t(BIT(ESD_BA_NoPrime, 1) | Sym.BindingStrength)) + << binaryBe(uint8_t(Sym.LoadingBehavior << 6 | BIT(ESD_BA_COMMON, 2) | + BIT(ESD_BA_Indirect, 3) | Sym.BindingScope)) + << binaryBe(uint8_t(Sym.LinkageType << 5 | Sym.Alignment)) + << zeros(3) // Behavioral attributes - Reserved + << binaryBe(static_cast(SymLength)) // Name length + << SymName.str(); +#undef BIT +} + +void GOFFState::writeSection(GOFFYAML::Section Sec) { + if (Sec.SymbolID == 0 || Sec.SymbolID > SymbolID) + reportError("section symbol not defined: " + Twine(Sec.SymbolID)); + + size_t Size = 0; + if (Sec.Data) { + Size = Sec.Data->binary_size(); + if (Size > GOFF::MaxDataLength) { + reportError("section content is too long: " + Twine(Size)); + return; + } + if (Sec.DataLength && Sec.DataLength != Size) { + reportError("Section content length " + Twine(Size) + + " does not match data length " + Twine(Sec.DataLength)); + return; + } + } else + Size = Sec.DataLength; + + GW.newRecord(GOFF::RT_TXT, GOFF::PayloadLength - TXTMaxDataLength + Size); + GW << binaryBe(Sec.TextStyle) // Text Record Style + << binaryBe(Sec.SymbolID) // Element ESDID + << binaryBe(uint32_t(0)) // Reserved + << binaryBe(Sec.Offset) // Offset + << binaryBe(Sec.TrueLength) // Text Field True Length + << binaryBe(Sec.TextEncoding) // Text Encoding + << binaryBe(static_cast(Size)); // Data Length + if (Sec.Data) + GW << *Sec.Data; // Data + else + GW << zeros(Size); +} + +void GOFFState::writeRelocationDirectory(GOFFYAML::Relocations Rels) { + size_t Size = 0; + for (const llvm::GOFFYAML::Relocation &Rel : Rels.Relocs) { + Size += 8; + if (!(Rel.Flags & GOFF::RLD_Same_RID)) + Size += 4; + if (!(Rel.Flags & GOFF::RLD_Same_PID)) + Size += 4; + if (!(Rel.Flags & GOFF::RLD_Same_Offset)) { + if (Rel.Flags & GOFF::RLD_Offset_Length) + Size += 8; + else + Size += 4; + } + if (Rel.Flags & GOFF::RLD_EA_Present) + Size += 8; + } + if (Size > 0xffffULL) { + reportError("Relocation directory is too large: " + Twine(Size)); + return; + } + + GW.newRecord(GOFF::RT_RLD, Size + 3); + GW << binaryBe(uint8_t(0)) // Reserved + << binaryBe(uint16_t(Size)); // Length of relocation data + for (const llvm::GOFFYAML::Relocation &Rel : Rels.Relocs) { + GW << binaryBe(uint8_t(Rel.Flags)) // Flags, byte 1 + << binaryBe(uint8_t(Rel.ReferenceType << 4 | Rel.ReferentType)) // + << binaryBe(uint8_t(Rel.Action << 1 | (Rel.Flags >> 8))) // + << zeros(1) // Reserved + << binaryBe(Rel.TargetFieldByteLength) // + << binaryBe(uint8_t(Rel.BitLength << 4 | Rel.BitOffset)) // + << zeros(2); // Reserved + if (!(Rel.Flags & GOFF::RLD_Same_RID)) + GW << binaryBe(Rel.RPointer); + if (!(Rel.Flags & GOFF::RLD_Same_PID)) + GW << binaryBe(Rel.PPointer); + if (!(Rel.Flags & GOFF::RLD_Same_Offset)) { + if (Rel.Flags & GOFF::RLD_Offset_Length) + GW << binaryBe(Rel.Offset); + else + GW << binaryBe(static_cast(Rel.Offset)); + } + if (Rel.Flags & GOFF::RLD_EA_Present) { + GW << binaryBe(Rel.ExtAttrID); + GW << binaryBe(Rel.ExtAttrOffset); + } + } +} + +void GOFFState::writeEnd() { + GW.newRecord(GOFF::RT_END, GOFF::PayloadLength); + GW << binaryBe(uint8_t(0)) // No entry point + << binaryBe(uint8_t(0)) // No AMODE + << zeros(3) // Reserved + << binaryBe(GW.logicalRecords()); + // No entry point yet. Automatically fill remaining space with zero bytes. + GW.finalize(); +} + +bool GOFFState::writeObject() { + // We follow a strict, recommended order: + // header, symbols, sections, relocations, end. + writeHeader(Doc.Header); + if (HasError) + return false; + // Iterate over all records. + for (auto &Rec : Doc.Records) { + if (auto *Rel = dyn_cast(Rec.get())) { + writeRelocationDirectory(*Rel); + } else if (auto *Sec = dyn_cast(Rec.get())) { + writeSection(*Sec); + } else if (auto *Sym = dyn_cast(Rec.get())) { + writeSymbol(*Sym); + } else { + reportError("Unknown record type"); + } + } + writeEnd(); + return true; +} + +bool GOFFState::writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc, + yaml::ErrorHandler ErrHandler) { + GOFFState State(OS, Doc, ErrHandler); + return State.writeObject(); +} +} // namespace + +namespace llvm { +namespace yaml { + +bool yaml2goff(llvm::GOFFYAML::Object &Doc, raw_ostream &Out, + ErrorHandler ErrHandler) { + return GOFFState::writeGOFF(Out, Doc, ErrHandler); +} + +} // namespace yaml +} // namespace llvm diff --git a/llvm/lib/ObjectYAML/GOFFYAML.cpp b/llvm/lib/ObjectYAML/GOFFYAML.cpp new file mode 100644 index 0000000000000..51d176c69a154 --- /dev/null +++ b/llvm/lib/ObjectYAML/GOFFYAML.cpp @@ -0,0 +1,375 @@ +//===-- GOFFYAML.cpp - GOFF YAMLIO implementation ---------------*- 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 defines classes for handling the YAML representation of GOFF. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ObjectYAML/GOFFYAML.h" +#include "llvm/BinaryFormat/GOFF.h" +#include + +namespace llvm { +namespace GOFFYAML { + +Object::Object() { memset(&Header, 0, sizeof(Header)); } + +} // namespace GOFFYAML + +namespace yaml { + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDSYMBOLTYPE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_ST_SectionDefinition); + ECase(ESD_ST_ElementDefinition); + ECase(ESD_ST_LabelDefinition); + ECase(ESD_ST_PartReference); + ECase(ESD_ST_ExternalReference); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDNAMESPACEID &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_NS_ProgramManagementBinder); + ECase(ESD_NS_NormalName); + ECase(ESD_NS_PseudoRegister); + ECase(ESD_NS_Parts); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarBitSetTraits::bitset( + IO &IO, GOFFYAML::GOFF_ESDFlags &Value) { +#define BCase(X) IO.bitSetCase(Value, #X, GOFF::X) +#define BCaseMask(X, M) IO.maskedBitSetCase(Value, #X, GOFF::X, GOFF::M) + BCase(ESD_FillByteValuePresent); + BCase(ESD_SymbolDisplayFlag); + BCase(ESD_SymbolRenamingFlag); + BCase(ESD_RemovableClass); + BCaseMask(ESD_RQ_0, ESD_Mask_RQW); + BCaseMask(ESD_RQ_1, ESD_Mask_RQW); + BCaseMask(ESD_RQ_2, ESD_Mask_RQW); + BCaseMask(ESD_RQ_3, ESD_Mask_RQW); +#undef BCase +#undef BCaseMask +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_TEXTRECORDSTYLE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(TXT_RS_Byte); + ECase(TXT_RS_Structured); + ECase(TXT_RS_Unstructured); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDAMODE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_AMODE_None); + ECase(ESD_AMODE_24); + ECase(ESD_AMODE_31); + ECase(ESD_AMODE_ANY); + ECase(ESD_AMODE_64); + ECase(ESD_AMODE_MIN); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDRMODE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_RMODE_None); + ECase(ESD_RMODE_24); + ECase(ESD_RMODE_31); + ECase(ESD_RMODE_64); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDTEXTSTYLE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_TS_ByteOriented); + ECase(ESD_TS_Structured); + ECase(ESD_TS_Unstructured); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDBINDINGALGORITHM &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_BA_Concatenate); + ECase(ESD_BA_Merge); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDTASKINGBEHAVIOR &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_TA_Unspecified); + ECase(ESD_TA_NonReus); + ECase(ESD_TA_Reus); + ECase(ESD_TA_Rent); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDEXECUTABLE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_EXE_Unspecified); + ECase(ESD_EXE_DATA); + ECase(ESD_EXE_CODE); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDLINKAGETYPE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_LT_OS); + ECase(ESD_LT_XPLink); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDBINDINGSTRENGTH &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_BST_Strong); + ECase(ESD_BST_Weak); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDLOADINGBEHAVIOR &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_LB_Initial); + ECase(ESD_LB_Deferred); + ECase(ESD_LB_NoLoad); + ECase(ESD_LB_Reserved); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDBINDINGSCOPE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_BSC_Unspecified); + ECase(ESD_BSC_Section); + ECase(ESD_BSC_Module); + ECase(ESD_BSC_Library); + ECase(ESD_BSC_ImportExport); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_ESDALIGNMENT &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(ESD_ALIGN_Byte); + ECase(ESD_ALIGN_Halfword); + ECase(ESD_ALIGN_Fullword); + ECase(ESD_ALIGN_Doubleword); + ECase(ESD_ALIGN_Quadword); + ECase(ESD_ALIGN_32byte); + ECase(ESD_ALIGN_64byte); + ECase(ESD_ALIGN_128byte); + ECase(ESD_ALIGN_256byte); + ECase(ESD_ALIGN_512byte); + ECase(ESD_ALIGN_1024byte); + ECase(ESD_ALIGN_2Kpage); + ECase(ESD_ALIGN_4Kpage); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarBitSetTraits::bitset( + IO &IO, GOFFYAML::GOFF_BAFLAGS &Value) { +#define BCase(X) IO.bitSetCase(Value, #X, GOFF::X) +#define BCaseMask(X, M) IO.maskedBitSetCase(Value, #X, GOFF::X, GOFF::M) + BCase(ESD_BA_Movable); + BCase(ESD_BA_ReadOnly); + BCase(ESD_BA_NoPrime); + BCase(ESD_BA_COMMON); + BCase(ESD_BA_Indirect); +#undef BCase +#undef BCaseMask +} + +void ScalarBitSetTraits::bitset( + IO &IO, GOFFYAML::GOFF_RLDFLAGS &Value) { +#define BCase(X) IO.bitSetCase(Value, #X, GOFF::X) +#define BCaseMask(X, M) IO.maskedBitSetCase(Value, #X, GOFF::X, GOFF::M) + BCase(RLD_Same_RID); + BCase(RLD_Same_PID); + BCase(RLD_Same_Offset); + BCase(RLD_EA_Present); + BCase(RLD_Offset_Length); + BCase(RLD_Adressing_Mode_Sensitivity); + BCase(RLD_FetchStore); +#undef BCase +#undef BCaseMask +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_RLDREFERENCETYPE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(RLD_RT_RAddress); + ECase(RLD_RT_ROffset); + ECase(RLD_RT_RLength); + ECase(RLD_RT_RRelativeImmediate); + ECase(RLD_RT_RTypeConstant); + ECase(RLD_RT_RLongDisplacement); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_RLDREFERENTTYPE &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(RLD_RO_Label); + ECase(RLD_RO_Element); + ECase(RLD_RO_Class); + ECase(RLD_RO_Part); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, GOFFYAML::GOFF_RLDACTION &Value) { +#define ECase(X) IO.enumCase(Value, #X, GOFF::X) + ECase(RLD_ACT_Add); + ECase(RLD_ACT_Subtract); +#undef ECase + IO.enumFallback(Value); +} + +void MappingTraits::mapping(IO &IO, + GOFFYAML::Relocation &Rel) { + IO.mapRequired("Flags", Rel.Flags); + IO.mapRequired("ReferenceType", Rel.ReferenceType); + IO.mapRequired("ReferentType", Rel.ReferentType); + IO.mapRequired("Action", Rel.Action); + IO.mapRequired("TargetFieldByteLength", Rel.TargetFieldByteLength); + IO.mapRequired("BitLength", Rel.BitLength); + IO.mapRequired("BitOffset", Rel.BitOffset); + if (!(Rel.Flags & GOFF::RLD_Same_RID)) + IO.mapRequired("RPointer", Rel.RPointer); + if (!(Rel.Flags & GOFF::RLD_Same_PID)) + IO.mapRequired("PPointer", Rel.PPointer); + if (!(Rel.Flags & GOFF::RLD_Same_Offset)) + IO.mapRequired("Offset", Rel.Offset); + if (Rel.Flags & GOFF::RLD_EA_Present) { + IO.mapOptional("ExtAttrID", Rel.ExtAttrID, 0); + IO.mapOptional("ExtAttrOffset", Rel.ExtAttrOffset, 0); + } +} + +void MappingTraits::mapping(IO &IO, GOFFYAML::Section &Sec) { + IO.mapRequired("SymbolName", Sec.SymbolName); + IO.mapRequired("SymbolID", Sec.SymbolID); + IO.mapOptional("Offset", Sec.Offset, 0); + IO.mapOptional("TrueLength", Sec.TrueLength, 0); + IO.mapOptional("TextEncoding", Sec.TextEncoding, 0); + IO.mapOptional("DataLength", Sec.DataLength, 0); + IO.mapOptional("TextStyle", Sec.TextStyle, GOFF::TXT_RS_Byte); + IO.mapOptional("Data", Sec.Data); +} + +void MappingTraits::mapping(IO &IO, GOFFYAML::Symbol &Sym) { + IO.mapRequired("Name", Sym.Name); + IO.mapRequired("Type", Sym.Type); + IO.mapRequired("ID", Sym.ID); + IO.mapOptional("OwnerID", Sym.OwnerID, 0); + IO.mapOptional("Address", Sym.Address, 0); + IO.mapOptional("Length", Sym.Length, 0); + IO.mapOptional("ExtAttrID", Sym.ExtAttrID, 0); + IO.mapOptional("ExtAttrOffset", Sym.ExtAttrOffset, 0); + IO.mapRequired("NameSpace", Sym.NameSpace); + IO.mapOptional("Flags", Sym.Flags, GOFFYAML::GOFF_ESDFlags(0)); + IO.mapOptional("FillByteValue", Sym.FillByteValue, 0); + IO.mapOptional("PSectID", Sym.PSectID, 0); + IO.mapOptional("Priority", Sym.Priority, 0); + IO.mapOptional("Signature", Sym.Signature); + IO.mapOptional("Amode", Sym.Amode, GOFF::ESD_AMODE_None); + IO.mapOptional("Rmode", Sym.Rmode, GOFF::ESD_RMODE_None); + IO.mapOptional("TextStyle", Sym.TextStyle, GOFF::ESD_TS_ByteOriented); + IO.mapOptional("BindingAlgorithm", Sym.BindingAlgorithm, + GOFF::ESD_BA_Concatenate); + IO.mapOptional("TaskingBehavior", Sym.TaskingBehavior, + GOFF::ESD_TA_Unspecified); + IO.mapOptional("Executable", Sym.Executable, GOFF::ESD_EXE_Unspecified); + IO.mapOptional("LinkageType", Sym.LinkageType, GOFF::ESD_LT_OS); + IO.mapOptional("BindingStrength", Sym.BindingStrength, GOFF::ESD_BST_Strong); + IO.mapOptional("LoadingBehavior", Sym.LoadingBehavior, GOFF::ESD_LB_Initial); + IO.mapOptional("BindingScope", Sym.BindingScope, GOFF::ESD_BSC_Unspecified); + IO.mapOptional("Alignment", Sym.Alignment, GOFF::ESD_ALIGN_Byte); + IO.mapOptional("BAFlags", Sym.BAFlags, 0); +} + +void MappingTraits::mapping( + IO &IO, GOFFYAML::FileHeader &FileHdr) { + IO.mapOptional("TargetEnvironment", FileHdr.TargetEnvironment, 0); + IO.mapOptional("TargetOperatingSystem", FileHdr.TargetOperatingSystem, 0); + IO.mapOptional("CCSID", FileHdr.CCSID, 0); + IO.mapOptional("CharacterSetName", FileHdr.CharacterSetName, ""); + IO.mapOptional("LanguageProductIdentifier", FileHdr.LanguageProductIdentifier, + ""); + IO.mapOptional("ArchitectureLevel", FileHdr.ArchitectureLevel, 1); + IO.mapOptional("InternalCCSID", FileHdr.InternalCCSID); + IO.mapOptional("TargetSoftwareEnvironment", + FileHdr.TargetSoftwareEnvironment); +} + +void CustomMappingTraits::inputOne( + IO &IO, StringRef Key, GOFFYAML::RecordPtr &Elem) { + if (Key == "Relocations") { + GOFFYAML::Relocations Rel; + IO.mapRequired("Relocations", Rel.Relocs); + Elem = std::make_unique(std::move(Rel)); + } else if (Key == "Section") { + GOFFYAML::Section Sec; + IO.mapRequired("Section", Sec); + Elem = std::make_unique(std::move(Sec)); + } else if (Key == "Symbol") { + GOFFYAML::Symbol Sym; + IO.mapRequired("Symbol", Sym); + Elem = std::make_unique(std::move(Sym)); + } +} + +void CustomMappingTraits::output( + IO &IO, GOFFYAML::RecordPtr &Elem) { + if (auto *Rel = dyn_cast(Elem.get())) { + IO.mapRequired("Relocations", Rel->Relocs); + } else if (auto *Sec = dyn_cast(Elem.get())) { + IO.mapRequired("Section", *Sec); + } else if (auto *Sym = dyn_cast(Elem.get())) { + IO.mapRequired("Symbol", *Sym); + } else { + IO.setError("Unknown record type"); + } +} + +void MappingTraits::mapping(IO &IO, GOFFYAML::Object &Obj) { + IO.mapTag("!GOFF", true); + IO.mapRequired("FileHeader", Obj.Header); + IO.mapRequired("Records", Obj.Records); +} + +} // namespace yaml +} // namespace llvm diff --git a/llvm/lib/ObjectYAML/ObjectYAML.cpp b/llvm/lib/ObjectYAML/ObjectYAML.cpp index d57e5583016b5..1815eaff8e36d 100644 --- a/llvm/lib/ObjectYAML/ObjectYAML.cpp +++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp @@ -26,6 +26,8 @@ void MappingTraits::mapping(IO &IO, MappingTraits::mapping(IO, *ObjectFile.Elf); if (ObjectFile.Coff) MappingTraits::mapping(IO, *ObjectFile.Coff); + if (ObjectFile.Goff) + MappingTraits::mapping(IO, *ObjectFile.Goff); if (ObjectFile.MachO) MappingTraits::mapping(IO, *ObjectFile.MachO); if (ObjectFile.FatMachO) @@ -46,6 +48,9 @@ void MappingTraits::mapping(IO &IO, } else if (IO.mapTag("!COFF")) { ObjectFile.Coff.reset(new COFFYAML::Object()); MappingTraits::mapping(IO, *ObjectFile.Coff); + } else if (IO.mapTag("!GOFF")) { + ObjectFile.Goff.reset(new GOFFYAML::Object()); + MappingTraits::mapping(IO, *ObjectFile.Goff); } else if (IO.mapTag("!mach-o")) { ObjectFile.MachO.reset(new MachOYAML::Object()); MappingTraits::mapping(IO, *ObjectFile.MachO); diff --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp index 06050e246fbff..b9a9ad6397099 100644 --- a/llvm/lib/ObjectYAML/yaml2obj.cpp +++ b/llvm/lib/ObjectYAML/yaml2obj.cpp @@ -38,6 +38,8 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler, return yaml2elf(*Doc.Elf, Out, ErrHandler, MaxSize); if (Doc.Coff) return yaml2coff(*Doc.Coff, Out, ErrHandler); + if (Doc.Goff) + return yaml2goff(*Doc.Goff, Out, ErrHandler); if (Doc.MachO || Doc.FatMachO) return yaml2macho(Doc, Out, ErrHandler); if (Doc.Minidump) diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-Basic.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-Basic.yaml new file mode 100644 index 0000000000000..1395bb1fdf264 --- /dev/null +++ b/llvm/test/ObjectYAML/GOFF/GOFF-Basic.yaml @@ -0,0 +1,59 @@ +# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s + +--- !GOFF +FileHeader: + ArchitectureLevel: 1 +Records: +# Bytes 80-159 +# CHECK: 03 00 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 00 +# CHECK: 00 00 00 00 00 00 00 04 88 89 7b c3 00 00 00 00 + - Symbol: + Name: 'hi#C' + Type: ESD_ST_SectionDefinition + ID: 1 + OwnerID: 0 + Address: 0 + Length: 0 + NameSpace: ESD_NS_ProgramManagementBinder +# Bytes 160-239 +# 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 81 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 03 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + - Symbol: + Name: 'C_WSA64' + Type: ESD_ST_ElementDefinition + ID: 2 + OwnerID: 1 + NameSpace: ESD_NS_Parts + Flags: [ ESD_FillByteValuePresent, ESD_RQ_1 ] + FillByteValue: 0 + Amode: ESD_AMODE_64 + Rmode: ESD_RMODE_64 + BindingAlgorithm: ESD_BA_Merge + Executable: ESD_EXE_DATA + LoadingBehavior: ESD_LB_Deferred + Alignment: ESD_ALIGN_Doubleword +# Bytes 240-319 +# CHECK: 03 00 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 02 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 00 00 00 01 +# CHECK: 00 01 24 00 00 00 00 04 88 89 7b e2 00 00 00 00 + - Symbol: + Name: 'hi#S' + Type: ESD_ST_PartReference + ID: 3 + OwnerID: 2 + Address: 0 + Length: 2 + NameSpace: ESD_NS_Parts + LinkageType: ESD_LT_XPLink + Alignment: ESD_ALIGN_Quadword + BindingScope: ESD_BSC_Section + Executable: ESD_EXE_DATA + diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-LongSymbol.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-LongSymbol.yaml new file mode 100644 index 0000000000000..650931dd0e1f5 --- /dev/null +++ b/llvm/test/ObjectYAML/GOFF/GOFF-LongSymbol.yaml @@ -0,0 +1,92 @@ +# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s + + +--- !GOFF +FileHeader: + ArchitectureLevel: 1 +Records: +# Bytes 80-159 +# Bits 06-07 of Byte 2 should be set to 01 to indicate that this +# is an "initial record" and it will be continued on the subsequent +# record. +# 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 00 +# CHECK: 00 00 00 00 00 00 00 39 88 89 a3 88 89 a2 89 a2 +# Bytes 160-239 +# Bits 06-07 of Byte 2 are set to 10 to indicate that this is +# a continuation record, and it is not continued on the next +# record. +# CHECK: 03 02 00 81 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 +# CHECK: a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 +# CHECK: a5 85 99 a8 93 96 95 87 a2 a8 94 82 96 93 95 81 +# CHECK: 94 85 7b c3 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 + - Symbol: + Name: 'hithisisaveryveryveryveryveryveryveryverylongsymbolname#C' + Type: ESD_ST_SectionDefinition + ID: 1 + OwnerID: 0 + Address: 0 + Length: 0 + NameSpace: ESD_NS_ProgramManagementBinder +# 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 81 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 03 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + - Symbol: + Name: 'C_WSA64' + Type: ESD_ST_ElementDefinition + ID: 2 + OwnerID: 1 + NameSpace: ESD_NS_Parts + Flags: [ ESD_FillByteValuePresent, ESD_RQ_1 ] + FillByteValue: 0 + Amode: ESD_AMODE_64 + Rmode: ESD_RMODE_64 + BindingAlgorithm: ESD_BA_Merge + Executable: ESD_EXE_DATA + LoadingBehavior: ESD_LB_Deferred + Alignment: ESD_ALIGN_Doubleword +# Symbol spanning 4 records. First record's second byte +# ends in 01 indicating that it is continued. +# CHECK: 03 01 00 03 00 00 00 03 00 00 00 01 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 00 00 00 01 +# CHECK: 00 00 02 00 00 00 00 cf 93 96 95 87 a2 a8 94 82 +# Second record's second byte ends in 11 indicating that it +# is continued, and it itself is a continuation. +# CHECK: 03 03 00 96 93 95 96 a3 a2 88 96 99 a3 a3 88 89 +# CHECK: a2 89 a2 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 +# CHECK: 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 +# CHECK: 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 +# CHECK: 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 +# Third record's second byte ends in 11 indicating that it +# is continued, and it itself is a continuation. +# CHECK: 03 03 00 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 +# CHECK: 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 +# CHECK: 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 99 a8 a5 85 +# CHECK: 99 a8 a5 85 99 a8 93 96 95 87 89 95 86 81 83 a3 +# CHECK: a3 88 89 a2 89 a2 85 a5 85 95 93 96 95 87 85 99 +# Fourth record's second byte ends in 10 indicating that it +# is not continued, but the record itself is a continuation. +# CHECK: 03 02 00 a3 88 81 95 a3 88 85 97 99 85 a5 89 96 +# CHECK: a4 a2 a2 a8 94 82 96 93 a6 88 89 83 88 a6 81 a2 +# CHECK: 98 a4 89 a3 85 93 96 95 87 81 93 99 85 81 84 a8 +# 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 + + - Symbol: + Name: 'longsymbolnotshortthisisveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryverylonginfactthisisevenlongerthantheprevioussymbolwhichwasquitelongalready' + Type: ESD_ST_PartReference + ID: 3 + OwnerID: 1 + Address: 0 + Length: 4 + NameSpace: ESD_NS_Parts + Alignment: ESD_ALIGN_Fullword + Executable: ESD_EXE_DATA + diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-OneSymb.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-OneSymb.yaml new file mode 100644 index 0000000000000..c565cba6dc787 --- /dev/null +++ b/llvm/test/ObjectYAML/GOFF/GOFF-OneSymb.yaml @@ -0,0 +1,40 @@ +# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s + +# Verify that GOFF Header is correct. +# 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 01 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 + +# Verify that the symbol is written correctly. +# CHECK: 03 00 00 01 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 01 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 + +# Verify GOFF Module end. +# CHECK: 03 40 00 00 00 00 00 00 00 00 00 03 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 + + + +--- !GOFF +FileHeader: + ArchitectureLevel: 1 +Records: + - Symbol: + Name: 'x' + Type: ESD_ST_ElementDefinition + ID: 1 + OwnerID: 0 + Address: 0 + Length: 0 + NameSpace: ESD_NS_NormalName + Flags: [] + FillByteValue: 0 + diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-Relocation.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-Relocation.yaml new file mode 100644 index 0000000000000..2ded36145202d --- /dev/null +++ b/llvm/test/ObjectYAML/GOFF/GOFF-Relocation.yaml @@ -0,0 +1,145 @@ +# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s + +--- !GOFF +FileHeader: + CharacterSetName: 'IBM-1047' + ArchitectureLevel: 1 +Records: +# CHECK: 03 00 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 01 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 + - Symbol: + Name: 'x' + Type: ESD_ST_SectionDefinition + ID: 1 + NameSpace: ESD_NS_NormalName +# 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 81 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 03 00 00 00 00 07 c3 6d e6 e2 c1 f6 f4 00 + - Symbol: + Name: 'C_WSA64' + Type: ESD_ST_ElementDefinition + ID: 2 + OwnerID: 1 + NameSpace: ESD_NS_Parts + Flags: [ ESD_FillByteValuePresent, ESD_RQ_1 ] + FillByteValue: 0 + Amode: ESD_AMODE_64 + Rmode: ESD_RMODE_64 + BindingAlgorithm: ESD_BA_Merge + Executable: ESD_EXE_DATA + LoadingBehavior: ESD_LB_Deferred + Alignment: ESD_ALIGN_Doubleword +# CHECK: 03 00 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 04 00 00 00 00 +# CHECK: 00 00 00 00 00 00 00 00 03 20 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 20 00 00 00 00 00 01 a7 00 00 00 00 00 00 00 + - Symbol: + Name: 'x' + Type: ESD_ST_PartReference + ID: 3 + OwnerID: 2 + Length: 4 + NameSpace: ESD_NS_Parts + Flags: [ ESD_SymbolRenamingFlag ] + Amode: ESD_AMODE_64 + Executable: ESD_EXE_DATA + BAFlags: [ ESD_BA_COMMON ] +# A TXT Record. Byte 1, bits 0-3 should be 0001. +# CHECK: 03 10 00 00 00 00 00 03 00 00 00 00 00 00 00 00 +# CHECK: 00 00 00 00 00 00 00 08 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 + - Section: + SymbolName: 'x' + SymbolID: 3 + DataLength: 8 +# Record with a Relocation Dictionary is indicated by byte 1, +# bits 0-3 should be 0010. +# We have four data items. The first is missing the extended +# attribute fields/offset so it has a length of 20 bytes. +# The second has the RLD_Same_Offset flag so the offset field +# isn't present, meaning it is 16 bytes. The third has the +# RLD_SAME_PID flag in addition, and the fourth has the +# RLD_SAME_RID flag in addition to the flags on the third +# data item so they are 12 and 8 bytes respectively, so +# the expected length of data items are 20+16+12+8 = 0x38. +# CHECK: 03 20 00 00 00 38 00 71 02 00 01 44 00 00 00 00 +# CHECK: 00 03 00 00 00 03 00 00 00 05 20 71 02 00 01 44 +# CHECK: 00 00 00 00 00 03 00 00 00 03 60 71 02 00 01 44 +# CHECK: 00 00 00 00 00 03 e0 71 02 00 01 44 00 00 00 00 +# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + - Relocations: + - Flags: [] + ReferenceType: RLD_RT_RTypeConstant + ReferentType: RLD_RO_Element + Action: RLD_ACT_Subtract + TargetFieldByteLength: 1 + BitLength: 4 + BitOffset: 4 + RPointer: 3 + PPointer: 3 + Offset: 5 + - Flags: [RLD_Same_Offset] + ReferenceType: RLD_RT_RTypeConstant + ReferentType: RLD_RO_Element + Action: RLD_ACT_Subtract + TargetFieldByteLength: 1 + BitLength: 4 + BitOffset: 4 + RPointer: 3 + PPointer: 3 + - Flags: [RLD_Same_Offset,RLD_Same_PID] + ReferenceType: RLD_RT_RTypeConstant + ReferentType: RLD_RO_Element + Action: RLD_ACT_Subtract + TargetFieldByteLength: 1 + BitLength: 4 + BitOffset: 4 + RPointer: 3 + - Flags: [RLD_Same_Offset,RLD_Same_PID,RLD_Same_RID] + ReferenceType: RLD_RT_RTypeConstant + ReferentType: RLD_RO_Element + Action: RLD_ACT_Subtract + TargetFieldByteLength: 1 + BitLength: 4 + BitOffset: 4 +# Relocation Dictionary with two data items. First data item has +# extended attributes so it has the maximal data size of 28 bytes. +# Second data item has different RID, PID, and offset as previous item +# so it has data size of 20, so expected data size is 28 + 20 + 48 = 0x30. +# CHECK: 03 20 00 00 00 30 04 71 02 00 01 44 00 00 00 00 +# CHECK: 00 03 00 00 00 03 00 00 00 0a 00 00 00 01 00 00 +# CHECK: 00 06 00 71 02 00 01 44 00 00 00 00 00 02 00 00 +# CHECK: 00 02 00 00 00 05 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 + - Relocations: + - Flags: [RLD_EA_Present] + ReferenceType: RLD_RT_RTypeConstant + ReferentType: RLD_RO_Element + Action: RLD_ACT_Subtract + TargetFieldByteLength: 1 + BitLength: 4 + BitOffset: 4 + RPointer: 3 + PPointer: 3 + Offset: 10 + ExtAttrID: 1 + ExtAttrOffset: 6 + - Flags: [] + ReferenceType: RLD_RT_RTypeConstant + ReferentType: RLD_RO_Element + Action: RLD_ACT_Subtract + TargetFieldByteLength: 1 + BitLength: 4 + BitOffset: 4 + RPointer: 2 + PPointer: 2 + Offset: 5 +... diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-TXTSection.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-TXTSection.yaml new file mode 100644 index 0000000000000..3336c452bcaef --- /dev/null +++ b/llvm/test/ObjectYAML/GOFF/GOFF-TXTSection.yaml @@ -0,0 +1,49 @@ +# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s + +--- !GOFF +FileHeader: + ArchitectureLevel: 1 +Records: + - Symbol: + Name: 'var#c' + Type: ESD_ST_SectionDefinition + ID: 1 + NameSpace: ESD_NS_ProgramManagementBinder + - Symbol: + Name: C_CODE64 + Type: ESD_ST_ElementDefinition + ID: 2 + OwnerID: 1 + Length: 8 + NameSpace: ESD_NS_NormalName + Flags: [ ESD_FillByteValuePresent ] + FillByteValue: 0 + Amode: ESD_AMODE_64 + Rmode: ESD_RMODE_64 + Executable: ESD_EXE_CODE + Alignment: ESD_ALIGN_Doubleword + BAFlags: [ ESD_BA_ReadOnly ] + - Symbol: + Name: 'var#c' + Type: ESD_ST_LabelDefinition + ID: 3 + OwnerID: 2 + NameSpace: ESD_NS_ProgramManagementBinder +# TXT Records' byte 1, bits 0-3 should be 0001. +# Byte 3, bits 4-7 represent Text Record Style, with 0000 +# for byte-oriented data. +# Note: DataLength field is 8, so despite Data field being a +# string of length greater than 8, there are only 8 bytes of +# data represented. +# CHECK: 03 10 00 00 00 00 00 02 00 00 00 00 00 00 00 00 +# CHECK: 00 00 00 00 00 00 00 08 12 34 56 78 9a bc de f0 +# 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 + - Section: + SymbolName: C_CODE64 + SymbolID: 2 + TextStyle: TXT_RS_Byte + DataLength: 8 + Data: "123456789ABCDEF0" +...