[llvm] [SystemZ][z/OS] Implement yaml2obj for GOFF Object File Format (PR #71445)
James Henderson via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 8 01:37:08 PST 2023
================
@@ -0,0 +1,451 @@
+//===- yaml2goff - Convert YAML to a GOFF object file ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// The GOFF component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/ConvertEBCDIC.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+
+static const uint8_t TXTMaxDataLength = 56;
+
+// Common flag values on records.
+enum {
+ // Flag: This record is continued.
+ Rec_Continued = 1 << (8 - 7 - 1),
+
+ // Flag: This record is a continuation.
+ Rec_Continuation = 1 << (8 - 6 - 1),
+};
+
+template <typename value_type> struct BinaryBeImpl {
+ value_type Value;
+ BinaryBeImpl(value_type V) : Value(V) {}
+};
+
+template <typename value_type>
+raw_ostream &operator<<(raw_ostream &OS, const BinaryBeImpl<value_type> &BBE) {
+ char Buffer[sizeof(BBE.Value)];
+ support::endian::write<value_type, llvm::endianness::big, support::unaligned>(
+ Buffer, BBE.Value);
+ OS.write(Buffer, sizeof(BBE.Value));
+ return OS;
+}
+
+template <typename value_type> BinaryBeImpl<value_type> binaryBe(value_type V) {
+ return BinaryBeImpl<value_type>(V);
+}
+
+struct ZerosImpl {
+ size_t NumBytes;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const ZerosImpl &Z) {
+ OS.write_zeros(Z.NumBytes);
+ return OS;
+}
+
+ZerosImpl zeros(const size_t NumBytes) { return ZerosImpl{NumBytes}; }
+
+raw_ostream &operator<<(raw_ostream &OS, const yaml::BinaryRef &Data) {
+ Data.writeAsBinary(OS);
+ return OS;
+}
+
+// The GOFFOstream is responsible to write the data into the fixed physical
+// records of the format. A user of this class announces the the begin of a new
+// logical record and the size of its payload. While writing the payload, the
+// physical records are created for the data. Possible fill bytes at the end of
+// a physical record are written automatically.
+class GOFFOstream : public raw_ostream {
+ /// The underlying raw_ostream.
+ raw_ostream &OS;
+
+ /// The number of logical records emitted to far.
+ uint32_t LogicalRecords;
+
+ /// The remaining size of this logical record, including fill
+ /// bytes.
+ size_t RemainingSize;
+
+ /// The type of the current (logical) record.
+ GOFF::RecordType CurrentType;
+
+ /// Signals begin of new record.
+ bool NewLogicalRecord;
+
+ // Return the number of bytes left to write until next physical record.
+ // Please note that we maintain the total numbers of byte left, not the
+ // written size.
+ size_t bytesToNextPhysicalRecord() {
+ size_t Bytes = RemainingSize % GOFF::PayloadLength;
+ return Bytes ? Bytes : GOFF::PayloadLength;
+ }
+
+ /// Write the record prefix of a physical record, using the current record
+ /// type.
+ static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+ size_t RemainingSize,
+ uint8_t Flags = Rec_Continuation);
+
+ /// Fill the last physical record of a logical record with zero bytes.
+ void fillRecord();
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ uint64_t current_pos() const override { return OS.tell(); }
+
+public:
+ explicit GOFFOstream(raw_ostream &OS)
+ : OS(OS), LogicalRecords(0), RemainingSize(0), NewLogicalRecord(false) {
+ SetBufferSize(GOFF::PayloadLength);
+ }
+
+ ~GOFFOstream() { finalize(); }
+
+ void newRecord(GOFF::RecordType Type, size_t Size);
+
+ void finalize() { fillRecord(); }
+
+ uint32_t logicalRecords() { return LogicalRecords; }
+};
+
+void GOFFOstream::writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+ size_t RemainingSize, uint8_t Flags) {
+ uint8_t TypeAndFlags = Flags | (Type << 4);
+ if (RemainingSize > GOFF::RecordLength)
+ TypeAndFlags |= Rec_Continued;
+ OS << binaryBe(static_cast<unsigned char>(GOFF::PTVPrefix))
+ << binaryBe(static_cast<unsigned char>(TypeAndFlags))
+ << binaryBe(static_cast<unsigned char>(0));
+}
+
+void GOFFOstream::newRecord(GOFF::RecordType Type, size_t Size) {
+ fillRecord();
+ CurrentType = Type;
+ RemainingSize = Size;
+ if (size_t Gap = (RemainingSize % GOFF::PayloadLength))
+ RemainingSize += GOFF::PayloadLength - Gap;
+ NewLogicalRecord = true;
+ ++LogicalRecords;
+}
+
+void GOFFOstream::fillRecord() {
+ assert((GetNumBytesInBuffer() <= RemainingSize) &&
+ "More bytes in buffer than expected");
+ size_t Remains = RemainingSize - GetNumBytesInBuffer();
+ if (Remains) {
+ assert((Remains < GOFF::RecordLength) &&
+ "Attempt to fill more than one physical record");
----------------
jh7370 wrote:
```suggestion
"Attempting to fill more than one physical record");
```
Also in other places.
https://github.com/llvm/llvm-project/pull/71445
More information about the llvm-commits
mailing list