xref: /freebsd-src/contrib/llvm-project/llvm/lib/MC/GOFFObjectWriter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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