text: //===- llvm/MC/MCObjectWriter.h - Object File Writer Interface --*- C++ -*-===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef LLVM_MC_MCOBJECTWRITER_H
  #define LLVM_MC_MCOBJECTWRITER_H
  
  #include "llvm/ADT/SmallVector.h"
  #include "llvm/ADT/StringRef.h"
  #include "llvm/Support/Endian.h"
  #include "llvm/Support/EndianStream.h"
  #include "llvm/Support/raw_ostream.h"
  #include <cassert>
  #include <cstdint>
  
  namespace llvm {
  
  class MCAsmLayout;
  class MCAssembler;
  class MCFixup;
  class MCFragment;
  class MCSymbol;
  class MCSymbolRefExpr;
  class MCValue;
  
  /// Defines the object file and target independent interfaces used by the
  /// assembler backend to write native file format object files.
  ///
  /// The object writer contains a few callbacks used by the assembler to allow
  /// the object writer to modify the assembler data structures at appropriate
  /// points. Once assembly is complete, the object writer is given the
  /// MCAssembler instance, which contains all the symbol and section data which
  /// should be emitted as part of writeObject().
  ///
  /// The object writer also contains a number of helper methods for writing
  /// binary data to the output stream.
  class MCObjectWriter {
    raw_pwrite_stream *OS;
  
  protected:
    unsigned IsLittleEndian : 1;
  
    // Can only create subclasses.
    MCObjectWriter(raw_pwrite_stream &OS, bool IsLittleEndian)
        : OS(&OS), IsLittleEndian(IsLittleEndian) {}
  
    unsigned getInitialOffset() {
      return OS->tell();
    }
  
  public:
    MCObjectWriter(const MCObjectWriter &) = delete;
    MCObjectWriter &operator=(const MCObjectWriter &) = delete;
    virtual ~MCObjectWriter();
  
    /// lifetime management
    virtual void reset() {}
  
    bool isLittleEndian() const { return IsLittleEndian; }
  
    raw_pwrite_stream &getStream() { return *OS; }
    void setStream(raw_pwrite_stream &NewOS) { OS = &NewOS; }
  
    /// \name High-Level API
    /// @{
  
    /// Perform any late binding of symbols (for example, to assign symbol
    /// indices for use when generating relocations).
    ///
    /// This routine is called by the assembler after layout and relaxation is
    /// complete.
    virtual void executePostLayoutBinding(MCAssembler &Asm,
                                          const MCAsmLayout &Layout) = 0;
  
    /// Record a relocation entry.
    ///
    /// This routine is called by the assembler after layout and relaxation, and
    /// post layout binding. The implementation is responsible for storing
    /// information about the relocation so that it can be emitted during
    /// writeObject().
    virtual void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
                                  const MCFragment *Fragment,
                                  const MCFixup &Fixup, MCValue Target,
                                  uint64_t &FixedValue) = 0;
  
    /// Check whether the difference (A - B) between two symbol references is
    /// fully resolved.
    ///
    /// Clients are not required to answer precisely and may conservatively return
    /// false, even when a difference is fully resolved.
    bool isSymbolRefDifferenceFullyResolved(const MCAssembler &Asm,
                                            const MCSymbolRefExpr *A,
                                            const MCSymbolRefExpr *B,
                                            bool InSet) const;
  
    virtual bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
                                                        const MCSymbol &A,
                                                        const MCSymbol &B,
                                                        bool InSet) const;
  
    virtual bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
                                                        const MCSymbol &SymA,
                                                        const MCFragment &FB,
                                                        bool InSet,
                                                        bool IsPCRel) const;
  
    /// Write the object file.
    ///
    /// This routine is called by the assembler after layout and relaxation is
    /// complete, fixups have been evaluated and applied, and relocations
    /// generated.
    virtual void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) = 0;
  
    /// @}
    /// \name Binary Output
    /// @{
  
    void write8(uint8_t Value) { *OS << char(Value); }
  
    void writeLE16(uint16_t Value) {
      support::endian::Writer<support::little>(*OS).write(Value);
    }
  
    void writeLE32(uint32_t Value) {
      support::endian::Writer<support::little>(*OS).write(Value);
    }
  
    void writeLE64(uint64_t Value) {
      support::endian::Writer<support::little>(*OS).write(Value);
    }
  
    void writeBE16(uint16_t Value) {
      support::endian::Writer<support::big>(*OS).write(Value);
    }
  
    void writeBE32(uint32_t Value) {
      support::endian::Writer<support::big>(*OS).write(Value);
    }
  
    void writeBE64(uint64_t Value) {
      support::endian::Writer<support::big>(*OS).write(Value);
    }
  
    void write16(uint16_t Value) {
      if (IsLittleEndian)
        writeLE16(Value);
      else
        writeBE16(Value);
    }
  
    void write32(uint32_t Value) {
      if (IsLittleEndian)
        writeLE32(Value);
      else
        writeBE32(Value);
    }
  
    void write64(uint64_t Value) {
      if (IsLittleEndian)
        writeLE64(Value);
      else
        writeBE64(Value);
    }
  
    void WriteZeros(unsigned N) {
      const char Zeros[16] = {0};
  
      for (unsigned i = 0, e = N / 16; i != e; ++i)
        *OS << StringRef(Zeros, 16);
  
      *OS << StringRef(Zeros, N % 16);
    }
  
    void writeBytes(const SmallVectorImpl<char> &ByteVec,
                    unsigned ZeroFillSize = 0) {
      writeBytes(StringRef(ByteVec.data(), ByteVec.size()), ZeroFillSize);
    }
  
    void writeBytes(StringRef Str, unsigned ZeroFillSize = 0) {
      // TODO: this version may need to go away once all fragment contents are
      // converted to SmallVector<char, N>
      assert(
          (ZeroFillSize == 0 || Str.size() <= ZeroFillSize) &&
          "data size greater than fill size, unexpected large write will occur");
      *OS << Str;
      if (ZeroFillSize)
        WriteZeros(ZeroFillSize - Str.size());
    }
  
    /// @}
  };
  
  } // end namespace llvm
  
  #endif // LLVM_MC_MCOBJECTWRITER_H
  