Home | History | Annotate | Download | only in MC
      1 //===-- llvm/MC/MCObjectWriter.h - Object File Writer Interface -*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_MC_MCOBJECTWRITER_H
     11 #define LLVM_MC_MCOBJECTWRITER_H
     12 
     13 #include "llvm/ADT/SmallVector.h"
     14 #include "llvm/Support/Compiler.h"
     15 #include "llvm/Support/DataTypes.h"
     16 #include "llvm/Support/EndianStream.h"
     17 #include "llvm/Support/raw_ostream.h"
     18 #include <cassert>
     19 
     20 namespace llvm {
     21 class MCAsmLayout;
     22 class MCAssembler;
     23 class MCFixup;
     24 class MCFragment;
     25 class MCSymbol;
     26 class MCSymbolRefExpr;
     27 class MCValue;
     28 
     29 /// Defines the object file and target independent interfaces used by the
     30 /// assembler backend to write native file format object files.
     31 ///
     32 /// The object writer contains a few callbacks used by the assembler to allow
     33 /// the object writer to modify the assembler data structures at appropriate
     34 /// points. Once assembly is complete, the object writer is given the
     35 /// MCAssembler instance, which contains all the symbol and section data which
     36 /// should be emitted as part of writeObject().
     37 ///
     38 /// The object writer also contains a number of helper methods for writing
     39 /// binary data to the output stream.
     40 class MCObjectWriter {
     41   MCObjectWriter(const MCObjectWriter &) = delete;
     42   void operator=(const MCObjectWriter &) = delete;
     43 
     44   raw_pwrite_stream *OS;
     45 
     46 protected:
     47   unsigned IsLittleEndian : 1;
     48 
     49 protected: // Can only create subclasses.
     50   MCObjectWriter(raw_pwrite_stream &OS, bool IsLittleEndian)
     51       : OS(&OS), IsLittleEndian(IsLittleEndian) {}
     52 
     53   unsigned getInitialOffset() {
     54     return OS->tell();
     55   }
     56 
     57 public:
     58   virtual ~MCObjectWriter();
     59 
     60   /// lifetime management
     61   virtual void reset() {}
     62 
     63   bool isLittleEndian() const { return IsLittleEndian; }
     64 
     65   raw_pwrite_stream &getStream() { return *OS; }
     66   void setStream(raw_pwrite_stream &NewOS) { OS = &NewOS; }
     67 
     68   /// \name High-Level API
     69   /// @{
     70 
     71   /// Perform any late binding of symbols (for example, to assign symbol
     72   /// indices for use when generating relocations).
     73   ///
     74   /// This routine is called by the assembler after layout and relaxation is
     75   /// complete.
     76   virtual void executePostLayoutBinding(MCAssembler &Asm,
     77                                         const MCAsmLayout &Layout) = 0;
     78 
     79   /// Record a relocation entry.
     80   ///
     81   /// This routine is called by the assembler after layout and relaxation, and
     82   /// post layout binding. The implementation is responsible for storing
     83   /// information about the relocation so that it can be emitted during
     84   /// writeObject().
     85   virtual void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
     86                                 const MCFragment *Fragment,
     87                                 const MCFixup &Fixup, MCValue Target,
     88                                 bool &IsPCRel, uint64_t &FixedValue) = 0;
     89 
     90   /// Check whether the difference (A - B) between two symbol references is
     91   /// fully resolved.
     92   ///
     93   /// Clients are not required to answer precisely and may conservatively return
     94   /// false, even when a difference is fully resolved.
     95   bool isSymbolRefDifferenceFullyResolved(const MCAssembler &Asm,
     96                                           const MCSymbolRefExpr *A,
     97                                           const MCSymbolRefExpr *B,
     98                                           bool InSet) const;
     99 
    100   virtual bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
    101                                                       const MCSymbol &A,
    102                                                       const MCSymbol &B,
    103                                                       bool InSet) const;
    104 
    105   virtual bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
    106                                                       const MCSymbol &SymA,
    107                                                       const MCFragment &FB,
    108                                                       bool InSet,
    109                                                       bool IsPCRel) const;
    110 
    111   /// True if this symbol (which is a variable) is weak. This is not
    112   /// just STB_WEAK, but more generally whether or not we can evaluate
    113   /// past it.
    114   virtual bool isWeak(const MCSymbol &Sym) const;
    115 
    116   /// Write the object file.
    117   ///
    118   /// This routine is called by the assembler after layout and relaxation is
    119   /// complete, fixups have been evaluated and applied, and relocations
    120   /// generated.
    121   virtual void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) = 0;
    122 
    123   /// @}
    124   /// \name Binary Output
    125   /// @{
    126 
    127   void write8(uint8_t Value) { *OS << char(Value); }
    128 
    129   void writeLE16(uint16_t Value) {
    130     support::endian::Writer<support::little>(*OS).write(Value);
    131   }
    132 
    133   void writeLE32(uint32_t Value) {
    134     support::endian::Writer<support::little>(*OS).write(Value);
    135   }
    136 
    137   void writeLE64(uint64_t Value) {
    138     support::endian::Writer<support::little>(*OS).write(Value);
    139   }
    140 
    141   void writeBE16(uint16_t Value) {
    142     support::endian::Writer<support::big>(*OS).write(Value);
    143   }
    144 
    145   void writeBE32(uint32_t Value) {
    146     support::endian::Writer<support::big>(*OS).write(Value);
    147   }
    148 
    149   void writeBE64(uint64_t Value) {
    150     support::endian::Writer<support::big>(*OS).write(Value);
    151   }
    152 
    153   void write16(uint16_t Value) {
    154     if (IsLittleEndian)
    155       writeLE16(Value);
    156     else
    157       writeBE16(Value);
    158   }
    159 
    160   void write32(uint32_t Value) {
    161     if (IsLittleEndian)
    162       writeLE32(Value);
    163     else
    164       writeBE32(Value);
    165   }
    166 
    167   void write64(uint64_t Value) {
    168     if (IsLittleEndian)
    169       writeLE64(Value);
    170     else
    171       writeBE64(Value);
    172   }
    173 
    174   void WriteZeros(unsigned N) {
    175     const char Zeros[16] = {0};
    176 
    177     for (unsigned i = 0, e = N / 16; i != e; ++i)
    178       *OS << StringRef(Zeros, 16);
    179 
    180     *OS << StringRef(Zeros, N % 16);
    181   }
    182 
    183   void writeBytes(const SmallVectorImpl<char> &ByteVec,
    184                   unsigned ZeroFillSize = 0) {
    185     writeBytes(StringRef(ByteVec.data(), ByteVec.size()), ZeroFillSize);
    186   }
    187 
    188   void writeBytes(StringRef Str, unsigned ZeroFillSize = 0) {
    189     // TODO: this version may need to go away once all fragment contents are
    190     // converted to SmallVector<char, N>
    191     assert(
    192         (ZeroFillSize == 0 || Str.size() <= ZeroFillSize) &&
    193         "data size greater than fill size, unexpected large write will occur");
    194     *OS << Str;
    195     if (ZeroFillSize)
    196       WriteZeros(ZeroFillSize - Str.size());
    197   }
    198 
    199   /// @}
    200 };
    201 
    202 } // End llvm namespace
    203 
    204 #endif
    205