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.
MCObjectWriter(raw_pwrite_stream & OS,bool IsLittleEndian)50   MCObjectWriter(raw_pwrite_stream &OS, bool IsLittleEndian)
51       : OS(OS), IsLittleEndian(IsLittleEndian) {}
52 
53 public:
54   virtual ~MCObjectWriter();
55 
56   /// lifetime management
reset()57   virtual void reset() { }
58 
isLittleEndian()59   bool isLittleEndian() const { return IsLittleEndian; }
60 
getStream()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 
Write8(uint8_t Value)119   void Write8(uint8_t Value) {
120     OS << char(Value);
121   }
122 
WriteLE16(uint16_t Value)123   void WriteLE16(uint16_t Value) {
124     support::endian::Writer<support::little>(OS).write(Value);
125   }
126 
WriteLE32(uint32_t Value)127   void WriteLE32(uint32_t Value) {
128     support::endian::Writer<support::little>(OS).write(Value);
129   }
130 
WriteLE64(uint64_t Value)131   void WriteLE64(uint64_t Value) {
132     support::endian::Writer<support::little>(OS).write(Value);
133   }
134 
WriteBE16(uint16_t Value)135   void WriteBE16(uint16_t Value) {
136     support::endian::Writer<support::big>(OS).write(Value);
137   }
138 
WriteBE32(uint32_t Value)139   void WriteBE32(uint32_t Value) {
140     support::endian::Writer<support::big>(OS).write(Value);
141   }
142 
WriteBE64(uint64_t Value)143   void WriteBE64(uint64_t Value) {
144     support::endian::Writer<support::big>(OS).write(Value);
145   }
146 
Write16(uint16_t Value)147   void Write16(uint16_t Value) {
148     if (IsLittleEndian)
149       WriteLE16(Value);
150     else
151       WriteBE16(Value);
152   }
153 
Write32(uint32_t Value)154   void Write32(uint32_t Value) {
155     if (IsLittleEndian)
156       WriteLE32(Value);
157     else
158       WriteBE32(Value);
159   }
160 
Write64(uint64_t Value)161   void Write64(uint64_t Value) {
162     if (IsLittleEndian)
163       WriteLE64(Value);
164     else
165       WriteBE64(Value);
166   }
167 
WriteZeros(unsigned N)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