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 MCSymbolData; 26 class MCSymbolRefExpr; 27 class MCValue; 28 29 /// MCObjectWriter - Defines the object file and target independent interfaces 30 /// used by the 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 protected: 45 raw_pwrite_stream &OS; 46 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 public: 54 virtual ~MCObjectWriter(); 55 56 /// lifetime management 57 virtual void reset() { } 58 59 bool isLittleEndian() const { return IsLittleEndian; } 60 61 raw_ostream &getStream() { return OS; } 62 63 /// @name High-Level API 64 /// @{ 65 66 /// \brief Perform any late binding of symbols (for example, to assign symbol 67 /// indices for use when generating relocations). 68 /// 69 /// This routine is called by the assembler after layout and relaxation is 70 /// complete. 71 virtual void ExecutePostLayoutBinding(MCAssembler &Asm, 72 const MCAsmLayout &Layout) = 0; 73 74 /// \brief Record a relocation entry. 75 /// 76 /// This routine is called by the assembler after layout and relaxation, and 77 /// post layout binding. The implementation is responsible for storing 78 /// information about the relocation so that it can be emitted during 79 /// WriteObject(). 80 virtual void RecordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, 81 const MCFragment *Fragment, 82 const MCFixup &Fixup, MCValue Target, 83 bool &IsPCRel, uint64_t &FixedValue) = 0; 84 85 /// \brief Check whether the difference (A - B) between two symbol 86 /// references is fully resolved. 87 /// 88 /// Clients are not required to answer precisely and may conservatively return 89 /// false, even when a difference is fully resolved. 90 bool IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, 91 const MCSymbolRefExpr *A, 92 const MCSymbolRefExpr *B, 93 bool InSet) const; 94 95 virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, 96 const MCSymbolData &DataA, 97 const MCSymbolData *DataB, 98 const MCFragment &FB, 99 bool InSet, 100 bool IsPCRel) const; 101 102 /// \brief True if this symbol (which is a variable) is weak. This is not 103 /// just STB_WEAK, but more generally whether or not we can evaluate 104 /// past it. 105 virtual bool isWeak(const MCSymbolData &SD) const; 106 107 /// \brief Write the object file. 108 /// 109 /// This routine is called by the assembler after layout and relaxation is 110 /// complete, fixups have been evaluated and applied, and relocations 111 /// generated. 112 virtual void WriteObject(MCAssembler &Asm, 113 const MCAsmLayout &Layout) = 0; 114 115 /// @} 116 /// @name Binary Output 117 /// @{ 118 119 void Write8(uint8_t Value) { 120 OS << char(Value); 121 } 122 123 void WriteLE16(uint16_t Value) { 124 support::endian::Writer<support::little>(OS).write(Value); 125 } 126 127 void WriteLE32(uint32_t Value) { 128 support::endian::Writer<support::little>(OS).write(Value); 129 } 130 131 void WriteLE64(uint64_t Value) { 132 support::endian::Writer<support::little>(OS).write(Value); 133 } 134 135 void WriteBE16(uint16_t Value) { 136 support::endian::Writer<support::big>(OS).write(Value); 137 } 138 139 void WriteBE32(uint32_t Value) { 140 support::endian::Writer<support::big>(OS).write(Value); 141 } 142 143 void WriteBE64(uint64_t Value) { 144 support::endian::Writer<support::big>(OS).write(Value); 145 } 146 147 void Write16(uint16_t Value) { 148 if (IsLittleEndian) 149 WriteLE16(Value); 150 else 151 WriteBE16(Value); 152 } 153 154 void Write32(uint32_t Value) { 155 if (IsLittleEndian) 156 WriteLE32(Value); 157 else 158 WriteBE32(Value); 159 } 160 161 void Write64(uint64_t Value) { 162 if (IsLittleEndian) 163 WriteLE64(Value); 164 else 165 WriteBE64(Value); 166 } 167 168 void WriteZeros(unsigned N) { 169 const char Zeros[16] = { 0 }; 170 171 for (unsigned i = 0, e = N / 16; i != e; ++i) 172 OS << StringRef(Zeros, 16); 173 174 OS << StringRef(Zeros, N % 16); 175 } 176 177 void WriteBytes(const SmallVectorImpl<char> &ByteVec, unsigned ZeroFillSize = 0) { 178 WriteBytes(StringRef(ByteVec.data(), ByteVec.size()), ZeroFillSize); 179 } 180 181 void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) { 182 // TODO: this version may need to go away once all fragment contents are 183 // converted to SmallVector<char, N> 184 assert((ZeroFillSize == 0 || Str.size () <= ZeroFillSize) && 185 "data size greater than fill size, unexpected large write will occur"); 186 OS << Str; 187 if (ZeroFillSize) 188 WriteZeros(ZeroFillSize - Str.size()); 189 } 190 191 /// @} 192 193 }; 194 195 } // End llvm namespace 196 197 #endif 198