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
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 */
199class 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 */
217class 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