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