xref: /llvm-project/llvm/lib/MC/GOFFObjectWriter.cpp (revision d73d5c8c9b56fadcbd89dd1dab71dca2c8f5e38d)
13adc2a0bSKai Nacke //===- lib/MC/GOFFObjectWriter.cpp - GOFF File Writer ---------------------===//
23adc2a0bSKai Nacke //
33adc2a0bSKai Nacke // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43adc2a0bSKai Nacke // See https://llvm.org/LICENSE.txt for license information.
53adc2a0bSKai Nacke // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63adc2a0bSKai Nacke //
73adc2a0bSKai Nacke //===----------------------------------------------------------------------===//
83adc2a0bSKai Nacke //
93adc2a0bSKai Nacke // This file implements GOFF object file writer information.
103adc2a0bSKai Nacke //
113adc2a0bSKai Nacke //===----------------------------------------------------------------------===//
123adc2a0bSKai Nacke 
133adc2a0bSKai Nacke #include "llvm/BinaryFormat/GOFF.h"
143adc2a0bSKai Nacke #include "llvm/MC/MCAssembler.h"
153adc2a0bSKai Nacke #include "llvm/MC/MCGOFFObjectWriter.h"
163adc2a0bSKai Nacke #include "llvm/MC/MCValue.h"
173adc2a0bSKai Nacke #include "llvm/Support/Debug.h"
183adc2a0bSKai Nacke #include "llvm/Support/Endian.h"
193adc2a0bSKai Nacke #include "llvm/Support/raw_ostream.h"
203adc2a0bSKai Nacke 
213adc2a0bSKai Nacke using namespace llvm;
223adc2a0bSKai Nacke 
233adc2a0bSKai Nacke #define DEBUG_TYPE "goff-writer"
243adc2a0bSKai Nacke 
253adc2a0bSKai Nacke namespace {
263adc2a0bSKai Nacke 
273adc2a0bSKai Nacke // The standard System/390 convention is to name the high-order (leftmost) bit
283adc2a0bSKai Nacke // in a byte as bit zero. The Flags type helps to set bits in a byte according
293adc2a0bSKai Nacke // to this numeration order.
303adc2a0bSKai Nacke class Flags {
313adc2a0bSKai Nacke   uint8_t Val;
323adc2a0bSKai Nacke 
333adc2a0bSKai Nacke   constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value,
343adc2a0bSKai Nacke                                 uint8_t OldValue) {
353adc2a0bSKai Nacke     assert(BitIndex < 8 && "Bit index out of bounds!");
363adc2a0bSKai Nacke     assert(Length + BitIndex <= 8 && "Bit length too long!");
373adc2a0bSKai Nacke 
383adc2a0bSKai Nacke     uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length);
393adc2a0bSKai Nacke     Value = Value << (8 - BitIndex - Length);
403adc2a0bSKai Nacke     assert((Value & Mask) == Value && "Bits set outside of range!");
413adc2a0bSKai Nacke 
423adc2a0bSKai Nacke     return (OldValue & ~Mask) | Value;
433adc2a0bSKai Nacke   }
443adc2a0bSKai Nacke 
453adc2a0bSKai Nacke public:
463adc2a0bSKai Nacke   constexpr Flags() : Val(0) {}
473adc2a0bSKai Nacke   constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value)
483adc2a0bSKai Nacke       : Val(bits(BitIndex, Length, Value, 0)) {}
493adc2a0bSKai Nacke 
503adc2a0bSKai Nacke   void set(uint8_t BitIndex, uint8_t Length, uint8_t Value) {
513adc2a0bSKai Nacke     Val = bits(BitIndex, Length, Value, Val);
523adc2a0bSKai Nacke   }
533adc2a0bSKai Nacke 
543adc2a0bSKai Nacke   constexpr operator uint8_t() const { return Val; }
553adc2a0bSKai Nacke };
563adc2a0bSKai Nacke 
573adc2a0bSKai Nacke // Common flag values on records.
583adc2a0bSKai Nacke 
593adc2a0bSKai Nacke // Flag: This record is continued.
603adc2a0bSKai Nacke constexpr uint8_t RecContinued = Flags(7, 1, 1);
613adc2a0bSKai Nacke 
623adc2a0bSKai Nacke // Flag: This record is a continuation.
633adc2a0bSKai Nacke constexpr uint8_t RecContinuation = Flags(6, 1, 1);
643adc2a0bSKai Nacke 
653adc2a0bSKai Nacke // The GOFFOstream is responsible to write the data into the fixed physical
663adc2a0bSKai Nacke // records of the format. A user of this class announces the start of a new
673adc2a0bSKai Nacke // logical record and the size of its content. While writing the content, the
683adc2a0bSKai Nacke // physical records are created for the data. Possible fill bytes at the end of
693adc2a0bSKai Nacke // a physical record are written automatically. In principle, the GOFFOstream
703adc2a0bSKai Nacke // is agnostic of the endianness of the content. However, it also supports
713adc2a0bSKai Nacke // writing data in big endian byte order.
723adc2a0bSKai Nacke class GOFFOstream : public raw_ostream {
733adc2a0bSKai Nacke   /// The underlying raw_pwrite_stream.
743adc2a0bSKai Nacke   raw_pwrite_stream &OS;
753adc2a0bSKai Nacke 
763adc2a0bSKai Nacke   /// The remaining size of this logical record, including fill bytes.
773adc2a0bSKai Nacke   size_t RemainingSize;
783adc2a0bSKai Nacke 
793adc2a0bSKai Nacke #ifndef NDEBUG
803adc2a0bSKai Nacke   /// The number of bytes needed to fill up the last physical record.
813adc2a0bSKai Nacke   size_t Gap = 0;
823adc2a0bSKai Nacke #endif
833adc2a0bSKai Nacke 
843adc2a0bSKai Nacke   /// The number of logical records emitted to far.
853adc2a0bSKai Nacke   uint32_t LogicalRecords;
863adc2a0bSKai Nacke 
873adc2a0bSKai Nacke   /// The type of the current (logical) record.
883adc2a0bSKai Nacke   GOFF::RecordType CurrentType;
893adc2a0bSKai Nacke 
903adc2a0bSKai Nacke   /// Signals start of new record.
913adc2a0bSKai Nacke   bool NewLogicalRecord;
923adc2a0bSKai Nacke 
933adc2a0bSKai Nacke   /// Static allocated buffer for the stream, used by the raw_ostream class. The
943adc2a0bSKai Nacke   /// buffer is sized to hold the content of a physical record.
953adc2a0bSKai Nacke   char Buffer[GOFF::RecordContentLength];
963adc2a0bSKai Nacke 
973adc2a0bSKai Nacke   // Return the number of bytes left to write until next physical record.
983adc2a0bSKai Nacke   // Please note that we maintain the total numbers of byte left, not the
993adc2a0bSKai Nacke   // written size.
1003adc2a0bSKai Nacke   size_t bytesToNextPhysicalRecord() {
1013adc2a0bSKai Nacke     size_t Bytes = RemainingSize % GOFF::RecordContentLength;
1023adc2a0bSKai Nacke     return Bytes ? Bytes : GOFF::RecordContentLength;
1033adc2a0bSKai Nacke   }
1043adc2a0bSKai Nacke 
1053adc2a0bSKai Nacke   /// Write the record prefix of a physical record, using the given record type.
1063adc2a0bSKai Nacke   static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
1073adc2a0bSKai Nacke                                 size_t RemainingSize,
1083adc2a0bSKai Nacke                                 uint8_t Flags = RecContinuation);
1093adc2a0bSKai Nacke 
1103adc2a0bSKai Nacke   /// Fill the last physical record of a logical record with zero bytes.
1113adc2a0bSKai Nacke   void fillRecord();
1123adc2a0bSKai Nacke 
1133adc2a0bSKai Nacke   /// See raw_ostream::write_impl.
1143adc2a0bSKai Nacke   void write_impl(const char *Ptr, size_t Size) override;
1153adc2a0bSKai Nacke 
1163adc2a0bSKai Nacke   /// Return the current position within the stream, not counting the bytes
1173adc2a0bSKai Nacke   /// currently in the buffer.
1183adc2a0bSKai Nacke   uint64_t current_pos() const override { return OS.tell(); }
1193adc2a0bSKai Nacke 
1203adc2a0bSKai Nacke public:
1213adc2a0bSKai Nacke   explicit GOFFOstream(raw_pwrite_stream &OS)
1223adc2a0bSKai Nacke       : OS(OS), RemainingSize(0), LogicalRecords(0), NewLogicalRecord(false) {
1233adc2a0bSKai Nacke     SetBuffer(Buffer, sizeof(Buffer));
1243adc2a0bSKai Nacke   }
1253adc2a0bSKai Nacke 
1263adc2a0bSKai Nacke   ~GOFFOstream() { finalize(); }
1273adc2a0bSKai Nacke 
1283adc2a0bSKai Nacke   raw_pwrite_stream &getOS() { return OS; }
1293adc2a0bSKai Nacke 
1303adc2a0bSKai Nacke   void newRecord(GOFF::RecordType Type, size_t Size);
1313adc2a0bSKai Nacke 
1323adc2a0bSKai Nacke   void finalize() { fillRecord(); }
1333adc2a0bSKai Nacke 
1343adc2a0bSKai Nacke   uint32_t logicalRecords() { return LogicalRecords; }
1353adc2a0bSKai Nacke 
1363adc2a0bSKai Nacke   // Support for endian-specific data.
1373adc2a0bSKai Nacke   template <typename value_type> void writebe(value_type Value) {
1384a0ccfa8SKazu Hirata     Value =
1394a0ccfa8SKazu Hirata         support::endian::byte_swap<value_type>(Value, llvm::endianness::big);
1403adc2a0bSKai Nacke     write(reinterpret_cast<const char *>(&Value), sizeof(value_type));
1413adc2a0bSKai Nacke   }
1423adc2a0bSKai Nacke };
1433adc2a0bSKai Nacke 
1443adc2a0bSKai Nacke void GOFFOstream::writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
1453adc2a0bSKai Nacke                                     size_t RemainingSize, uint8_t Flags) {
1463adc2a0bSKai Nacke   uint8_t TypeAndFlags = Flags | (Type << 4);
1473adc2a0bSKai Nacke   if (RemainingSize > GOFF::RecordLength)
1483adc2a0bSKai Nacke     TypeAndFlags |= RecContinued;
1493adc2a0bSKai Nacke   OS << static_cast<unsigned char>(GOFF::PTVPrefix) // Record Type
1503adc2a0bSKai Nacke      << static_cast<unsigned char>(TypeAndFlags)    // Continuation
1513adc2a0bSKai Nacke      << static_cast<unsigned char>(0);              // Version
1523adc2a0bSKai Nacke }
1533adc2a0bSKai Nacke 
1543adc2a0bSKai Nacke void GOFFOstream::newRecord(GOFF::RecordType Type, size_t Size) {
1553adc2a0bSKai Nacke   fillRecord();
1563adc2a0bSKai Nacke   CurrentType = Type;
1573adc2a0bSKai Nacke   RemainingSize = Size;
1583adc2a0bSKai Nacke #ifdef NDEBUG
1593adc2a0bSKai Nacke   size_t Gap;
1603adc2a0bSKai Nacke #endif
1613adc2a0bSKai Nacke   Gap = (RemainingSize % GOFF::RecordContentLength);
1623adc2a0bSKai Nacke   if (Gap) {
1633adc2a0bSKai Nacke     Gap = GOFF::RecordContentLength - Gap;
1643adc2a0bSKai Nacke     RemainingSize += Gap;
1653adc2a0bSKai Nacke   }
1663adc2a0bSKai Nacke   NewLogicalRecord = true;
1673adc2a0bSKai Nacke   ++LogicalRecords;
1683adc2a0bSKai Nacke }
1693adc2a0bSKai Nacke 
1703adc2a0bSKai Nacke void GOFFOstream::fillRecord() {
1713adc2a0bSKai Nacke   assert((GetNumBytesInBuffer() <= RemainingSize) &&
1723adc2a0bSKai Nacke          "More bytes in buffer than expected");
1733adc2a0bSKai Nacke   size_t Remains = RemainingSize - GetNumBytesInBuffer();
1743adc2a0bSKai Nacke   if (Remains) {
1753adc2a0bSKai Nacke     assert(Remains == Gap && "Wrong size of fill gap");
1763adc2a0bSKai Nacke     assert((Remains < GOFF::RecordLength) &&
1773adc2a0bSKai Nacke            "Attempt to fill more than one physical record");
1783adc2a0bSKai Nacke     raw_ostream::write_zeros(Remains);
1793adc2a0bSKai Nacke   }
1803adc2a0bSKai Nacke   flush();
1813adc2a0bSKai Nacke   assert(RemainingSize == 0 && "Not fully flushed");
1823adc2a0bSKai Nacke   assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty");
1833adc2a0bSKai Nacke }
1843adc2a0bSKai Nacke 
1853adc2a0bSKai Nacke // This function is called from the raw_ostream implementation if:
1863adc2a0bSKai Nacke // - The internal buffer is full. Size is excactly the size of the buffer.
1873adc2a0bSKai Nacke // - Data larger than the internal buffer is written. Size is a multiple of the
1883adc2a0bSKai Nacke //   buffer size.
1893adc2a0bSKai Nacke // - flush() has been called. Size is at most the buffer size.
1903adc2a0bSKai Nacke // The GOFFOstream implementation ensures that flush() is called before a new
1913adc2a0bSKai Nacke // logical record begins. Therefore it is sufficient to check for a new block
1923adc2a0bSKai Nacke // only once.
1933adc2a0bSKai Nacke void GOFFOstream::write_impl(const char *Ptr, size_t Size) {
1943adc2a0bSKai Nacke   assert((RemainingSize >= Size) && "Attempt to write too much data");
1953adc2a0bSKai Nacke   assert(RemainingSize && "Logical record overflow");
1963adc2a0bSKai Nacke   if (!(RemainingSize % GOFF::RecordContentLength)) {
1973adc2a0bSKai Nacke     writeRecordPrefix(OS, CurrentType, RemainingSize,
1983adc2a0bSKai Nacke                       NewLogicalRecord ? 0 : RecContinuation);
1993adc2a0bSKai Nacke     NewLogicalRecord = false;
2003adc2a0bSKai Nacke   }
2013adc2a0bSKai Nacke   assert(!NewLogicalRecord &&
2023adc2a0bSKai Nacke          "New logical record not on physical record boundary");
2033adc2a0bSKai Nacke 
2043adc2a0bSKai Nacke   size_t Idx = 0;
2053adc2a0bSKai Nacke   while (Size > 0) {
2063adc2a0bSKai Nacke     size_t BytesToWrite = bytesToNextPhysicalRecord();
2073adc2a0bSKai Nacke     if (BytesToWrite > Size)
2083adc2a0bSKai Nacke       BytesToWrite = Size;
2093adc2a0bSKai Nacke     OS.write(Ptr + Idx, BytesToWrite);
2103adc2a0bSKai Nacke     Idx += BytesToWrite;
2113adc2a0bSKai Nacke     Size -= BytesToWrite;
2123adc2a0bSKai Nacke     RemainingSize -= BytesToWrite;
2133adc2a0bSKai Nacke     if (Size)
2143adc2a0bSKai Nacke       writeRecordPrefix(OS, CurrentType, RemainingSize);
2153adc2a0bSKai Nacke   }
2163adc2a0bSKai Nacke }
2173adc2a0bSKai Nacke 
2183adc2a0bSKai Nacke class GOFFObjectWriter : public MCObjectWriter {
2193adc2a0bSKai Nacke   // The target specific GOFF writer instance.
2203adc2a0bSKai Nacke   std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
2213adc2a0bSKai Nacke 
2223adc2a0bSKai Nacke   // The stream used to write the GOFF records.
2233adc2a0bSKai Nacke   GOFFOstream OS;
2243adc2a0bSKai Nacke 
2253adc2a0bSKai Nacke public:
2263adc2a0bSKai Nacke   GOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
2273adc2a0bSKai Nacke                    raw_pwrite_stream &OS)
2283adc2a0bSKai Nacke       : TargetObjectWriter(std::move(MOTW)), OS(OS) {}
2293adc2a0bSKai Nacke 
2303adc2a0bSKai Nacke   ~GOFFObjectWriter() override {}
2313adc2a0bSKai Nacke 
2323adc2a0bSKai Nacke   // Write GOFF records.
2333adc2a0bSKai Nacke   void writeHeader();
2343adc2a0bSKai Nacke   void writeEnd();
2353adc2a0bSKai Nacke 
2363adc2a0bSKai Nacke   // Implementation of the MCObjectWriter interface.
2374289c422SFangrui Song   void recordRelocation(MCAssembler &Asm, const MCFragment *Fragment,
2384289c422SFangrui Song                         const MCFixup &Fixup, MCValue Target,
2394289c422SFangrui Song                         uint64_t &FixedValue) override {}
240*23e62243SFangrui Song   uint64_t writeObject(MCAssembler &Asm) override;
2413adc2a0bSKai Nacke };
2423adc2a0bSKai Nacke } // end anonymous namespace
2433adc2a0bSKai Nacke 
2443adc2a0bSKai Nacke void GOFFObjectWriter::writeHeader() {
2453adc2a0bSKai Nacke   OS.newRecord(GOFF::RT_HDR, /*Size=*/57);
2463adc2a0bSKai Nacke   OS.write_zeros(1);       // Reserved
2473adc2a0bSKai Nacke   OS.writebe<uint32_t>(0); // Target Hardware Environment
2483adc2a0bSKai Nacke   OS.writebe<uint32_t>(0); // Target Operating System Environment
2493adc2a0bSKai Nacke   OS.write_zeros(2);       // Reserved
2503adc2a0bSKai Nacke   OS.writebe<uint16_t>(0); // CCSID
2513adc2a0bSKai Nacke   OS.write_zeros(16);      // Character Set name
2523adc2a0bSKai Nacke   OS.write_zeros(16);      // Language Product Identifier
2533adc2a0bSKai Nacke   OS.writebe<uint32_t>(1); // Architecture Level
2543adc2a0bSKai Nacke   OS.writebe<uint16_t>(0); // Module Properties Length
2553adc2a0bSKai Nacke   OS.write_zeros(6);       // Reserved
2563adc2a0bSKai Nacke }
2573adc2a0bSKai Nacke 
2583adc2a0bSKai Nacke void GOFFObjectWriter::writeEnd() {
2593adc2a0bSKai Nacke   uint8_t F = GOFF::END_EPR_None;
2603adc2a0bSKai Nacke   uint8_t AMODE = 0;
2613adc2a0bSKai Nacke   uint32_t ESDID = 0;
2623adc2a0bSKai Nacke 
2633adc2a0bSKai Nacke   // TODO Set Flags/AMODE/ESDID for entry point.
2643adc2a0bSKai Nacke 
2653adc2a0bSKai Nacke   OS.newRecord(GOFF::RT_END, /*Size=*/13);
2663adc2a0bSKai Nacke   OS.writebe<uint8_t>(Flags(6, 2, F)); // Indicator flags
2673adc2a0bSKai Nacke   OS.writebe<uint8_t>(AMODE);          // AMODE
2683adc2a0bSKai Nacke   OS.write_zeros(3);                   // Reserved
2693adc2a0bSKai Nacke   // The record count is the number of logical records. In principle, this value
2703adc2a0bSKai Nacke   // is available as OS.logicalRecords(). However, some tools rely on this field
2713adc2a0bSKai Nacke   // being zero.
2723adc2a0bSKai Nacke   OS.writebe<uint32_t>(0);     // Record Count
2733adc2a0bSKai Nacke   OS.writebe<uint32_t>(ESDID); // ESDID (of entry point)
2743adc2a0bSKai Nacke   OS.finalize();
2753adc2a0bSKai Nacke }
2763adc2a0bSKai Nacke 
277*23e62243SFangrui Song uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm) {
2783adc2a0bSKai Nacke   uint64_t StartOffset = OS.tell();
2793adc2a0bSKai Nacke 
2803adc2a0bSKai Nacke   writeHeader();
2813adc2a0bSKai Nacke   writeEnd();
2823adc2a0bSKai Nacke 
2833adc2a0bSKai Nacke   LLVM_DEBUG(dbgs() << "Wrote " << OS.logicalRecords() << " logical records.");
2843adc2a0bSKai Nacke 
2853adc2a0bSKai Nacke   return OS.tell() - StartOffset;
2863adc2a0bSKai Nacke }
2873adc2a0bSKai Nacke 
2883adc2a0bSKai Nacke std::unique_ptr<MCObjectWriter>
2893adc2a0bSKai Nacke llvm::createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
2903adc2a0bSKai Nacke                              raw_pwrite_stream &OS) {
2913adc2a0bSKai Nacke   return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS);
2923adc2a0bSKai Nacke }
293