1 //===- MipsGOT.h ----------------------------------------------------------===//
2 //
3 //                     The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #ifndef TARGET_MIPS_MIPSGOT_H_
10 #define TARGET_MIPS_MIPSGOT_H_
11 #include "mcld/ADT/SizeTraits.h"
12 #include "mcld/Fragment/Relocation.h"
13 #include "mcld/Support/MemoryRegion.h"
14 #include "mcld/Target/GOT.h"
15 
16 #include <llvm/ADT/DenseMap.h>
17 #include <llvm/ADT/DenseSet.h>
18 
19 #include <map>
20 #include <set>
21 #include <vector>
22 
23 namespace mcld {
24 
25 class Input;
26 class LDSection;
27 class LDSymbol;
28 class OutputRelocSection;
29 
30 /** \class MipsGOT
31  *  \brief Mips Global Offset Table.
32  */
33 class MipsGOT : public GOT {
34  public:
35   explicit MipsGOT(LDSection& pSection);
36 
37   /// Assign value to the GOT entry.
38   virtual void setEntryValue(Fragment* entry, uint64_t pValue) = 0;
39 
40   /// Emit the global offset table.
41   virtual uint64_t emit(MemoryRegion& pRegion) = 0;
42 
43   /// Address of _gp_disp symbol.
44   uint64_t getGPDispAddress() const;
45 
46   void initializeScan(const Input& pInput);
47   void finalizeScan(const Input& pInput);
48 
49   bool reserveLocalEntry(ResolveInfo& pInfo,
50                          int reloc,
51                          Relocation::DWord pAddend);
52   bool reserveGlobalEntry(ResolveInfo& pInfo);
53 
54   size_t getLocalNum() const;   ///< number of local symbols in primary GOT
55   size_t getGlobalNum() const;  ///< total number of global symbols
56 
57   bool isPrimaryGOTConsumed();
58 
59   Fragment* consumeLocal();
60   Fragment* consumeGlobal();
61 
62   uint64_t getGPAddr(const Input& pInput) const;
63   uint64_t getGPRelOffset(const Input& pInput, const Fragment& pEntry) const;
64 
65   void recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry);
66   Fragment* lookupGlobalEntry(const ResolveInfo* pInfo);
67 
68   void recordLocalEntry(const ResolveInfo* pInfo,
69                         Relocation::DWord pAddend,
70                         Fragment* pEntry);
71   Fragment* lookupLocalEntry(const ResolveInfo* pInfo,
72                              Relocation::DWord pAddend);
73 
74   /// hasGOT1 - return if this got section has any GOT1 entry
75   bool hasGOT1() const;
76 
77   bool hasMultipleGOT() const;
78 
79   /// Create GOT entries and reserve dynrel entries.
80   void finalizeScanning(OutputRelocSection& pRelDyn);
81 
82   /// Compare two symbols to define order in the .dynsym.
83   bool dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const;
84 
85  protected:
86   /// Create GOT entry.
87   virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent) = 0;
88 
89   /// Size of GOT entry.
90   virtual size_t getEntrySize() const = 0;
91 
92   /// Reserve GOT header entries.
93   virtual void reserveHeader() = 0;
94 
95  private:
96   /** \class GOTMultipart
97    *  \brief GOTMultipart counts local and global entries in the GOT.
98    */
99   struct GOTMultipart {
100     explicit GOTMultipart(size_t local = 0, size_t global = 0);
101 
102     typedef llvm::DenseSet<const Input*> InputSetType;
103 
104     size_t m_LocalNum;   ///< number of reserved local entries
105     size_t m_GlobalNum;  ///< number of reserved global entries
106 
107     size_t m_ConsumedLocal;   ///< consumed local entries
108     size_t m_ConsumedGlobal;  ///< consumed global entries
109 
110     Fragment* m_pLastLocal;   ///< the last consumed local entry
111     Fragment* m_pLastGlobal;  ///< the last consumed global entry
112 
113     InputSetType m_Inputs;
114 
115     bool isConsumed() const;
116 
117     void consumeLocal();
118     void consumeGlobal();
119   };
120 
121   /** \class LocalEntry
122    *  \brief LocalEntry local GOT entry descriptor.
123    */
124   struct LocalEntry {
125     const ResolveInfo* m_pInfo;
126     Relocation::DWord m_Addend;
127     bool m_IsGot16;
128 
129     LocalEntry(const ResolveInfo* pInfo,
130                Relocation::DWord addend,
131                bool isGot16);
132 
133     bool operator<(const LocalEntry& O) const;
134   };
135 
136   typedef std::vector<GOTMultipart> MultipartListType;
137 
138   // Set of global symbols.
139   typedef llvm::DenseSet<const ResolveInfo*> SymbolSetType;
140   // Map of symbols. If value is true, the symbol is referenced
141   // in the current input only. If value is false, the symbol
142   // is referenced in the other modules merged to the current GOT.
143   typedef llvm::DenseMap<const ResolveInfo*, bool> SymbolUniqueMapType;
144 
145   // Set of local symbols.
146   typedef std::set<LocalEntry> LocalSymbolSetType;
147 
148   MultipartListType m_MultipartList;  ///< list of GOT's descriptors
149   const Input* m_pInput;              ///< current input
150 
151   // Global symbols merged to the current GOT
152   // except symbols from the current input.
153   SymbolSetType m_MergedGlobalSymbols;
154   // Global symbols from the current input.
155   SymbolUniqueMapType m_InputGlobalSymbols;
156   // Local symbols merged to the current GOT
157   // except symbols from the current input.
158   LocalSymbolSetType m_MergedLocalSymbols;
159   // Local symbols from the current input.
160   LocalSymbolSetType m_InputLocalSymbols;
161 
162   size_t m_CurrentGOTPart;
163 
164   typedef llvm::DenseMap<const LDSymbol*, unsigned> SymbolOrderMapType;
165   SymbolOrderMapType m_SymbolOrderMap;
166 
167   void initGOTList();
168 
169   void changeInput();
170   bool isGOTFull() const;
171   void split();
172   void reserve(size_t pNum);
173 
174  private:
175   struct GotEntryKey {
176     size_t m_GOTPage;
177     const ResolveInfo* m_pInfo;
178     Relocation::DWord m_Addend;
179 
180     bool operator<(const GotEntryKey& key) const {
181       if (m_GOTPage != key.m_GOTPage)
182         return m_GOTPage < key.m_GOTPage;
183 
184       if (m_pInfo != key.m_pInfo)
185         return m_pInfo < key.m_pInfo;
186 
187       return m_Addend < key.m_Addend;
188     }
189   };
190 
191   typedef std::map<GotEntryKey, Fragment*> GotEntryMapType;
192   GotEntryMapType m_GotLocalEntriesMap;
193   GotEntryMapType m_GotGlobalEntriesMap;
194 };
195 
196 /** \class Mips32GOT
197  *  \brief Mips 32-bit Global Offset Table.
198  */
199 class Mips32GOT : public MipsGOT {
200  public:
201   explicit Mips32GOT(LDSection& pSection);
202 
203  private:
204   typedef GOT::Entry<4> Mips32GOTEntry;
205 
206   // MipsGOT
207   virtual void setEntryValue(Fragment* entry, uint64_t pValue);
208   virtual uint64_t emit(MemoryRegion& pRegion);
209   virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
210   virtual size_t getEntrySize() const;
211   virtual void reserveHeader();
212 };
213 
214 /** \class Mips64GOT
215  *  \brief Mips 64-bit Global Offset Table.
216  */
217 class Mips64GOT : public MipsGOT {
218  public:
219   explicit Mips64GOT(LDSection& pSection);
220 
221  private:
222   typedef GOT::Entry<8> Mips64GOTEntry;
223 
224   // MipsGOT
225   virtual void setEntryValue(Fragment* entry, uint64_t pValue);
226   virtual uint64_t emit(MemoryRegion& pRegion);
227   virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
228   virtual size_t getEntrySize() const;
229   virtual void reserveHeader();
230 };
231 
232 }  // namespace mcld
233 
234 #endif  // TARGET_MIPS_MIPSGOT_H_
235