1//===- lib/MC/GOFFObjectWriter.cpp - GOFF File Writer ---------------------===// 
  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 
  7//===----------------------------------------------------------------------===// 
  9// This file implements GOFF object file writer information. 
  11//===----------------------------------------------------------------------===// 
  27 #define DEBUG_TYPE "goff-writer" 
  30// Common flag values on records. 
  32// Flag: This record is continued. 
  35// Flag: This record is a continuation. 
  38// The GOFFOstream is responsible to write the data into the fixed physical 
  39// records of the format. A user of this class announces the begin of a new 
  40// logical record. While writing the payload, the physical records are created 
  41// for the data. Possible fill bytes at the end of a physical record are written 
  42// automatically. In principle, the GOFFOstream is agnostic of the endianness of 
  43// the payload. However, it also supports writing data in big endian byte order. 
  45// The physical records use the flag field to indicate if the there is a 
  46// successor and predecessor record. To be able to set these flags while 
  47// writing, the basic implementation idea is to always buffer the last seen 
  50 /// The underlying raw_pwrite_stream. 
  53 /// The number of logical records emitted so far. 
  56 /// The number of physical records emitted so far. 
  59 /// The size of the buffer. Same as the payload size of a physical record. 
  62 /// Current position in buffer. 
  63 char *BufferPtr = Buffer;
 
  65 /// Static allocated buffer for the stream. 
  66 char Buffer[BufferSize];
 
  68 /// The type of the current logical record, and the flags (aka continued and 
  69 /// continuation indicators) for the previous (physical) record. 
  78 uint32_t getNumLogicalRecords() { 
return LogicalRecords; }
 
  80 /// Write the specified bytes. 
  83 /// Write zeroes, up to a maximum of 16 bytes. 
  84 void write_zeros(
unsigned NumZeros);
 
  86 /// Support for endian-specific data. 
  87 template <
typename value_type> 
void writebe(value_type 
Value) {
 
  90 write((
const char *)&
Value, 
sizeof(value_type));
 
  93 /// Begin a new logical record. Implies finalizing the previous record. 
  96 /// Ends a logical record. 
  97 void finalizeRecord();
 
  100 /// Updates the continued/continuation flags, and writes the record prefix of 
  101 /// a physical record. 
  102 void updateFlagsAndWritePrefix(
bool IsContinued);
 
  104 /// Returns the remaining size in the buffer. 
  105 size_t getRemainingSize();
 
  111GOFFOstream::~GOFFOstream() { finalizeRecord(); }
 
  113void GOFFOstream::updateFlagsAndWritePrefix(
bool IsContinued) {
 
  114 // Update the flags based on the previous state and the flag IsContinued. 
  115 if (TypeAndFlags & RecContinued)
 
  116 TypeAndFlags |= RecContinuation;
 
  118 TypeAndFlags |= RecContinued;
 
  120 TypeAndFlags &= ~RecContinued;
 
  123 << 
static_cast<unsigned char>(TypeAndFlags) 
// Continuation 
  124 << 
static_cast<unsigned char>(0); 
// Version 
  129size_t GOFFOstream::getRemainingSize() {
 
  130 return size_t(&Buffer[BufferSize] - BufferPtr);
 
  133void GOFFOstream::write(
const char *
Ptr, 
size_t Size) {
 
  134 size_t RemainingSize = getRemainingSize();
 
  136 // Data fits into the buffer. 
  143 // Otherwise the buffer is partially filled or full, and data does not fit 
  145 updateFlagsAndWritePrefix(
/*IsContinued=*/true);
 
  146 OS.
write(Buffer, 
size_t(BufferPtr - Buffer));
 
  147 if (RemainingSize > 0) {
 
  149 Ptr += RemainingSize;
 
  150 Size -= RemainingSize;
 
  153 while (
Size > BufferSize) {
 
  154 updateFlagsAndWritePrefix(
/*IsContinued=*/true);
 
  160 // The remaining bytes fit into the buffer. 
  162 BufferPtr = &Buffer[
Size];
 
  165void GOFFOstream::write_zeros(
unsigned NumZeros) {
 
  166 assert(NumZeros <= 16 && 
"Range for zeros too large");
 
  168 // Handle the common case first: all fits in the buffer. 
  169 size_t RemainingSize = getRemainingSize();
 
  171 memset(BufferPtr, 0, NumZeros);
 
  172 BufferPtr += NumZeros;
 
  176 // Otherwise some field value is cleared. 
  177 static char Zeros[16] = {
 
  180 write(Zeros, NumZeros);
 
  185 TypeAndFlags = 
Type << 4;
 
  189void GOFFOstream::finalizeRecord() {
 
  190 if (Buffer == BufferPtr)
 
  192 updateFlagsAndWritePrefix(
/*IsContinued=*/false);
 
  193 OS.
write(Buffer, 
size_t(BufferPtr - Buffer));
 
  199// A GOFFSymbol holds all the data required for writing an ESD record. 
  204 uint32_t ParentEsdId;
 
  205 uint64_t 
Offset = 0; 
// Offset of the symbol into the section. LD only. 
  206 // Offset is only 32 bit, the larger type is used to 
  207 // enable error checking. 
  211 GOFF::BehavioralAttributes BehavAttrs;
 
  212 GOFF::SymbolFlags SymbolFlags;
 
  213 uint32_t SortKey = 0;
 
  214 uint32_t SectionLength = 0;
 
  215 uint32_t ADAEsdId = 0;
 
  216 uint32_t EASectionEDEsdId = 0;
 
  217 uint32_t EASectionOffset = 0;
 
  218 uint8_t FillByteValue = 0;
 
  220 GOFFSymbol() : EsdId(0), ParentEsdId(0) {}
 
  222 GOFFSymbol(StringRef Name, uint32_t EsdID, 
const GOFF::SDAttr &Attr)
 
  229 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
 
  230 const GOFF::EDAttr &Attr)
 
  234 // We always set a fill byte value. 
  238 // TODO Do we need/should set the "mangled" flag? 
  240 BehavAttrs.setRmode(Attr.
Rmode);
 
  247 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
 
  254 BehavAttrs.setLinkageType(Attr.
Linkage);
 
  255 BehavAttrs.setAmode(Attr.
Amode);
 
  259 GOFFSymbol(StringRef Name, uint32_t EsdID, uint32_t ParentEsdID,
 
  260 const GOFF::EDAttr &EDAttr, 
const GOFF::PRAttr &Attr)
 
  265 BehavAttrs.setLinkageType(Attr.
Linkage);
 
  267 BehavAttrs.setAlignment(EDAttr.
Alignment);
 
  276 void writeSymbol(
const GOFFSymbol &Symbol);
 
  277 void writeText(
const MCSectionGOFF *MC);
 
  280 void defineSectionSymbols(
const MCSectionGOFF &Section);
 
  281 void defineLabel(
const MCSymbolGOFF &Symbol);
 
  282 void defineSymbols();
 
  285 GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm);
 
  286 uint64_t writeObject();
 
  290GOFFWriter::GOFFWriter(raw_pwrite_stream &OS, MCAssembler &Asm)
 
  293void GOFFWriter::defineSectionSymbols(
const MCSectionGOFF &Section) {
 
  308 MCSectionGOFF *Parent = 
Section.getParent();
 
  312 if (
Section.requiresNonZeroLength()) {
 
  313 // We cannot have a zero-length section for data. If we do, 
  314 // artificially inflate it. Use 2 bytes to avoid odd alignments. Note: 
  315 // if this is ever changed, you will need to update the code in 
  316 // SystemZAsmPrinter::emitCEEMAIN and SystemZAsmPrinter::emitCELQMAIN to 
  317 // generate -1 if there is no ADA 
  318 if (!PR.SectionLength)
 
  319 PR.SectionLength = 2;
 
  325void GOFFWriter::defineLabel(
const MCSymbolGOFF &Symbol) {
 
  326 MCSectionGOFF &
Section = 
static_cast<MCSectionGOFF &
>(
Symbol.getSection());
 
  328 Section.getEDAttributes().NameSpace, 
Symbol.getLDAttributes());
 
  330 LD.ADAEsdId = 
Symbol.getADA()->getOrdinal();
 
  334void GOFFWriter::defineSymbols() {
 
  335 unsigned Ordinal = 0;
 
  336 // Process all sections. 
  337 for (MCSection &S : Asm) {
 
  338 auto &
Section = 
static_cast<MCSectionGOFF &
>(S);
 
  340 defineSectionSymbols(Section);
 
  343 // Process all symbols 
  344 for (
const MCSymbol &Sym : 
Asm.symbols()) {
 
  345 if (Sym.isTemporary())
 
  347 auto &
Symbol = 
static_cast<const MCSymbolGOFF &
>(Sym);
 
  348 if (
Symbol.hasLDAttributes()) {
 
  349 Symbol.setIndex(++Ordinal);
 
  355void GOFFWriter::writeHeader() {
 
  357 OS.write_zeros(1); 
// Reserved 
  358 OS.writebe<uint32_t>(0); 
// Target Hardware Environment 
  359 OS.writebe<uint32_t>(0); 
// Target Operating System Environment 
  360 OS.write_zeros(2); 
// Reserved 
  361 OS.writebe<uint16_t>(0); 
// CCSID 
  362 OS.write_zeros(16); 
// Character Set name 
  363 OS.write_zeros(16); 
// Language Product Identifier 
  364 OS.writebe<uint32_t>(1); 
// Architecture Level 
  365 OS.writebe<uint16_t>(0); 
// Module Properties Length 
  366 OS.write_zeros(6); 
// Reserved 
  369void GOFFWriter::writeSymbol(
const GOFFSymbol &Symbol) {
 
  370 if (
Symbol.Offset >= (((uint64_t)1) << 31))
 
  373 // All symbol names are in EBCDIC. 
  374 SmallString<256> 
Name;
 
  377 // Check length here since this number is technically signed but we need uint 
  378 // for writing to records. 
  381 uint16_t NameLength = 
Name.size();
 
  384 OS.writebe<uint8_t>(
Symbol.SymbolType); 
// Symbol Type 
  385 OS.writebe<uint32_t>(
Symbol.EsdId); 
// ESDID 
  386 OS.writebe<uint32_t>(
Symbol.ParentEsdId); 
// Parent or Owning ESDID 
  387 OS.writebe<uint32_t>(0); 
// Reserved 
  388 OS.writebe<uint32_t>(
 
  389 static_cast<uint32_t
>(
Symbol.Offset)); 
// Offset or Address 
  390 OS.writebe<uint32_t>(0); 
// Reserved 
  391 OS.writebe<uint32_t>(
Symbol.SectionLength); 
// Length 
  392 OS.writebe<uint32_t>(
Symbol.EASectionEDEsdId); 
// Extended Attribute ESDID 
  393 OS.writebe<uint32_t>(
Symbol.EASectionOffset); 
// Extended Attribute Offset 
  394 OS.writebe<uint32_t>(0); 
// Reserved 
  395 OS.writebe<uint8_t>(
Symbol.NameSpace); 
// Name Space ID 
  396 OS.writebe<uint8_t>(
Symbol.SymbolFlags); 
// Flags 
  397 OS.writebe<uint8_t>(
Symbol.FillByteValue); 
// Fill-Byte Value 
  398 OS.writebe<uint8_t>(0); 
// Reserved 
  399 OS.writebe<uint32_t>(
Symbol.ADAEsdId); 
// ADA ESDID 
  400 OS.writebe<uint32_t>(
Symbol.SortKey); 
// Sort Priority 
  401 OS.writebe<uint64_t>(0); 
// Reserved 
  402 for (
auto F : 
Symbol.BehavAttrs.Attr)
 
  403 OS.writebe<uint8_t>(
F); 
// Behavioral Attributes 
  404 OS.writebe<uint16_t>(NameLength); 
// Name Length 
  405 OS.write(
Name.data(), NameLength); 
// Name 
  409/// Adapter stream to write a text section. 
  410class TextStream : 
public raw_ostream {
 
  411 /// The underlying GOFFOstream. 
  414 /// The buffer size is the maximum number of bytes in a TXT section. 
  417 /// Static allocated buffer for the stream, used by the raw_ostream class. The 
  418 /// buffer is sized to hold the payload of a logical TXT record. 
  419 char Buffer[BufferSize];
 
  421 /// The offset for the next TXT record. This is equal to the number of bytes 
  425 /// The Esdid of the GOFF section. 
  426 const uint32_t EsdId;
 
  428 /// The record style. 
  431 /// See raw_ostream::write_impl. 
  432 void write_impl(
const char *
Ptr, 
size_t Size) 
override;
 
  434 uint64_t current_pos()
 const override { 
return Offset; }
 
  437 explicit TextStream(GOFFOstream &OS, uint32_t EsdId,
 
  439 : OS(OS), 
Offset(0), EsdId(EsdId), RecordStyle(RecordStyle) {
 
  440 SetBuffer(Buffer, 
sizeof(Buffer));
 
  443 ~TextStream()
 override { flush(); }
 
  447void TextStream::write_impl(
const char *
Ptr, 
size_t Size) {
 
  448 size_t WrittenLength = 0;
 
  450 // We only have signed 32bits of offset. 
  451 if (
Offset + 
Size > std::numeric_limits<int32_t>::max())
 
  454 while (WrittenLength < 
Size) {
 
  455 size_t ToWriteLength =
 
  459 OS.writebe<uint8_t>(GOFF::Flags(4, 4, RecordStyle)); 
// Text Record Style 
  460 OS.writebe<uint32_t>(EsdId); 
// Element ESDID 
  461 OS.writebe<uint32_t>(0); 
// Reserved 
  462 OS.writebe<uint32_t>(
static_cast<uint32_t
>(
Offset)); 
// Offset 
  463 OS.writebe<uint32_t>(0); 
// Text Field True Length 
  464 OS.writebe<uint16_t>(0); 
// Text Encoding 
  465 OS.writebe<uint16_t>(ToWriteLength); 
// Data Length 
  466 OS.write(
Ptr + WrittenLength, ToWriteLength); 
// Data 
  468 WrittenLength += ToWriteLength;
 
  473void GOFFWriter::writeText(
const MCSectionGOFF *Section) {
 
  474 // A BSS section contains only zeros, no need to write this. 
  479 Asm.writeSectionData(S, Section);
 
  482void GOFFWriter::writeEnd() {
 
  487 // TODO Set Flags/AMODE/ESDID for entry point. 
  490 OS.writebe<uint8_t>(GOFF::Flags(6, 2, 
F)); 
// Indicator flags 
  491 OS.writebe<uint8_t>(AMODE); 
// AMODE 
  492 OS.write_zeros(3); 
// Reserved 
  493 // The record count is the number of logical records. In principle, this value 
  494 // is available as OS.logicalRecords(). However, some tools rely on this field 
  496 OS.writebe<uint32_t>(0); 
// Record Count 
  497 OS.writebe<uint32_t>(ESDID); 
// ESDID (of entry point) 
  500uint64_t GOFFWriter::writeObject() {
 
  505 for (
const MCSection &Section : Asm)
 
  506 writeText(
static_cast<const MCSectionGOFF *
>(&Section));
 
  510 // Make sure all records are written. 
  514 << 
" logical records.");
 
  516 return OS.getWrittenSize();
 
  521 : TargetObjectWriter(
std::
move(MOTW)), OS(OS) {}
 
 
  530std::unique_ptr<MCObjectWriter>
 
  533 return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS);
 
 
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
 
#define LLVM_LIKELY(EXPR)
 
This file provides utility functions for converting between EBCDIC-1047 and UTF-8.
 
This file declares the MCSectionGOFF class, which contains all of the necessary machine code sections...
 
This file contains the MCSymbolGOFF class.
 
GOFFObjectWriter(std::unique_ptr< MCGOFFObjectTargetWriter > MOTW, raw_pwrite_stream &OS)
 
uint64_t writeObject() override
Write the object file and returns the number of bytes written.
 
~GOFFObjectWriter() override
 
LLVM_ABI uint64_t getSectionAddressSize(const MCSection &Sec) const
 
GOFF::EDAttr getEDAttributes() const
 
unsigned getOrdinal() const
 
The instances of the Type class are immutable: once they are created, they are never changed.
 
LLVM Value Representation.
 
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
 
raw_ostream & write(unsigned char C)
 
An abstract base class for streams implementations that also support a pwrite operation.
 
LLVM_ABI std::error_code convertToEBCDIC(StringRef Source, SmallVectorImpl< char > &Result)
 
constexpr uint8_t PayloadLength
 
constexpr uint16_t MaxDataLength
Maximum data length before starting a new card for RLD and TXT data.
 
constexpr uint8_t PTVPrefix
Prefix byte on every record. This indicates GOFF format.
 
constexpr uint8_t RecordLength
Length of the parts of a physical GOFF record.
 
@ ESD_NS_ProgramManagementBinder
 
@ ESD_ST_ElementDefinition
 
@ ESD_ST_SectionDefinition
 
value_type byte_swap(value_type value, endianness endian)
 
This is an optimization pass for GlobalISel generic memory operations.
 
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
 
std::unique_ptr< MCObjectWriter > createGOFFObjectWriter(std::unique_ptr< MCGOFFObjectTargetWriter > MOTW, raw_pwrite_stream &OS)
Construct a new GOFF writer instance.
 
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
 
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
 
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
 
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
 
Implement std::hash so that hash_code can be used in STL containers.
 
GOFF::ESDReserveQwords ReservedQwords
 
GOFF::ESDAlignment Alignment
 
GOFF::ESDTextStyle TextStyle
 
GOFF::ESDLoadingBehavior LoadBehavior
 
GOFF::ESDNameSpaceId NameSpace
 
GOFF::ESDBindingAlgorithm BindAlgorithm
 
GOFF::ESDBindingStrength BindingStrength
 
GOFF::ESDExecutable Executable
 
GOFF::ESDBindingScope BindingScope
 
GOFF::ESDLinkageType Linkage
 
GOFF::ESDLinkageType Linkage
 
GOFF::ESDBindingScope BindingScope
 
GOFF::ESDExecutable Executable
 
GOFF::ESDTaskingBehavior TaskingBehavior
 
GOFF::ESDBindingScope BindingScope