Index: llvm/include/llvm/BinaryFormat/GOFF.h =================================================================== --- /dev/null +++ llvm/include/llvm/BinaryFormat/GOFF.h @@ -0,0 +1,63 @@ +//===-- llvm/BinaryFormat/GOFF.h - GOFF definitions --------------*- 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 header contains common, non-processor-specific data structures and +// 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/2.4.0?topic=facilities-generalized-object-file-format-goff +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BINARYFORMAT_GOFF_H +#define LLVM_BINARYFORMAT_GOFF_H + +#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 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; + +/// \brief Prefix byte on every record. This indicates GOFF format. +constexpr uint8_t PTVPrefix = 0x03; + +enum RecordType : uint8_t { + RT_ESD = 0, + RT_TXT = 1, + RT_RLD = 2, + RT_LEN = 3, + RT_END = 4, + RT_HDR = 15, +}; + +enum ENDEntryPointRequest : uint8_t { + END_EPR_None = 0, + END_EPR_EsdidOffset = 1, + END_EPR_ExternalName = 2, + END_EPR_Reserved = 3, +}; + +} // end namespace GOFF + +} // end namespace llvm + +#endif // LLVM_BINARYFORMAT_GOFF_H Index: llvm/include/llvm/MC/MCGOFFObjectWriter.h =================================================================== --- /dev/null +++ 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 Index: llvm/include/llvm/MC/MCGOFFStreamer.h =================================================================== --- /dev/null +++ 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, + unsigned ByteAlignment) override {} + void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override {} + void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, unsigned ByteAlignment = 0, + SMLoc Loc = SMLoc()) override {} +}; + +} // end namespace llvm + +#endif Index: llvm/include/llvm/MC/TargetRegistry.h =================================================================== --- llvm/include/llvm/MC/TargetRegistry.h +++ llvm/include/llvm/MC/TargetRegistry.h @@ -93,6 +93,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, @@ -182,6 +187,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, @@ -299,6 +308,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; @@ -565,7 +575,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), @@ -946,6 +962,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; } Index: llvm/lib/MC/CMakeLists.txt =================================================================== --- llvm/lib/MC/CMakeLists.txt +++ llvm/lib/MC/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_component_library(LLVMMC ConstantPools.cpp ELFObjectWriter.cpp + GOFFObjectWriter.cpp MCAsmBackend.cpp MCAsmInfo.cpp MCAsmInfoCOFF.cpp @@ -20,6 +21,7 @@ MCELFStreamer.cpp MCExpr.cpp MCFragment.cpp + MCGOFFStreamer.cpp MCInst.cpp MCInstPrinter.cpp MCInstrAnalysis.cpp Index: llvm/lib/MC/GOFFObjectWriter.cpp =================================================================== --- /dev/null +++ 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_t type helps to set bits in a byte according +// to this numeration order. +class flags_t { + 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_t() : Val(0) {} + constexpr flags_t(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_t(7, 1, 1); + +// Flag: This record is a continuation. +constexpr uint8_t RecContinuation = flags_t(6, 1, 1); + +// The goff_ostream is responsible to write the data into the fixed physical +// records of the format. A user of this class announces the begin 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 goff_ostream +// is agnostic of the endianness of the content. However, it also supports +// writing data in big endian byte order. +class goff_ostream : 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 begin 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 write_record_prefix(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 fill_record(); + + /// 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 goff_ostream(raw_pwrite_stream &OS) + : OS(OS), RemainingSize(0), LogicalRecords(0), NewLogicalRecord(false) { + SetBuffer(Buffer, sizeof(Buffer)); + } + + ~goff_ostream() { finalize(); } + + raw_pwrite_stream &getOS() { return OS; } + + void new_record(GOFF::RecordType Type, size_t Size); + + void finalize() { fill_record(); } + + uint32_t logical_records() { return LogicalRecords; } + + // Support for endian specific data. + template void write_be(value_type Value) { + Value = support::endian::byte_swap(Value, support::big); + write((const char *)&Value, sizeof(value_type)); + } +}; + +void goff_ostream::write_record_prefix(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 goff_ostream::new_record(GOFF::RecordType Type, size_t Size) { + fill_record(); + 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 goff_ostream::fill_record() { + assert((GetNumBytesInBuffer() <= RemainingSize) && + "More bytes in buffer than expected"); + size_t Remains = RemainingSize - GetNumBytesInBuffer(); + if (Remains) { +#ifndef NDEBUG + assert(Remains == Gap && "Wrong size of fill gap"); +#endif + 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 goff_ostream 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 goff_ostream::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)) { + write_record_prefix(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) { + write_record_prefix(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. + goff_ostream 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.new_record(GOFF::RT_HDR, /* Size = */ 57); + OS.write_zeros(1); // Reserved + OS.write_be(0); // Target Hardware Environment + OS.write_be(0); // Target Operating System Environment + OS.write_zeros(2); // Reserved + OS.write_be(0); // CCSID + OS.write_zeros(16); // Character Set name + OS.write_zeros(16); // Language Product Identifier + OS.write_be(1); // Architecture Level + OS.write_be(0); // Module Properties Length + OS.write_zeros(6); // Reserved +} + +void GOFFObjectWriter::writeEnd() { + uint8_t Flags = GOFF::END_EPR_None; + uint8_t AMODE = 0; + uint32_t ESDID = 0; + + // TODO Set Flags/AMODE/ESDID for entry point. + + OS.new_record(GOFF::RT_END, /* Size = */ 13); + OS.write_be(flags_t(6, 2, Flags)); // Indicator flags + OS.write_be(AMODE); // AMODE + OS.write_zeros(3); // Reserved + OS.write_be(0); // Record Count + OS.write_be(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.logical_records() << " 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); +} Index: llvm/lib/MC/MCAsmBackend.cpp =================================================================== --- llvm/lib/MC/MCAsmBackend.cpp +++ llvm/lib/MC/MCAsmBackend.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/STLArrayExtras.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/MCWasmObjectWriter.h" @@ -42,6 +43,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); Index: llvm/lib/MC/MCGOFFStreamer.cpp =================================================================== --- /dev/null +++ llvm/lib/MC/MCGOFFStreamer.cpp @@ -0,0 +1,33 @@ +//===- 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/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; +} Index: llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt +++ llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt @@ -1,9 +1,10 @@ add_llvm_component_library(LLVMSystemZDesc + SystemZELFObjectWriter.cpp + SystemZGOFFObjectWriter.cpp SystemZInstPrinter.cpp SystemZMCAsmBackend.cpp SystemZMCAsmInfo.cpp SystemZMCCodeEmitter.cpp - SystemZMCObjectWriter.cpp SystemZMCTargetDesc.cpp LINK_COMPONENTS Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp +++ 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. @@ -22,10 +22,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. @@ -35,19 +35,25 @@ } // 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(unsigned Kind) { switch (Kind) { - case FK_Data_1: return ELF::R_390_8; - case FK_Data_2: return ELF::R_390_16; - case FK_Data_4: return ELF::R_390_32; - case FK_Data_8: return ELF::R_390_64; - case SystemZ::FK_390_12: return ELF::R_390_12; - case SystemZ::FK_390_20: return ELF::R_390_20; + case FK_Data_1: + return ELF::R_390_8; + case FK_Data_2: + return ELF::R_390_16; + case FK_Data_4: + return ELF::R_390_32; + case FK_Data_8: + return ELF::R_390_64; + case SystemZ::FK_390_12: + return ELF::R_390_12; + case SystemZ::FK_390_20: + return ELF::R_390_20; } llvm_unreachable("Unsupported absolute address"); } @@ -55,13 +61,20 @@ // Return the relocation type for a PC-relative value of MCFixupKind Kind. static unsigned getPCRelReloc(unsigned Kind) { switch (Kind) { - case FK_Data_2: return ELF::R_390_PC16; - case FK_Data_4: return ELF::R_390_PC32; - case FK_Data_8: return ELF::R_390_PC64; - case SystemZ::FK_390_PC12DBL: return ELF::R_390_PC12DBL; - case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; - case SystemZ::FK_390_PC24DBL: return ELF::R_390_PC24DBL; - case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; + case FK_Data_2: + return ELF::R_390_PC16; + case FK_Data_4: + return ELF::R_390_PC32; + case FK_Data_8: + return ELF::R_390_PC64; + case SystemZ::FK_390_PC12DBL: + return ELF::R_390_PC12DBL; + case SystemZ::FK_390_PC16DBL: + return ELF::R_390_PC16DBL; + case SystemZ::FK_390_PC24DBL: + return ELF::R_390_PC24DBL; + case SystemZ::FK_390_PC32DBL: + return ELF::R_390_PC32DBL; } llvm_unreachable("Unsupported PC-relative address"); } @@ -69,8 +82,10 @@ // Return the R_390_TLS_LE* relocation type for MCFixupKind Kind. static unsigned getTLSLEReloc(unsigned Kind) { switch (Kind) { - case FK_Data_4: return ELF::R_390_TLS_LE32; - case FK_Data_8: return ELF::R_390_TLS_LE64; + case FK_Data_4: + return ELF::R_390_TLS_LE32; + case FK_Data_8: + return ELF::R_390_TLS_LE64; } llvm_unreachable("Unsupported absolute address"); } @@ -78,8 +93,10 @@ // Return the R_390_TLS_LDO* relocation type for MCFixupKind Kind. static unsigned getTLSLDOReloc(unsigned Kind) { switch (Kind) { - case FK_Data_4: return ELF::R_390_TLS_LDO32; - case FK_Data_8: return ELF::R_390_TLS_LDO64; + case FK_Data_4: + return ELF::R_390_TLS_LDO32; + case FK_Data_8: + return ELF::R_390_TLS_LDO64; } llvm_unreachable("Unsupported absolute address"); } @@ -87,9 +104,12 @@ // Return the R_390_TLS_LDM* relocation type for MCFixupKind Kind. static unsigned getTLSLDMReloc(unsigned Kind) { switch (Kind) { - case FK_Data_4: return ELF::R_390_TLS_LDM32; - case FK_Data_8: return ELF::R_390_TLS_LDM64; - case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_LDCALL; + case FK_Data_4: + return ELF::R_390_TLS_LDM32; + case FK_Data_8: + return ELF::R_390_TLS_LDM64; + case SystemZ::FK_390_TLS_CALL: + return ELF::R_390_TLS_LDCALL; } llvm_unreachable("Unsupported absolute address"); } @@ -97,9 +117,12 @@ // Return the R_390_TLS_GD* relocation type for MCFixupKind Kind. static unsigned getTLSGDReloc(unsigned Kind) { switch (Kind) { - case FK_Data_4: return ELF::R_390_TLS_GD32; - case FK_Data_8: return ELF::R_390_TLS_GD64; - case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_GDCALL; + case FK_Data_4: + return ELF::R_390_TLS_GD32; + case FK_Data_8: + return ELF::R_390_TLS_GD64; + case SystemZ::FK_390_TLS_CALL: + return ELF::R_390_TLS_GDCALL; } llvm_unreachable("Unsupported absolute address"); } @@ -107,18 +130,22 @@ // Return the PLT relocation counterpart of MCFixupKind Kind. static unsigned getPLTReloc(unsigned Kind) { switch (Kind) { - case SystemZ::FK_390_PC12DBL: return ELF::R_390_PLT12DBL; - case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL; - case SystemZ::FK_390_PC24DBL: return ELF::R_390_PLT24DBL; - case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; + case SystemZ::FK_390_PC12DBL: + return ELF::R_390_PLT12DBL; + case SystemZ::FK_390_PC16DBL: + return ELF::R_390_PLT16DBL; + case SystemZ::FK_390_PC24DBL: + return ELF::R_390_PLT24DBL; + case SystemZ::FK_390_PC32DBL: + return ELF::R_390_PLT32DBL; } llvm_unreachable("Unsupported absolute address"); } -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 { unsigned Kind = Fixup.getKind(); if (Kind >= FirstLiteralRelocationKind) return Kind - FirstLiteralRelocationKind; @@ -136,7 +163,8 @@ case MCSymbolRefExpr::VK_INDNTPOFF: if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) return ELF::R_390_TLS_IEENT; - llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); + llvm_unreachable( + "Only PC-relative INDNTPOFF accesses are supported for now"); case MCSymbolRefExpr::VK_DTPOFF: assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); @@ -165,6 +193,6 @@ } std::unique_ptr -llvm::createSystemZObjectWriter(uint8_t OSABI) { - return std::make_unique(OSABI); +llvm::createSystemZELFObjectWriter(uint8_t OSABI) { + return std::make_unique(OSABI); } Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp =================================================================== --- /dev/null +++ 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(); +} Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp +++ llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -80,10 +80,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 { @@ -104,10 +103,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 @@ -191,11 +186,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); } Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h +++ llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h @@ -86,7 +86,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. Index: llvm/test/MC/GOFF/empty-goff.s =================================================================== --- /dev/null +++ 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