1*5f757f3fSDimitry Andric //===- lib/MC/GOFFObjectWriter.cpp - GOFF File Writer ---------------------===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric // 9*5f757f3fSDimitry Andric // This file implements GOFF object file writer information. 10*5f757f3fSDimitry Andric // 11*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 12*5f757f3fSDimitry Andric 13*5f757f3fSDimitry Andric #include "llvm/BinaryFormat/GOFF.h" 14*5f757f3fSDimitry Andric #include "llvm/MC/MCAsmLayout.h" 15*5f757f3fSDimitry Andric #include "llvm/MC/MCAssembler.h" 16*5f757f3fSDimitry Andric #include "llvm/MC/MCGOFFObjectWriter.h" 17*5f757f3fSDimitry Andric #include "llvm/MC/MCValue.h" 18*5f757f3fSDimitry Andric #include "llvm/Support/Debug.h" 19*5f757f3fSDimitry Andric #include "llvm/Support/Endian.h" 20*5f757f3fSDimitry Andric #include "llvm/Support/Path.h" 21*5f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h" 22*5f757f3fSDimitry Andric 23*5f757f3fSDimitry Andric using namespace llvm; 24*5f757f3fSDimitry Andric 25*5f757f3fSDimitry Andric #define DEBUG_TYPE "goff-writer" 26*5f757f3fSDimitry Andric 27*5f757f3fSDimitry Andric namespace { 28*5f757f3fSDimitry Andric 29*5f757f3fSDimitry Andric // The standard System/390 convention is to name the high-order (leftmost) bit 30*5f757f3fSDimitry Andric // in a byte as bit zero. The Flags type helps to set bits in a byte according 31*5f757f3fSDimitry Andric // to this numeration order. 32*5f757f3fSDimitry Andric class Flags { 33*5f757f3fSDimitry Andric uint8_t Val; 34*5f757f3fSDimitry Andric 35*5f757f3fSDimitry Andric constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value, 36*5f757f3fSDimitry Andric uint8_t OldValue) { 37*5f757f3fSDimitry Andric assert(BitIndex < 8 && "Bit index out of bounds!"); 38*5f757f3fSDimitry Andric assert(Length + BitIndex <= 8 && "Bit length too long!"); 39*5f757f3fSDimitry Andric 40*5f757f3fSDimitry Andric uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length); 41*5f757f3fSDimitry Andric Value = Value << (8 - BitIndex - Length); 42*5f757f3fSDimitry Andric assert((Value & Mask) == Value && "Bits set outside of range!"); 43*5f757f3fSDimitry Andric 44*5f757f3fSDimitry Andric return (OldValue & ~Mask) | Value; 45*5f757f3fSDimitry Andric } 46*5f757f3fSDimitry Andric 47*5f757f3fSDimitry Andric public: 48*5f757f3fSDimitry Andric constexpr Flags() : Val(0) {} 49*5f757f3fSDimitry Andric constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value) 50*5f757f3fSDimitry Andric : Val(bits(BitIndex, Length, Value, 0)) {} 51*5f757f3fSDimitry Andric 52*5f757f3fSDimitry Andric void set(uint8_t BitIndex, uint8_t Length, uint8_t Value) { 53*5f757f3fSDimitry Andric Val = bits(BitIndex, Length, Value, Val); 54*5f757f3fSDimitry Andric } 55*5f757f3fSDimitry Andric 56*5f757f3fSDimitry Andric constexpr operator uint8_t() const { return Val; } 57*5f757f3fSDimitry Andric }; 58*5f757f3fSDimitry Andric 59*5f757f3fSDimitry Andric // Common flag values on records. 60*5f757f3fSDimitry Andric 61*5f757f3fSDimitry Andric // Flag: This record is continued. 62*5f757f3fSDimitry Andric constexpr uint8_t RecContinued = Flags(7, 1, 1); 63*5f757f3fSDimitry Andric 64*5f757f3fSDimitry Andric // Flag: This record is a continuation. 65*5f757f3fSDimitry Andric constexpr uint8_t RecContinuation = Flags(6, 1, 1); 66*5f757f3fSDimitry Andric 67*5f757f3fSDimitry Andric // The GOFFOstream is responsible to write the data into the fixed physical 68*5f757f3fSDimitry Andric // records of the format. A user of this class announces the start of a new 69*5f757f3fSDimitry Andric // logical record and the size of its content. While writing the content, the 70*5f757f3fSDimitry Andric // physical records are created for the data. Possible fill bytes at the end of 71*5f757f3fSDimitry Andric // a physical record are written automatically. In principle, the GOFFOstream 72*5f757f3fSDimitry Andric // is agnostic of the endianness of the content. However, it also supports 73*5f757f3fSDimitry Andric // writing data in big endian byte order. 74*5f757f3fSDimitry Andric class GOFFOstream : public raw_ostream { 75*5f757f3fSDimitry Andric /// The underlying raw_pwrite_stream. 76*5f757f3fSDimitry Andric raw_pwrite_stream &OS; 77*5f757f3fSDimitry Andric 78*5f757f3fSDimitry Andric /// The remaining size of this logical record, including fill bytes. 79*5f757f3fSDimitry Andric size_t RemainingSize; 80*5f757f3fSDimitry Andric 81*5f757f3fSDimitry Andric #ifndef NDEBUG 82*5f757f3fSDimitry Andric /// The number of bytes needed to fill up the last physical record. 83*5f757f3fSDimitry Andric size_t Gap = 0; 84*5f757f3fSDimitry Andric #endif 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric /// The number of logical records emitted to far. 87*5f757f3fSDimitry Andric uint32_t LogicalRecords; 88*5f757f3fSDimitry Andric 89*5f757f3fSDimitry Andric /// The type of the current (logical) record. 90*5f757f3fSDimitry Andric GOFF::RecordType CurrentType; 91*5f757f3fSDimitry Andric 92*5f757f3fSDimitry Andric /// Signals start of new record. 93*5f757f3fSDimitry Andric bool NewLogicalRecord; 94*5f757f3fSDimitry Andric 95*5f757f3fSDimitry Andric /// Static allocated buffer for the stream, used by the raw_ostream class. The 96*5f757f3fSDimitry Andric /// buffer is sized to hold the content of a physical record. 97*5f757f3fSDimitry Andric char Buffer[GOFF::RecordContentLength]; 98*5f757f3fSDimitry Andric 99*5f757f3fSDimitry Andric // Return the number of bytes left to write until next physical record. 100*5f757f3fSDimitry Andric // Please note that we maintain the total numbers of byte left, not the 101*5f757f3fSDimitry Andric // written size. 102*5f757f3fSDimitry Andric size_t bytesToNextPhysicalRecord() { 103*5f757f3fSDimitry Andric size_t Bytes = RemainingSize % GOFF::RecordContentLength; 104*5f757f3fSDimitry Andric return Bytes ? Bytes : GOFF::RecordContentLength; 105*5f757f3fSDimitry Andric } 106*5f757f3fSDimitry Andric 107*5f757f3fSDimitry Andric /// Write the record prefix of a physical record, using the given record type. 108*5f757f3fSDimitry Andric static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type, 109*5f757f3fSDimitry Andric size_t RemainingSize, 110*5f757f3fSDimitry Andric uint8_t Flags = RecContinuation); 111*5f757f3fSDimitry Andric 112*5f757f3fSDimitry Andric /// Fill the last physical record of a logical record with zero bytes. 113*5f757f3fSDimitry Andric void fillRecord(); 114*5f757f3fSDimitry Andric 115*5f757f3fSDimitry Andric /// See raw_ostream::write_impl. 116*5f757f3fSDimitry Andric void write_impl(const char *Ptr, size_t Size) override; 117*5f757f3fSDimitry Andric 118*5f757f3fSDimitry Andric /// Return the current position within the stream, not counting the bytes 119*5f757f3fSDimitry Andric /// currently in the buffer. 120*5f757f3fSDimitry Andric uint64_t current_pos() const override { return OS.tell(); } 121*5f757f3fSDimitry Andric 122*5f757f3fSDimitry Andric public: 123*5f757f3fSDimitry Andric explicit GOFFOstream(raw_pwrite_stream &OS) 124*5f757f3fSDimitry Andric : OS(OS), RemainingSize(0), LogicalRecords(0), NewLogicalRecord(false) { 125*5f757f3fSDimitry Andric SetBuffer(Buffer, sizeof(Buffer)); 126*5f757f3fSDimitry Andric } 127*5f757f3fSDimitry Andric 128*5f757f3fSDimitry Andric ~GOFFOstream() { finalize(); } 129*5f757f3fSDimitry Andric 130*5f757f3fSDimitry Andric raw_pwrite_stream &getOS() { return OS; } 131*5f757f3fSDimitry Andric 132*5f757f3fSDimitry Andric void newRecord(GOFF::RecordType Type, size_t Size); 133*5f757f3fSDimitry Andric 134*5f757f3fSDimitry Andric void finalize() { fillRecord(); } 135*5f757f3fSDimitry Andric 136*5f757f3fSDimitry Andric uint32_t logicalRecords() { return LogicalRecords; } 137*5f757f3fSDimitry Andric 138*5f757f3fSDimitry Andric // Support for endian-specific data. 139*5f757f3fSDimitry Andric template <typename value_type> void writebe(value_type Value) { 140*5f757f3fSDimitry Andric Value = 141*5f757f3fSDimitry Andric support::endian::byte_swap<value_type>(Value, llvm::endianness::big); 142*5f757f3fSDimitry Andric write(reinterpret_cast<const char *>(&Value), sizeof(value_type)); 143*5f757f3fSDimitry Andric } 144*5f757f3fSDimitry Andric }; 145*5f757f3fSDimitry Andric 146*5f757f3fSDimitry Andric void GOFFOstream::writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type, 147*5f757f3fSDimitry Andric size_t RemainingSize, uint8_t Flags) { 148*5f757f3fSDimitry Andric uint8_t TypeAndFlags = Flags | (Type << 4); 149*5f757f3fSDimitry Andric if (RemainingSize > GOFF::RecordLength) 150*5f757f3fSDimitry Andric TypeAndFlags |= RecContinued; 151*5f757f3fSDimitry Andric OS << static_cast<unsigned char>(GOFF::PTVPrefix) // Record Type 152*5f757f3fSDimitry Andric << static_cast<unsigned char>(TypeAndFlags) // Continuation 153*5f757f3fSDimitry Andric << static_cast<unsigned char>(0); // Version 154*5f757f3fSDimitry Andric } 155*5f757f3fSDimitry Andric 156*5f757f3fSDimitry Andric void GOFFOstream::newRecord(GOFF::RecordType Type, size_t Size) { 157*5f757f3fSDimitry Andric fillRecord(); 158*5f757f3fSDimitry Andric CurrentType = Type; 159*5f757f3fSDimitry Andric RemainingSize = Size; 160*5f757f3fSDimitry Andric #ifdef NDEBUG 161*5f757f3fSDimitry Andric size_t Gap; 162*5f757f3fSDimitry Andric #endif 163*5f757f3fSDimitry Andric Gap = (RemainingSize % GOFF::RecordContentLength); 164*5f757f3fSDimitry Andric if (Gap) { 165*5f757f3fSDimitry Andric Gap = GOFF::RecordContentLength - Gap; 166*5f757f3fSDimitry Andric RemainingSize += Gap; 167*5f757f3fSDimitry Andric } 168*5f757f3fSDimitry Andric NewLogicalRecord = true; 169*5f757f3fSDimitry Andric ++LogicalRecords; 170*5f757f3fSDimitry Andric } 171*5f757f3fSDimitry Andric 172*5f757f3fSDimitry Andric void GOFFOstream::fillRecord() { 173*5f757f3fSDimitry Andric assert((GetNumBytesInBuffer() <= RemainingSize) && 174*5f757f3fSDimitry Andric "More bytes in buffer than expected"); 175*5f757f3fSDimitry Andric size_t Remains = RemainingSize - GetNumBytesInBuffer(); 176*5f757f3fSDimitry Andric if (Remains) { 177*5f757f3fSDimitry Andric assert(Remains == Gap && "Wrong size of fill gap"); 178*5f757f3fSDimitry Andric assert((Remains < GOFF::RecordLength) && 179*5f757f3fSDimitry Andric "Attempt to fill more than one physical record"); 180*5f757f3fSDimitry Andric raw_ostream::write_zeros(Remains); 181*5f757f3fSDimitry Andric } 182*5f757f3fSDimitry Andric flush(); 183*5f757f3fSDimitry Andric assert(RemainingSize == 0 && "Not fully flushed"); 184*5f757f3fSDimitry Andric assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty"); 185*5f757f3fSDimitry Andric } 186*5f757f3fSDimitry Andric 187*5f757f3fSDimitry Andric // This function is called from the raw_ostream implementation if: 188*5f757f3fSDimitry Andric // - The internal buffer is full. Size is excactly the size of the buffer. 189*5f757f3fSDimitry Andric // - Data larger than the internal buffer is written. Size is a multiple of the 190*5f757f3fSDimitry Andric // buffer size. 191*5f757f3fSDimitry Andric // - flush() has been called. Size is at most the buffer size. 192*5f757f3fSDimitry Andric // The GOFFOstream implementation ensures that flush() is called before a new 193*5f757f3fSDimitry Andric // logical record begins. Therefore it is sufficient to check for a new block 194*5f757f3fSDimitry Andric // only once. 195*5f757f3fSDimitry Andric void GOFFOstream::write_impl(const char *Ptr, size_t Size) { 196*5f757f3fSDimitry Andric assert((RemainingSize >= Size) && "Attempt to write too much data"); 197*5f757f3fSDimitry Andric assert(RemainingSize && "Logical record overflow"); 198*5f757f3fSDimitry Andric if (!(RemainingSize % GOFF::RecordContentLength)) { 199*5f757f3fSDimitry Andric writeRecordPrefix(OS, CurrentType, RemainingSize, 200*5f757f3fSDimitry Andric NewLogicalRecord ? 0 : RecContinuation); 201*5f757f3fSDimitry Andric NewLogicalRecord = false; 202*5f757f3fSDimitry Andric } 203*5f757f3fSDimitry Andric assert(!NewLogicalRecord && 204*5f757f3fSDimitry Andric "New logical record not on physical record boundary"); 205*5f757f3fSDimitry Andric 206*5f757f3fSDimitry Andric size_t Idx = 0; 207*5f757f3fSDimitry Andric while (Size > 0) { 208*5f757f3fSDimitry Andric size_t BytesToWrite = bytesToNextPhysicalRecord(); 209*5f757f3fSDimitry Andric if (BytesToWrite > Size) 210*5f757f3fSDimitry Andric BytesToWrite = Size; 211*5f757f3fSDimitry Andric OS.write(Ptr + Idx, BytesToWrite); 212*5f757f3fSDimitry Andric Idx += BytesToWrite; 213*5f757f3fSDimitry Andric Size -= BytesToWrite; 214*5f757f3fSDimitry Andric RemainingSize -= BytesToWrite; 215*5f757f3fSDimitry Andric if (Size) 216*5f757f3fSDimitry Andric writeRecordPrefix(OS, CurrentType, RemainingSize); 217*5f757f3fSDimitry Andric } 218*5f757f3fSDimitry Andric } 219*5f757f3fSDimitry Andric 220*5f757f3fSDimitry Andric class GOFFObjectWriter : public MCObjectWriter { 221*5f757f3fSDimitry Andric // The target specific GOFF writer instance. 222*5f757f3fSDimitry Andric std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter; 223*5f757f3fSDimitry Andric 224*5f757f3fSDimitry Andric // The stream used to write the GOFF records. 225*5f757f3fSDimitry Andric GOFFOstream OS; 226*5f757f3fSDimitry Andric 227*5f757f3fSDimitry Andric public: 228*5f757f3fSDimitry Andric GOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW, 229*5f757f3fSDimitry Andric raw_pwrite_stream &OS) 230*5f757f3fSDimitry Andric : TargetObjectWriter(std::move(MOTW)), OS(OS) {} 231*5f757f3fSDimitry Andric 232*5f757f3fSDimitry Andric ~GOFFObjectWriter() override {} 233*5f757f3fSDimitry Andric 234*5f757f3fSDimitry Andric // Write GOFF records. 235*5f757f3fSDimitry Andric void writeHeader(); 236*5f757f3fSDimitry Andric void writeEnd(); 237*5f757f3fSDimitry Andric 238*5f757f3fSDimitry Andric // Implementation of the MCObjectWriter interface. 239*5f757f3fSDimitry Andric void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, 240*5f757f3fSDimitry Andric const MCFragment *Fragment, const MCFixup &Fixup, 241*5f757f3fSDimitry Andric MCValue Target, uint64_t &FixedValue) override {} 242*5f757f3fSDimitry Andric void executePostLayoutBinding(MCAssembler &Asm, 243*5f757f3fSDimitry Andric const MCAsmLayout &Layout) override {} 244*5f757f3fSDimitry Andric uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; 245*5f757f3fSDimitry Andric }; 246*5f757f3fSDimitry Andric } // end anonymous namespace 247*5f757f3fSDimitry Andric 248*5f757f3fSDimitry Andric void GOFFObjectWriter::writeHeader() { 249*5f757f3fSDimitry Andric OS.newRecord(GOFF::RT_HDR, /*Size=*/57); 250*5f757f3fSDimitry Andric OS.write_zeros(1); // Reserved 251*5f757f3fSDimitry Andric OS.writebe<uint32_t>(0); // Target Hardware Environment 252*5f757f3fSDimitry Andric OS.writebe<uint32_t>(0); // Target Operating System Environment 253*5f757f3fSDimitry Andric OS.write_zeros(2); // Reserved 254*5f757f3fSDimitry Andric OS.writebe<uint16_t>(0); // CCSID 255*5f757f3fSDimitry Andric OS.write_zeros(16); // Character Set name 256*5f757f3fSDimitry Andric OS.write_zeros(16); // Language Product Identifier 257*5f757f3fSDimitry Andric OS.writebe<uint32_t>(1); // Architecture Level 258*5f757f3fSDimitry Andric OS.writebe<uint16_t>(0); // Module Properties Length 259*5f757f3fSDimitry Andric OS.write_zeros(6); // Reserved 260*5f757f3fSDimitry Andric } 261*5f757f3fSDimitry Andric 262*5f757f3fSDimitry Andric void GOFFObjectWriter::writeEnd() { 263*5f757f3fSDimitry Andric uint8_t F = GOFF::END_EPR_None; 264*5f757f3fSDimitry Andric uint8_t AMODE = 0; 265*5f757f3fSDimitry Andric uint32_t ESDID = 0; 266*5f757f3fSDimitry Andric 267*5f757f3fSDimitry Andric // TODO Set Flags/AMODE/ESDID for entry point. 268*5f757f3fSDimitry Andric 269*5f757f3fSDimitry Andric OS.newRecord(GOFF::RT_END, /*Size=*/13); 270*5f757f3fSDimitry Andric OS.writebe<uint8_t>(Flags(6, 2, F)); // Indicator flags 271*5f757f3fSDimitry Andric OS.writebe<uint8_t>(AMODE); // AMODE 272*5f757f3fSDimitry Andric OS.write_zeros(3); // Reserved 273*5f757f3fSDimitry Andric // The record count is the number of logical records. In principle, this value 274*5f757f3fSDimitry Andric // is available as OS.logicalRecords(). However, some tools rely on this field 275*5f757f3fSDimitry Andric // being zero. 276*5f757f3fSDimitry Andric OS.writebe<uint32_t>(0); // Record Count 277*5f757f3fSDimitry Andric OS.writebe<uint32_t>(ESDID); // ESDID (of entry point) 278*5f757f3fSDimitry Andric OS.finalize(); 279*5f757f3fSDimitry Andric } 280*5f757f3fSDimitry Andric 281*5f757f3fSDimitry Andric uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm, 282*5f757f3fSDimitry Andric const MCAsmLayout &Layout) { 283*5f757f3fSDimitry Andric uint64_t StartOffset = OS.tell(); 284*5f757f3fSDimitry Andric 285*5f757f3fSDimitry Andric writeHeader(); 286*5f757f3fSDimitry Andric writeEnd(); 287*5f757f3fSDimitry Andric 288*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Wrote " << OS.logicalRecords() << " logical records."); 289*5f757f3fSDimitry Andric 290*5f757f3fSDimitry Andric return OS.tell() - StartOffset; 291*5f757f3fSDimitry Andric } 292*5f757f3fSDimitry Andric 293*5f757f3fSDimitry Andric std::unique_ptr<MCObjectWriter> 294*5f757f3fSDimitry Andric llvm::createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW, 295*5f757f3fSDimitry Andric raw_pwrite_stream &OS) { 296*5f757f3fSDimitry Andric return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS); 297*5f757f3fSDimitry Andric } 298