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