MipsGOT.cpp revision f7ac0f19a1c8d0ad14bcf6456ce368b830fea886
1//===- MipsGOT.cpp --------------------------------------------------------===//
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
10#include <llvm/Support/Casting.h>
11#include <llvm/Support/ELF.h>
12
13#include <mcld/LD/ResolveInfo.h>
14#include <mcld/Support/MemoryRegion.h>
15#include <mcld/Support/MsgHandling.h>
16#include <mcld/Target/OutputRelocSection.h>
17
18#include "MipsGOT.h"
19#include "MipsRelocator.h"
20
21namespace {
22  const size_t MipsGOT0Num = 1;
23  const size_t MipsGOTGpOffset = 0x7FF0;
24  const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF;
25}
26
27using namespace mcld;
28
29//===----------------------------------------------------------------------===//
30// MipsGOTEntry
31//===----------------------------------------------------------------------===//
32MipsGOTEntry::MipsGOTEntry(uint64_t pContent, SectionData* pParent)
33   : GOT::Entry<4>(pContent, pParent)
34{}
35
36//===----------------------------------------------------------------------===//
37// MipsGOT::GOTMultipart
38//===----------------------------------------------------------------------===//
39MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global)
40  : m_LocalNum(local),
41    m_GlobalNum(global),
42    m_ConsumedLocal(0),
43    m_ConsumedGlobal(0),
44    m_pLastLocal(NULL),
45    m_pLastGlobal(NULL)
46{
47}
48
49bool MipsGOT::GOTMultipart::isConsumed() const
50{
51  return m_LocalNum == m_ConsumedLocal &&
52         m_GlobalNum == m_ConsumedGlobal;
53}
54
55void MipsGOT::GOTMultipart::consumeLocal()
56{
57  assert(m_ConsumedLocal < m_LocalNum &&
58         "Consumed too many local GOT entries");
59  ++m_ConsumedLocal;
60  m_pLastLocal = llvm::cast<MipsGOTEntry>(m_pLastLocal->getNextNode());
61}
62
63void MipsGOT::GOTMultipart::consumeGlobal()
64{
65  assert(m_ConsumedGlobal < m_GlobalNum &&
66         "Consumed too many global GOT entries");
67  ++m_ConsumedGlobal;
68  m_pLastGlobal = llvm::cast<MipsGOTEntry>(m_pLastGlobal->getNextNode());
69}
70
71//===----------------------------------------------------------------------===//
72// MipsGOT
73//===----------------------------------------------------------------------===//
74MipsGOT::MipsGOT(LDSection& pSection)
75  : GOT(pSection),
76    m_pInput(NULL),
77    m_CurrentGOTPart(0)
78{
79}
80
81SizeTraits<32>::Address MipsGOT::getGPDispAddress() const
82{
83  return addr() + MipsGOTGpOffset;
84}
85
86void MipsGOT::reserve(size_t pNum)
87{
88  for (size_t i = 0; i < pNum; i++) {
89    new MipsGOTEntry(0, m_SectionData);
90  }
91}
92
93bool MipsGOT::hasGOT1() const
94{
95  return !m_MultipartList.empty();
96}
97
98bool MipsGOT::hasMultipleGOT() const
99{
100  return m_MultipartList.size() > 1;
101}
102
103void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn)
104{
105  for (MultipartListType::iterator it = m_MultipartList.begin();
106       it != m_MultipartList.end(); ++it) {
107    reserve(MipsGOT0Num);
108    it->m_pLastLocal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
109    reserve(it->m_LocalNum);
110    it->m_pLastGlobal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
111    reserve(it->m_GlobalNum);
112
113    if (it == m_MultipartList.begin())
114      // Reserve entries in the second part of the primary GOT.
115      // These entries correspond to the global symbols in all
116      // non-primary GOTs.
117      reserve(getGlobalNum() - it->m_GlobalNum);
118    else {
119      // Reserve reldyn entries for R_MIPS_REL32 relocations
120      // for all global entries of secondary GOTs.
121      // FIXME: (simon) Do not count local entries for non-pic.
122      size_t count = it->m_GlobalNum + it->m_LocalNum;
123      for (size_t i = 0; i < count; ++i)
124        pRelDyn.reserveEntry();
125    }
126  }
127}
128
129bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const
130{
131  SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX);
132  SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY);
133
134  if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end())
135    return itX->second < itY->second;
136
137  return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end();
138}
139
140uint64_t MipsGOT::emit(MemoryRegion& pRegion)
141{
142  uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
143
144  uint64_t result = 0;
145  for (iterator it = begin(), ie = end();
146       it != ie; ++it, ++buffer) {
147    MipsGOTEntry* got = &(llvm::cast<MipsGOTEntry>((*it)));
148    *buffer = static_cast<uint32_t>(got->getValue());
149    result += got->size();
150  }
151  return result;
152}
153
154void MipsGOT::initGOTList()
155{
156  m_SymbolOrderMap.clear();
157
158  m_MultipartList.clear();
159  m_MultipartList.push_back(GOTMultipart());
160
161  m_MultipartList.back().m_Inputs.insert(m_pInput);
162
163  m_MergedGlobalSymbols.clear();
164  m_InputGlobalSymbols.clear();
165  m_MergedLocalSymbols.clear();
166  m_InputLocalSymbols.clear();
167}
168
169void MipsGOT::changeInput()
170{
171  m_MultipartList.back().m_Inputs.insert(m_pInput);
172
173  for (SymbolSetType::iterator it = m_InputLocalSymbols.begin(),
174                               end = m_InputLocalSymbols.end();
175       it != end; ++it)
176    m_MergedLocalSymbols.insert(*it);
177
178  m_InputLocalSymbols.clear();
179
180  for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(),
181                                     end = m_InputGlobalSymbols.end();
182       it != end; ++it)
183    m_MergedGlobalSymbols.insert(it->first);
184
185  m_InputGlobalSymbols.clear();
186}
187
188bool MipsGOT::isGOTFull() const
189{
190  uint64_t gotCount = MipsGOT0Num +
191                      m_MultipartList.back().m_LocalNum +
192                      m_MultipartList.back().m_GlobalNum;
193
194  gotCount += 1;
195
196  return (gotCount * mcld::MipsGOTEntry::EntrySize) > MipsGOTSize;
197}
198
199void MipsGOT::split()
200{
201  m_MergedLocalSymbols.clear();
202  m_MergedGlobalSymbols.clear();
203
204  size_t uniqueCount = 0;
205  for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(),
206                                           end = m_InputGlobalSymbols.end();
207       it != end; ++it) {
208    if (it->second)
209      ++uniqueCount;
210  }
211
212  m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size();
213  m_MultipartList.back().m_GlobalNum -= uniqueCount;
214  m_MultipartList.back().m_Inputs.erase(m_pInput);
215
216  m_MultipartList.push_back(GOTMultipart(m_InputLocalSymbols.size(),
217                                         m_InputGlobalSymbols.size()));
218  m_MultipartList.back().m_Inputs.insert(m_pInput);
219}
220
221void MipsGOT::initializeScan(const Input& pInput)
222{
223  if (m_pInput == NULL) {
224    m_pInput = &pInput;
225    initGOTList();
226  }
227  else {
228    m_pInput = &pInput;
229    changeInput();
230  }
231}
232
233void MipsGOT::finalizeScan(const Input& pInput)
234{
235}
236
237bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo)
238{
239  if (pInfo.type() != ResolveInfo::Section) {
240    if (m_InputLocalSymbols.count(&pInfo))
241      return false;
242
243    if (m_MergedLocalSymbols.count(&pInfo)) {
244      m_InputLocalSymbols.insert(&pInfo);
245      return false;
246    }
247  }
248
249  if (isGOTFull())
250    split();
251
252  if (pInfo.type() != ResolveInfo::Section)
253    m_InputLocalSymbols.insert(&pInfo);
254
255  ++m_MultipartList.back().m_LocalNum;
256  return true;
257}
258
259bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo)
260{
261  if (m_InputGlobalSymbols.count(&pInfo))
262    return false;
263
264  if (m_MergedGlobalSymbols.count(&pInfo)) {
265    m_InputGlobalSymbols[&pInfo] = false;
266    return false;
267  }
268
269  if (isGOTFull())
270    split();
271
272  m_InputGlobalSymbols[&pInfo] = true;
273  ++m_MultipartList.back().m_GlobalNum;
274
275  if (!(pInfo.reserved() & MipsRelocator::ReserveGot)) {
276    m_SymbolOrderMap[pInfo.outSymbol()] = m_SymbolOrderMap.size();
277    pInfo.setReserved(pInfo.reserved() | MipsRelocator::ReserveGot);
278  }
279
280  return true;
281}
282
283bool MipsGOT::isPrimaryGOTConsumed()
284{
285  return m_CurrentGOTPart > 0;
286}
287
288MipsGOTEntry* MipsGOT::consumeLocal()
289{
290  assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
291
292  if (m_MultipartList[m_CurrentGOTPart].isConsumed())
293    ++m_CurrentGOTPart;
294
295  m_MultipartList[m_CurrentGOTPart].consumeLocal();
296
297  return m_MultipartList[m_CurrentGOTPart].m_pLastLocal;
298}
299
300MipsGOTEntry* MipsGOT::consumeGlobal()
301{
302  assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
303
304  if (m_MultipartList[m_CurrentGOTPart].isConsumed())
305    ++m_CurrentGOTPart;
306
307  m_MultipartList[m_CurrentGOTPart].consumeGlobal();
308
309  return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal;
310}
311
312SizeTraits<32>::Address MipsGOT::getGPAddr(const Input& pInput) const
313{
314  uint64_t gotSize = 0;
315  for (MultipartListType::const_iterator it = m_MultipartList.begin();
316                                         it != m_MultipartList.end(); ++it) {
317    if (it->m_Inputs.count(&pInput))
318      break;
319
320    gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum);
321    if (it == m_MultipartList.begin())
322      gotSize += getGlobalNum() - it->m_GlobalNum;
323  }
324
325  return addr() + gotSize * MipsGOTEntry::EntrySize + MipsGOTGpOffset;
326}
327
328SizeTraits<32>::Offset MipsGOT::getGPRelOffset(const Input& pInput,
329                                               const MipsGOTEntry& pEntry) const
330{
331  SizeTraits<32>::Address gpAddr = getGPAddr(pInput);
332  return addr() + pEntry.getOffset() - gpAddr;
333}
334
335void MipsGOT::recordEntry(const ResolveInfo* pInfo, MipsGOTEntry* pEntry)
336{
337  GotEntryKey key;
338  key.m_GOTPage = m_CurrentGOTPart;
339  key.m_pInfo = pInfo;
340  m_GotEntriesMap[key] = pEntry;
341}
342
343MipsGOTEntry* MipsGOT::lookupEntry(const ResolveInfo* pInfo)
344{
345  GotEntryKey key;
346  key.m_GOTPage= m_CurrentGOTPart;
347  key.m_pInfo = pInfo;
348  GotEntryMapType::iterator it = m_GotEntriesMap.find(key);
349
350  if (it == m_GotEntriesMap.end())
351    return NULL;
352
353  return it->second;
354}
355
356size_t MipsGOT::getLocalNum() const
357{
358  assert(!m_MultipartList.empty() && "GOT is empty!");
359  return m_MultipartList[0].m_LocalNum + MipsGOT0Num;
360}
361
362size_t MipsGOT::getGlobalNum() const
363{
364  return m_SymbolOrderMap.size();
365}
366