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