diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h --- a/llvm/include/llvm/BinaryFormat/GOFF.h +++ b/llvm/include/llvm/BinaryFormat/GOFF.h @@ -10,6 +10,8 @@ // constants for the GOFF file format. // // GOFF specifics can be found in MVS Program Management: Advanced Facilities. +// See +// https://www.ibm.com/docs/en/zos/3.1.0?topic=facilities-generalized-object-file-format-goff // //===----------------------------------------------------------------------===// @@ -19,13 +21,24 @@ #include "llvm/Support/DataTypes.h" namespace llvm { + namespace GOFF { +/// \brief Length of the parts of a physical GOFF record. constexpr uint8_t RecordLength = 80; constexpr uint8_t RecordPrefixLength = 3; constexpr uint8_t PayloadLength = 77; +constexpr uint8_t RecordContentLength = RecordLength - RecordPrefixLength; + +/// \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 32K-1 bytes. +constexpr uint16_t MaxDataLength = 32 * 1024 - 1; -// Prefix byte on every record. This indicates GOFF format. +/// \brief Prefix byte on every record. This indicates GOFF format. constexpr uint8_t PTVPrefix = 0x03; enum RecordType : uint8_t { diff --git a/llvm/include/llvm/MC/MCGOFFObjectWriter.h b/llvm/include/llvm/MC/MCGOFFObjectWriter.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCGOFFObjectWriter.h @@ -0,0 +1,42 @@ +//===- MCGOFFObjectWriter.h - GOFF Object Writer ----------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCGOFFOBJECTWRITER_H +#define LLVM_MC_MCGOFFOBJECTWRITER_H + +#include "llvm/MC/MCObjectWriter.h" + +namespace llvm { +class MCObjectWriter; +class raw_pwrite_stream; + +class MCGOFFObjectTargetWriter : public MCObjectTargetWriter { +protected: + MCGOFFObjectTargetWriter() = default; + +public: + virtual ~MCGOFFObjectTargetWriter() = default; + + Triple::ObjectFormatType getFormat() const override { return Triple::GOFF; } + + static bool classof(const MCObjectTargetWriter *W) { + return W->getFormat() == Triple::GOFF; + } +}; + +/// \brief Construct a new GOFF writer instance. +/// +/// \param MOTW - The target-specific GOFF writer subclass. +/// \param OS - The stream to write to. +/// \returns The constructed object writer. +std::unique_ptr +createGOFFObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS); +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCGOFFStreamer.h @@ -0,0 +1,40 @@ +//===- MCGOFFStreamer.h - MCStreamer GOFF Object File Interface--*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCGOFFSTREAMER_H +#define LLVM_MC_MCGOFFSTREAMER_H + +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCObjectWriter.h" + +namespace llvm { + +class MCGOFFStreamer : public MCObjectStreamer { +public: + MCGOFFStreamer(MCContext &Context, std::unique_ptr MAB, + std::unique_ptr OW, + std::unique_ptr Emitter) + : MCObjectStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)) {} + + ~MCGOFFStreamer() override; + + bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { + return false; + } + void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + Align ByteAlignment) override {} + void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override {} + void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, Align ByteAlignment = Align(1), + SMLoc Loc = SMLoc()) override {} +}; + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h --- a/llvm/include/llvm/MC/TargetRegistry.h +++ b/llvm/include/llvm/MC/TargetRegistry.h @@ -94,6 +94,11 @@ std::unique_ptr &&OW, std::unique_ptr &&CE, bool RelaxAll); +MCStreamer *createGOFFStreamer(MCContext &Ctx, + std::unique_ptr &&TAB, + std::unique_ptr &&OW, + std::unique_ptr &&CE, + bool RelaxAll); MCStreamer *createMachOStreamer(MCContext &Ctx, std::unique_ptr &&TAB, std::unique_ptr &&OW, @@ -195,6 +200,10 @@ std::unique_ptr &&TAB, std::unique_ptr &&OW, std::unique_ptr &&Emitter, bool RelaxAll); + using GOFFStreamerCtorTy = + MCStreamer *(*)(MCContext &Ctx, std::unique_ptr &&TAB, + std::unique_ptr &&OW, + std::unique_ptr &&Emitter, bool RelaxAll); using MachOStreamerCtorTy = MCStreamer *(*)(MCContext &Ctx, std::unique_ptr &&TAB, std::unique_ptr &&OW, @@ -327,6 +336,7 @@ // Construction functions for the various object formats, if registered. COFFStreamerCtorTy COFFStreamerCtorFn = nullptr; + GOFFStreamerCtorTy GOFFStreamerCtorFn = nullptr; MachOStreamerCtorTy MachOStreamerCtorFn = nullptr; ELFStreamerCtorTy ELFStreamerCtorFn = nullptr; WasmStreamerCtorTy WasmStreamerCtorFn = nullptr; @@ -597,7 +607,13 @@ std::move(Emitter), RelaxAll); break; case Triple::GOFF: - report_fatal_error("GOFF MCObjectStreamer not implemented yet"); + if (GOFFStreamerCtorFn) + S = GOFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + else + S = createGOFFStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + break; case Triple::XCOFF: if (XCOFFStreamerCtorFn) S = XCOFFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), @@ -1004,6 +1020,10 @@ T.COFFStreamerCtorFn = Fn; } + static void RegisterGOFFStreamer(Target &T, Target::GOFFStreamerCtorTy Fn) { + T.GOFFStreamerCtorFn = Fn; + } + static void RegisterMachOStreamer(Target &T, Target::MachOStreamerCtorTy Fn) { T.MachOStreamerCtorFn = Fn; } diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt --- a/llvm/lib/MC/CMakeLists.txt +++ b/llvm/lib/MC/CMakeLists.txt @@ -2,6 +2,7 @@ ConstantPools.cpp DXContainerPSVInfo.cpp ELFObjectWriter.cpp + GOFFObjectWriter.cpp MCAsmBackend.cpp MCAsmInfo.cpp MCAsmInfoCOFF.cpp @@ -23,6 +24,7 @@ MCELFStreamer.cpp MCExpr.cpp MCFragment.cpp + MCGOFFStreamer.cpp MCInst.cpp MCInstPrinter.cpp MCInstrAnalysis.cpp diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/GOFFObjectWriter.cpp @@ -0,0 +1,296 @@ +//===- lib/MC/GOFFObjectWriter.cpp - GOFF File Writer ---------------------===// +// +// 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 implements GOFF object file writer information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/GOFF.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCGOFFObjectWriter.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "goff-writer" + +namespace { + +// The standard System/390 convention is to name the high-order (leftmost) bit +// in a byte as bit zero. The Flags type helps to set bits in a byte according +// to this numeration order. +class Flags { + uint8_t Val; + + constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value, + uint8_t OldValue) { + assert(BitIndex < 8 && "Bit index out of bounds!"); + assert(Length + BitIndex <= 8 && "Bit length too long!"); + + uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length); + Value = Value << (8 - BitIndex - Length); + assert((Value & Mask) == Value && "Bits set outside of range!"); + + return (OldValue & ~Mask) | Value; + } + +public: + constexpr Flags() : Val(0) {} + constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value) + : Val(bits(BitIndex, Length, Value, 0)) {} + + void set(uint8_t BitIndex, uint8_t Length, uint8_t Value) { + Val = bits(BitIndex, Length, Value, Val); + } + + constexpr operator uint8_t() const { return Val; } +}; + +// Common flag values on records. + +// Flag: This record is continued. +constexpr uint8_t RecContinued = Flags(7, 1, 1); + +// Flag: This record is a continuation. +constexpr uint8_t RecContinuation = Flags(6, 1, 1); + +// The GOFFOstream is responsible to write the data into the fixed physical +// records of the format. A user of this class announces the start of a new +// logical record and the size of its content. While writing the content, the +// physical records are created for the data. Possible fill bytes at the end of +// a physical record are written automatically. In principle, the GOFFOstream +// is agnostic of the endianness of the content. However, it also supports +// writing data in big endian byte order. +class GOFFOstream : public raw_ostream { + /// The underlying raw_pwrite_stream. + raw_pwrite_stream &OS; + + /// The remaining size of this logical record, including fill bytes. + size_t RemainingSize; + +#ifndef NDEBUG + /// The number of bytes needed to fill up the last physical record. + size_t Gap = 0; +#endif + + /// The number of logical records emitted to far. + uint32_t LogicalRecords; + + /// The type of the current (logical) record. + GOFF::RecordType CurrentType; + + /// Signals start of new record. + bool NewLogicalRecord; + + /// Static allocated buffer for the stream, used by the raw_ostream class. The + /// buffer is sized to hold the content of a physical record. + char Buffer[GOFF::RecordContentLength]; + + // Return the number of bytes left to write until next physical record. + // Please note that we maintain the total numbers of byte left, not the + // written size. + size_t bytesToNextPhysicalRecord() { + size_t Bytes = RemainingSize % GOFF::RecordContentLength; + return Bytes ? Bytes : GOFF::RecordContentLength; + } + + /// Write the record prefix of a physical record, using the given record type. + static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type, + size_t RemainingSize, + uint8_t Flags = RecContinuation); + + /// 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(); } + +public: + explicit GOFFOstream(raw_pwrite_stream &OS) + : OS(OS), RemainingSize(0), LogicalRecords(0), NewLogicalRecord(false) { + SetBuffer(Buffer, sizeof(Buffer)); + } + + ~GOFFOstream() { finalize(); } + + raw_pwrite_stream &getOS() { return OS; } + + void newRecord(GOFF::RecordType Type, size_t Size); + + void finalize() { fillRecord(); } + + uint32_t logicalRecords() { return LogicalRecords; } + + // Support for endian-specific data. + template void writebe(value_type Value) { + Value = support::endian::byte_swap(Value, support::big); + write(reinterpret_cast(&Value), sizeof(value_type)); + } +}; + +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 |= RecContinued; + OS << static_cast(GOFF::PTVPrefix) // Record Type + << static_cast(TypeAndFlags) // Continuation + << static_cast(0); // Version +} + +void GOFFOstream::newRecord(GOFF::RecordType Type, size_t Size) { + fillRecord(); + CurrentType = Type; + RemainingSize = Size; +#ifdef NDEBUG + size_t Gap; +#endif + Gap = (RemainingSize % GOFF::RecordContentLength); + if (Gap) { + Gap = GOFF::RecordContentLength - Gap; + RemainingSize += 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 == Gap && "Wrong size of fill gap"); + assert((Remains < GOFF::RecordLength) && + "Attempt 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"); +} + +// This function is called from the raw_ostream implementation if: +// - The internal buffer is full. Size is excactly the size of the buffer. +// - Data larger than the internal buffer is written. Size is a multiple of the +// buffer size. +// - flush() has been called. Size is at most the buffer size. +// The GOFFOstream implementation ensures that flush() is called before a new +// logical record begins. Therefore it is sufficient to check for a new block +// only once. +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::RecordContentLength)) { + writeRecordPrefix(OS, CurrentType, RemainingSize, + NewLogicalRecord ? 0 : RecContinuation); + 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 GOFFObjectWriter : public MCObjectWriter { + // The target specific GOFF writer instance. + std::unique_ptr TargetObjectWriter; + + // The stream used to write the GOFF records. + GOFFOstream OS; + +public: + GOFFObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS) + : TargetObjectWriter(std::move(MOTW)), OS(OS) {} + + ~GOFFObjectWriter() override {} + + // Write GOFF records. + void writeHeader(); + void writeEnd(); + + // Implementation of the MCObjectWriter interface. + void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) override {} + void executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) override {} + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; +}; +} // end anonymous namespace + +void GOFFObjectWriter::writeHeader() { + OS.newRecord(GOFF::RT_HDR, /*Size=*/57); + OS.write_zeros(1); // Reserved + OS.writebe(0); // Target Hardware Environment + OS.writebe(0); // Target Operating System Environment + OS.write_zeros(2); // Reserved + OS.writebe(0); // CCSID + OS.write_zeros(16); // Character Set name + OS.write_zeros(16); // Language Product Identifier + OS.writebe(1); // Architecture Level + OS.writebe(0); // Module Properties Length + OS.write_zeros(6); // Reserved +} + +void GOFFObjectWriter::writeEnd() { + uint8_t F = GOFF::END_EPR_None; + uint8_t AMODE = 0; + uint32_t ESDID = 0; + + // TODO Set Flags/AMODE/ESDID for entry point. + + OS.newRecord(GOFF::RT_END, /*Size=*/13); + OS.writebe(Flags(6, 2, F)); // Indicator flags + OS.writebe(AMODE); // AMODE + OS.write_zeros(3); // Reserved + // The record count is the number of logical records. In principle, this value + // is available as OS.logicalRecords(). However, some tools rely on this field + // being zero. + OS.writebe(0); // Record Count + OS.writebe(ESDID); // ESDID (of entry point) + OS.finalize(); +} + +uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartOffset = OS.tell(); + + writeHeader(); + writeEnd(); + + LLVM_DEBUG(dbgs() << "Wrote " << OS.logicalRecords() << " logical records."); + + return OS.tell() - StartOffset; +} + +std::unique_ptr +llvm::createGOFFObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS) { + return std::make_unique(std::move(MOTW), OS); +} diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCDXContainerWriter.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCGOFFObjectWriter.h" #include "llvm/MC/MCMachObjectWriter.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSPIRVObjectWriter.h" @@ -46,6 +47,9 @@ case Triple::Wasm: return createWasmObjectWriter(cast(std::move(TW)), OS); + case Triple::GOFF: + return createGOFFObjectWriter(cast(std::move(TW)), + OS); case Triple::XCOFF: return createXCOFFObjectWriter( cast(std::move(TW)), OS); diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/MCGOFFStreamer.cpp @@ -0,0 +1,34 @@ +//===- lib/MC/MCGOFFStreamer.cpp - GOFF Object Output ---------------------===// +// +// 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 assembles .s files and emits GOFF .o object files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCGOFFStreamer.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/TargetRegistry.h" + +using namespace llvm; + +MCGOFFStreamer::~MCGOFFStreamer() {} + +MCStreamer *llvm::createGOFFStreamer(MCContext &Context, + std::unique_ptr &&MAB, + std::unique_ptr &&OW, + std::unique_ptr &&CE, + bool RelaxAll) { + MCGOFFStreamer *S = + new MCGOFFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + return S; +} diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt --- a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt @@ -1,10 +1,11 @@ add_llvm_component_library(LLVMSystemZDesc + SystemZELFObjectWriter.cpp + SystemZGOFFObjectWriter.cpp SystemZInstPrinter.cpp SystemZMCAsmBackend.cpp SystemZMCAsmInfo.cpp SystemZMCCodeEmitter.cpp SystemZMCExpr.cpp - SystemZMCObjectWriter.cpp SystemZMCTargetDesc.cpp LINK_COMPONENTS diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp rename from llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp rename to llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp @@ -1,4 +1,4 @@ -//===-- SystemZMCObjectWriter.cpp - SystemZ ELF writer --------------------===// +//===-- SystemZELFObjectWriter.cpp - SystemZ ELF writer -------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -23,10 +23,10 @@ namespace { -class SystemZObjectWriter : public MCELFObjectTargetWriter { +class SystemZELFObjectWriter : public MCELFObjectTargetWriter { public: - SystemZObjectWriter(uint8_t OSABI); - ~SystemZObjectWriter() override = default; + SystemZELFObjectWriter(uint8_t OSABI); + ~SystemZELFObjectWriter() override = default; protected: // Override MCELFObjectTargetWriter. @@ -36,9 +36,9 @@ } // end anonymous namespace -SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI) - : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390, - /*HasRelocationAddend_=*/ true) {} +SystemZELFObjectWriter::SystemZELFObjectWriter(uint8_t OSABI) + : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390, + /*HasRelocationAddend_=*/true) {} // Return the relocation type for an absolute value of MCFixupKind Kind. static unsigned getAbsoluteReloc(MCContext &Ctx, SMLoc Loc, unsigned Kind) { @@ -146,10 +146,10 @@ return 0; } -unsigned SystemZObjectWriter::getRelocType(MCContext &Ctx, - const MCValue &Target, - const MCFixup &Fixup, - bool IsPCRel) const { +unsigned SystemZELFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { SMLoc Loc = Fixup.getLoc(); unsigned Kind = Fixup.getKind(); if (Kind >= FirstLiteralRelocationKind) @@ -199,6 +199,6 @@ } std::unique_ptr -llvm::createSystemZObjectWriter(uint8_t OSABI) { - return std::make_unique(OSABI); +llvm::createSystemZELFObjectWriter(uint8_t OSABI) { + return std::make_unique(OSABI); } diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp @@ -0,0 +1,26 @@ +//===- SystemZGOFFObjectWriter.cpp - SystemZ GOFF writer ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SystemZMCTargetDesc.h" +#include "llvm/MC/MCGOFFObjectWriter.h" + +using namespace llvm; + +namespace { +class SystemZGOFFObjectWriter : public MCGOFFObjectTargetWriter { +public: + SystemZGOFFObjectWriter(); +}; +} // end anonymous namespace + +SystemZGOFFObjectWriter::SystemZGOFFObjectWriter() + : MCGOFFObjectTargetWriter() {} + +std::unique_ptr llvm::createSystemZGOFFObjectWriter() { + return std::make_unique(); +} diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -106,10 +106,9 @@ namespace { class SystemZMCAsmBackend : public MCAsmBackend { - uint8_t OSABI; public: - SystemZMCAsmBackend(uint8_t osABI) - : MCAsmBackend(support::big), OSABI(osABI) {} + SystemZMCAsmBackend() + : MCAsmBackend(support::big) {} // Override MCAsmBackend unsigned getNumFixupKinds() const override { @@ -130,10 +129,6 @@ } bool writeNopData(raw_ostream &OS, uint64_t Count, const MCSubtargetInfo *STI) const override; - std::unique_ptr - createObjectTargetWriter() const override { - return createSystemZObjectWriter(OSABI); - } }; } // end anonymous namespace @@ -208,11 +203,39 @@ return true; } +namespace { +class ELFSystemZAsmBackend : public SystemZMCAsmBackend { + uint8_t OSABI; + +public: + ELFSystemZAsmBackend(uint8_t OsABI) : SystemZMCAsmBackend(), OSABI(OsABI){}; + + std::unique_ptr + createObjectTargetWriter() const override { + return createSystemZELFObjectWriter(OSABI); + } +}; + +class GOFFSystemZAsmBackend : public SystemZMCAsmBackend { +public: + GOFFSystemZAsmBackend() : SystemZMCAsmBackend(){}; + + std::unique_ptr + createObjectTargetWriter() const override { + return createSystemZGOFFObjectWriter(); + } +}; +} // namespace + MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &Options) { + if (STI.getTargetTriple().isOSzOS()) { + return new GOFFSystemZAsmBackend(); + } + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()); - return new SystemZMCAsmBackend(OSABI); + return new ELFSystemZAsmBackend(OSABI); } diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h @@ -85,7 +85,9 @@ const MCRegisterInfo &MRI, const MCTargetOptions &Options); -std::unique_ptr createSystemZObjectWriter(uint8_t OSABI); +std::unique_ptr +createSystemZELFObjectWriter(uint8_t OSABI); +std::unique_ptr createSystemZGOFFObjectWriter(); } // end namespace llvm // Defines symbolic names for SystemZ registers. diff --git a/llvm/test/MC/GOFF/empty-goff.s b/llvm/test/MC/GOFF/empty-goff.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/GOFF/empty-goff.s @@ -0,0 +1,23 @@ +* RUN: llvm-mc <%s --triple s390x-ibm-zos --filetype=obj -o - | \ +* RUN: od -Ax -tx1 -v | FileCheck --ignore-case %s + +* Header record: +* 03 is prefix byte +* f. is header type +* .0 is version +* The 1 at offset 51 is the architecture level. +* CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +* End record: +* 03 is prefix byte +* 4. is header type +* .0 is version +* CHECK: 000050 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* CHECK: 000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00