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
23namespace mcld {
24
25class Input;
26class LDSection;
27class LDSymbol;
28class OutputRelocSection;
29
30/** \class MipsGOT
31 *  \brief Mips Global Offset Table.
32 */
33class 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  bool reserveTLSGdEntry(ResolveInfo& pInfo);
54  bool reserveTLSGotEntry(ResolveInfo& pInfo);
55  bool reserveTLSLdmEntry();
56
57  size_t getLocalNum() const;   ///< number of local symbols in primary GOT
58  size_t getGlobalNum() const;  ///< total number of global symbols
59
60  bool isPrimaryGOTConsumed();
61
62  Fragment* consumeLocal();
63  Fragment* consumeGlobal();
64  Fragment* consumeTLS(Relocation::Type pType);
65
66  uint64_t getGPAddr(const Input& pInput) const;
67  uint64_t getGPRelOffset(const Input& pInput, const Fragment& pEntry) const;
68
69  void recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry);
70  Fragment* lookupGlobalEntry(const ResolveInfo* pInfo);
71
72  void recordTLSEntry(const ResolveInfo* pInfo, Fragment* pEntry,
73                      Relocation::Type pType);
74  Fragment* lookupTLSEntry(const ResolveInfo* pInfo, Relocation::Type pType);
75
76  void recordLocalEntry(const ResolveInfo* pInfo,
77                        Relocation::DWord pAddend,
78                        Fragment* pEntry);
79  Fragment* lookupLocalEntry(const ResolveInfo* pInfo,
80                             Relocation::DWord pAddend);
81
82  /// hasGOT1 - return if this got section has any GOT1 entry
83  bool hasGOT1() const;
84
85  bool hasMultipleGOT() const;
86
87  /// Create GOT entries and reserve dynrel entries.
88  void finalizeScanning(OutputRelocSection& pRelDyn);
89
90  /// Compare two symbols to define order in the .dynsym.
91  bool dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const;
92
93 protected:
94  /// Create GOT entry.
95  virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent) = 0;
96
97  /// Size of GOT entry.
98  virtual size_t getEntrySize() const = 0;
99
100  /// Reserve GOT header entries.
101  virtual void reserveHeader() = 0;
102
103 private:
104  /** \class GOTMultipart
105   *  \brief GOTMultipart counts local and global entries in the GOT.
106   */
107  struct GOTMultipart {
108    explicit GOTMultipart(size_t local = 0, size_t global = 0);
109
110    typedef llvm::DenseSet<const Input*> InputSetType;
111
112    size_t m_LocalNum;   ///< number of reserved local entries
113    size_t m_GlobalNum;  ///< number of reserved global entries
114    size_t m_TLSNum;     ///< number of reserved TLS entries
115    size_t m_TLSDynNum;  ///< number of reserved TLS related dynamic relocations
116
117    size_t m_ConsumedLocal;   ///< consumed local entries
118    size_t m_ConsumedGlobal;  ///< consumed global entries
119    size_t m_ConsumedTLS;     ///< consumed TLS entries
120
121    Fragment* m_pLastLocal;   ///< the last consumed local entry
122    Fragment* m_pLastGlobal;  ///< the last consumed global entry
123    Fragment* m_pLastTLS;     ///< the last consumed TLS entry
124
125    InputSetType m_Inputs;
126
127    bool isConsumed() const;
128
129    void consumeLocal();
130    void consumeGlobal();
131    void consumeTLS(Relocation::Type pType);
132  };
133
134  /** \class LocalEntry
135   *  \brief LocalEntry local GOT entry descriptor.
136   */
137  struct LocalEntry {
138    const ResolveInfo* m_pInfo;
139    Relocation::DWord m_Addend;
140    bool m_IsGot16;
141
142    LocalEntry(const ResolveInfo* pInfo,
143               Relocation::DWord addend,
144               bool isGot16);
145
146    bool operator<(const LocalEntry& O) const;
147  };
148
149  typedef std::vector<GOTMultipart> MultipartListType;
150
151  // Set of global symbols.
152  typedef llvm::DenseSet<const ResolveInfo*> SymbolSetType;
153  // Map of symbols. If value is true, the symbol is referenced
154  // in the current input only. If value is false, the symbol
155  // is referenced in the other modules merged to the current GOT.
156  typedef llvm::DenseMap<const ResolveInfo*, bool> SymbolUniqueMapType;
157
158  // Set of local symbols.
159  typedef std::set<LocalEntry> LocalSymbolSetType;
160
161  MultipartListType m_MultipartList;  ///< list of GOT's descriptors
162  const Input* m_pInput;              ///< current input
163
164  // Global symbols merged to the current GOT
165  // except symbols from the current input.
166  SymbolSetType m_MergedGlobalSymbols;
167  // Global symbols from the current input.
168  SymbolUniqueMapType m_InputGlobalSymbols;
169  // Set of symbols referenced by TLS GD relocations.
170  SymbolSetType m_InputTLSGdSymbols;
171  // Set of symbols referenced by TLS GOTTPREL relocation.
172  SymbolSetType m_InputTLSGotSymbols;
173  // There is a symbol referenced by TLS LDM relocations.
174  bool m_HasTLSLdmSymbol;
175  // Local symbols merged to the current GOT
176  // except symbols from the current input.
177  LocalSymbolSetType m_MergedLocalSymbols;
178  // Local symbols from the current input.
179  LocalSymbolSetType m_InputLocalSymbols;
180
181  size_t m_CurrentGOTPart;
182
183  typedef llvm::DenseMap<const LDSymbol*, unsigned> SymbolOrderMapType;
184  SymbolOrderMapType m_SymbolOrderMap;
185
186  void initGOTList();
187
188  void changeInput();
189  bool isGOTFull() const;
190  void split();
191  void reserve(size_t pNum);
192
193 private:
194  struct GotEntryKey {
195    size_t m_GOTPage;
196    const ResolveInfo* m_pInfo;
197    Relocation::DWord m_Addend;
198
199    bool operator<(const GotEntryKey& key) const {
200      if (m_GOTPage != key.m_GOTPage)
201        return m_GOTPage < key.m_GOTPage;
202
203      if (m_pInfo != key.m_pInfo)
204        return m_pInfo < key.m_pInfo;
205
206      return m_Addend < key.m_Addend;
207    }
208  };
209
210  typedef std::map<GotEntryKey, Fragment*> GotEntryMapType;
211  GotEntryMapType m_GotLocalEntriesMap;
212  GotEntryMapType m_GotGlobalEntriesMap;
213  GotEntryMapType m_GotTLSGdEntriesMap;
214  GotEntryMapType m_GotTLSGotEntriesMap;
215  Fragment* m_GotTLSLdmEntry;
216};
217
218/** \class Mips32GOT
219 *  \brief Mips 32-bit Global Offset Table.
220 */
221class Mips32GOT : public MipsGOT {
222 public:
223  explicit Mips32GOT(LDSection& pSection);
224
225 private:
226  typedef GOT::Entry<4> Mips32GOTEntry;
227
228  // MipsGOT
229  virtual void setEntryValue(Fragment* entry, uint64_t pValue);
230  virtual uint64_t emit(MemoryRegion& pRegion);
231  virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
232  virtual size_t getEntrySize() const;
233  virtual void reserveHeader();
234};
235
236/** \class Mips64GOT
237 *  \brief Mips 64-bit Global Offset Table.
238 */
239class Mips64GOT : public MipsGOT {
240 public:
241  explicit Mips64GOT(LDSection& pSection);
242
243 private:
244  typedef GOT::Entry<8> Mips64GOTEntry;
245
246  // MipsGOT
247  virtual void setEntryValue(Fragment* entry, uint64_t pValue);
248  virtual uint64_t emit(MemoryRegion& pRegion);
249  virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
250  virtual size_t getEntrySize() const;
251  virtual void reserveHeader();
252};
253
254}  // namespace mcld
255
256#endif  // TARGET_MIPS_MIPSGOT_H_
257