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