MipsGOT.cpp revision cfcb22478ca64c308df58f9abe6fa2dedb213c16
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 "mcld/LD/ResolveInfo.h"
11#include "mcld/Support/MsgHandling.h"
12#include "mcld/Target/OutputRelocSection.h"
13
14#include "MipsGOT.h"
15#include "MipsRelocator.h"
16
17#include <llvm/Support/Casting.h>
18#include <llvm/Support/ELF.h>
19
20namespace {
21const uint32_t Mips32ModulePtr = 1 << 31;
22const uint64_t Mips64ModulePtr = 1ull << 63;
23const size_t MipsGOT0Num = 2;
24const size_t MipsGOTGpOffset = 0x7FF0;
25const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF;
26}
27
28namespace mcld {
29
30//===----------------------------------------------------------------------===//
31// MipsGOT::GOTMultipart
32//===----------------------------------------------------------------------===//
33MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global)
34    : m_LocalNum(local),
35      m_GlobalNum(global),
36      m_TLSNum(0),
37      m_TLSDynNum(0),
38      m_ConsumedLocal(0),
39      m_ConsumedGlobal(0),
40      m_ConsumedTLS(0),
41      m_pLastLocal(NULL),
42      m_pLastGlobal(NULL),
43      m_pLastTLS(NULL) {
44}
45
46bool MipsGOT::GOTMultipart::isConsumed() const {
47  return m_LocalNum == m_ConsumedLocal && m_GlobalNum == m_ConsumedGlobal &&
48         m_TLSNum == m_ConsumedTLS;
49}
50
51void MipsGOT::GOTMultipart::consumeLocal() {
52  assert(m_ConsumedLocal < m_LocalNum && "Consumed too many local GOT entries");
53  ++m_ConsumedLocal;
54  m_pLastLocal = m_pLastLocal->getNextNode();
55}
56
57void MipsGOT::GOTMultipart::consumeGlobal() {
58  assert(m_ConsumedGlobal < m_GlobalNum &&
59         "Consumed too many global GOT entries");
60  ++m_ConsumedGlobal;
61  m_pLastGlobal = m_pLastGlobal->getNextNode();
62}
63
64void MipsGOT::GOTMultipart::consumeTLS(Relocation::Type pType) {
65  assert(m_ConsumedTLS < m_TLSNum &&
66         "Consumed too many TLS GOT entries");
67  m_ConsumedTLS += pType == llvm::ELF::R_MIPS_TLS_GOTTPREL ? 1 : 2;
68  m_pLastTLS = m_pLastTLS->getNextNode();
69}
70
71//===----------------------------------------------------------------------===//
72// MipsGOT::LocalEntry
73//===----------------------------------------------------------------------===//
74MipsGOT::LocalEntry::LocalEntry(const ResolveInfo* pInfo,
75                                Relocation::DWord addend,
76                                bool isGot16)
77    : m_pInfo(pInfo), m_Addend(addend), m_IsGot16(isGot16) {
78}
79
80bool MipsGOT::LocalEntry::operator<(const LocalEntry& O) const {
81  if (m_pInfo != O.m_pInfo)
82    return m_pInfo < O.m_pInfo;
83
84  if (m_Addend != O.m_Addend)
85    return m_Addend < O.m_Addend;
86
87  return m_IsGot16 < O.m_IsGot16;
88}
89
90//===----------------------------------------------------------------------===//
91// MipsGOT
92//===----------------------------------------------------------------------===//
93MipsGOT::MipsGOT(LDSection& pSection)
94    : GOT(pSection),
95      m_pInput(NULL),
96      m_HasTLSLdmSymbol(false),
97      m_CurrentGOTPart(0),
98      m_GotTLSLdmEntry(nullptr) {
99}
100
101uint64_t MipsGOT::getGPDispAddress() const {
102  return addr() + MipsGOTGpOffset;
103}
104
105void MipsGOT::reserve(size_t pNum) {
106  for (size_t i = 0; i < pNum; ++i)
107    createEntry(0, m_SectionData);
108}
109
110bool MipsGOT::hasGOT1() const {
111  return !m_MultipartList.empty();
112}
113
114bool MipsGOT::hasMultipleGOT() const {
115  return m_MultipartList.size() > 1;
116}
117
118void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn) {
119  for (MultipartListType::iterator it = m_MultipartList.begin();
120       it != m_MultipartList.end();
121       ++it) {
122    reserveHeader();
123    it->m_pLastLocal = &m_SectionData->back();
124    reserve(it->m_LocalNum);
125    it->m_pLastGlobal = &m_SectionData->back();
126    reserve(it->m_GlobalNum);
127    it->m_pLastTLS = &m_SectionData->back();
128    reserve(it->m_TLSNum);
129
130    if (it == m_MultipartList.begin()) {
131      // Reserve entries in the second part of the primary GOT.
132      // These entries correspond to the global symbols in all
133      // non-primary GOTs.
134      reserve(getGlobalNum() - it->m_GlobalNum);
135    } else {
136      // Reserve reldyn entries for R_MIPS_REL32 relocations
137      // for all global entries of secondary GOTs.
138      // FIXME: (simon) Do not count local entries for non-pic.
139      size_t count = it->m_GlobalNum + it->m_LocalNum;
140      for (size_t i = 0; i < count; ++i)
141        pRelDyn.reserveEntry();
142    }
143
144    for (size_t i = 0; i < it->m_TLSDynNum; ++i)
145      pRelDyn.reserveEntry();
146  }
147}
148
149bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const {
150  SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX);
151  SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY);
152
153  if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end())
154    return itX->second < itY->second;
155
156  return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end();
157}
158
159void MipsGOT::initGOTList() {
160  m_SymbolOrderMap.clear();
161
162  m_MultipartList.clear();
163  m_MultipartList.push_back(GOTMultipart());
164
165  m_MultipartList.back().m_Inputs.insert(m_pInput);
166
167  m_MergedGlobalSymbols.clear();
168  m_InputGlobalSymbols.clear();
169  m_MergedLocalSymbols.clear();
170  m_InputLocalSymbols.clear();
171  m_InputTLSGdSymbols.clear();
172  m_HasTLSLdmSymbol = false;
173}
174
175void MipsGOT::changeInput() {
176  m_MultipartList.back().m_Inputs.insert(m_pInput);
177
178  for (LocalSymbolSetType::iterator it = m_InputLocalSymbols.begin(),
179                                    end = m_InputLocalSymbols.end();
180       it != end;
181       ++it)
182    m_MergedLocalSymbols.insert(*it);
183
184  m_InputLocalSymbols.clear();
185
186  for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(),
187                                     end = m_InputGlobalSymbols.end();
188       it != end;
189       ++it)
190    m_MergedGlobalSymbols.insert(it->first);
191
192  m_InputGlobalSymbols.clear();
193}
194
195bool MipsGOT::isGOTFull() const {
196  uint64_t gotCount = MipsGOT0Num + m_MultipartList.back().m_LocalNum +
197                      m_MultipartList.back().m_GlobalNum;
198
199  gotCount += 1;
200
201  return gotCount * getEntrySize() > MipsGOTSize;
202}
203
204void MipsGOT::split() {
205  m_MergedLocalSymbols.clear();
206  m_MergedGlobalSymbols.clear();
207
208  size_t uniqueCount = 0;
209  for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(),
210                                           end = m_InputGlobalSymbols.end();
211       it != end;
212       ++it) {
213    if (it->second)
214      ++uniqueCount;
215  }
216
217  m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size();
218  m_MultipartList.back().m_GlobalNum -= uniqueCount;
219  m_MultipartList.back().m_Inputs.erase(m_pInput);
220
221  m_MultipartList.push_back(
222      GOTMultipart(m_InputLocalSymbols.size(), m_InputGlobalSymbols.size()));
223  m_MultipartList.back().m_Inputs.insert(m_pInput);
224}
225
226void MipsGOT::initializeScan(const Input& pInput) {
227  if (m_pInput == NULL) {
228    m_pInput = &pInput;
229    initGOTList();
230  } else {
231    m_pInput = &pInput;
232    changeInput();
233  }
234}
235
236void MipsGOT::finalizeScan(const Input& pInput) {
237}
238
239bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo,
240                                int reloc,
241                                Relocation::DWord pAddend) {
242  LocalEntry entry(&pInfo, pAddend, reloc == llvm::ELF::R_MIPS_GOT16);
243
244  if (m_InputLocalSymbols.count(entry))
245    // Do nothing, if we have seen this symbol
246    // in the current input already.
247    return false;
248
249  if (m_MergedLocalSymbols.count(entry)) {
250    // We have seen this symbol in previous inputs.
251    // Remember that it exists in the current input too.
252    m_InputLocalSymbols.insert(entry);
253    return false;
254  }
255
256  if (isGOTFull())
257    split();
258
259  m_InputLocalSymbols.insert(entry);
260
261  ++m_MultipartList.back().m_LocalNum;
262  return true;
263}
264
265bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo) {
266  if (m_InputGlobalSymbols.count(&pInfo))
267    return false;
268
269  if (m_MergedGlobalSymbols.count(&pInfo)) {
270    m_InputGlobalSymbols[&pInfo] = false;
271    return false;
272  }
273
274  if (isGOTFull())
275    split();
276
277  m_InputGlobalSymbols[&pInfo] = true;
278  ++m_MultipartList.back().m_GlobalNum;
279
280  if (!(pInfo.reserved() & MipsRelocator::ReserveGot)) {
281    m_SymbolOrderMap[pInfo.outSymbol()] = m_SymbolOrderMap.size();
282    pInfo.setReserved(pInfo.reserved() | MipsRelocator::ReserveGot);
283  }
284
285  return true;
286}
287
288bool MipsGOT::reserveTLSGdEntry(ResolveInfo& pInfo) {
289  if (m_InputTLSGdSymbols.count(&pInfo))
290    return false;
291
292  m_InputTLSGdSymbols.insert(&pInfo);
293  m_MultipartList.back().m_TLSNum += 2;
294  m_MultipartList.back().m_TLSDynNum += 2;
295
296  return true;
297}
298
299bool MipsGOT::reserveTLSLdmEntry() {
300  if (m_HasTLSLdmSymbol)
301    return false;
302
303  m_HasTLSLdmSymbol = true;
304  m_MultipartList.back().m_TLSNum += 2;
305  m_MultipartList.back().m_TLSDynNum += 1;
306
307  return true;
308}
309
310bool MipsGOT::reserveTLSGotEntry(ResolveInfo& pInfo) {
311  if (m_InputTLSGotSymbols.count(&pInfo))
312    return false;
313
314  m_InputTLSGotSymbols.insert(&pInfo);
315  m_MultipartList.back().m_TLSNum += 1;
316  m_MultipartList.back().m_TLSDynNum += 1;
317
318  return true;
319}
320
321bool MipsGOT::isPrimaryGOTConsumed() {
322  return m_CurrentGOTPart > 0;
323}
324
325Fragment* MipsGOT::consumeLocal() {
326  assert(m_CurrentGOTPart < m_MultipartList.size() &&
327         "GOT number is out of range!");
328
329  if (m_MultipartList[m_CurrentGOTPart].isConsumed())
330    ++m_CurrentGOTPart;
331
332  m_MultipartList[m_CurrentGOTPart].consumeLocal();
333
334  return m_MultipartList[m_CurrentGOTPart].m_pLastLocal;
335}
336
337Fragment* MipsGOT::consumeGlobal() {
338  assert(m_CurrentGOTPart < m_MultipartList.size() &&
339         "GOT number is out of range!");
340
341  if (m_MultipartList[m_CurrentGOTPart].isConsumed())
342    ++m_CurrentGOTPart;
343
344  m_MultipartList[m_CurrentGOTPart].consumeGlobal();
345
346  return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal;
347}
348
349Fragment* MipsGOT::consumeTLS(Relocation::Type pType) {
350  assert(m_CurrentGOTPart < m_MultipartList.size() &&
351         "GOT number is out of range!");
352
353  if (m_MultipartList[m_CurrentGOTPart].isConsumed())
354    ++m_CurrentGOTPart;
355
356  m_MultipartList[m_CurrentGOTPart].consumeTLS(pType);
357
358  return m_MultipartList[m_CurrentGOTPart].m_pLastTLS;
359}
360
361uint64_t MipsGOT::getGPAddr(const Input& pInput) const {
362  uint64_t gotSize = 0;
363  for (MultipartListType::const_iterator it = m_MultipartList.begin(),
364                                         ie = m_MultipartList.end();
365       it != ie;
366       ++it) {
367    if (it->m_Inputs.count(&pInput))
368      break;
369
370    gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum);
371    if (it == m_MultipartList.begin())
372      gotSize += getGlobalNum() - it->m_GlobalNum;
373  }
374
375  return addr() + gotSize * getEntrySize() + MipsGOTGpOffset;
376}
377
378uint64_t MipsGOT::getGPRelOffset(const Input& pInput,
379                                 const Fragment& pEntry) const {
380  return addr() + pEntry.getOffset() - getGPAddr(pInput);
381}
382
383void MipsGOT::recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry) {
384  GotEntryKey key;
385  key.m_GOTPage = m_CurrentGOTPart;
386  key.m_pInfo = pInfo;
387  key.m_Addend = 0;
388  m_GotGlobalEntriesMap[key] = pEntry;
389}
390
391Fragment* MipsGOT::lookupGlobalEntry(const ResolveInfo* pInfo) {
392  GotEntryKey key;
393  key.m_GOTPage = m_CurrentGOTPart;
394  key.m_pInfo = pInfo;
395  key.m_Addend = 0;
396  GotEntryMapType::iterator it = m_GotGlobalEntriesMap.find(key);
397
398  if (it == m_GotGlobalEntriesMap.end())
399    return NULL;
400
401  return it->second;
402}
403
404void MipsGOT::recordTLSEntry(const ResolveInfo* pInfo, Fragment* pEntry,
405                             Relocation::Type pType) {
406  if (pType == llvm::ELF::R_MIPS_TLS_LDM) {
407    m_GotTLSLdmEntry = pEntry;
408  } else if (pType == llvm::ELF::R_MIPS_TLS_GD) {
409    GotEntryKey key;
410    key.m_GOTPage = m_CurrentGOTPart;
411    key.m_pInfo = pInfo;
412    key.m_Addend = 0;
413    m_GotTLSGdEntriesMap[key] = pEntry;
414  } else if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) {
415    GotEntryKey key;
416    key.m_GOTPage = m_CurrentGOTPart;
417    key.m_pInfo = pInfo;
418    key.m_Addend = 0;
419    m_GotTLSGotEntriesMap[key] = pEntry;
420  } else {
421    llvm_unreachable("Unexpected relocation");
422  }
423}
424
425Fragment* MipsGOT::lookupTLSEntry(const ResolveInfo* pInfo,
426                                  Relocation::Type pType) {
427  if (pType == llvm::ELF::R_MIPS_TLS_LDM)
428    return m_GotTLSLdmEntry;
429  if (pType == llvm::ELF::R_MIPS_TLS_GD) {
430    GotEntryKey key;
431    key.m_GOTPage = m_CurrentGOTPart;
432    key.m_pInfo = pInfo;
433    key.m_Addend = 0;
434    GotEntryMapType::iterator it = m_GotTLSGdEntriesMap.find(key);
435    return it == m_GotTLSGdEntriesMap.end() ? nullptr : it->second;
436  }
437  if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) {
438    GotEntryKey key;
439    key.m_GOTPage = m_CurrentGOTPart;
440    key.m_pInfo = pInfo;
441    key.m_Addend = 0;
442    GotEntryMapType::iterator it = m_GotTLSGotEntriesMap.find(key);
443    return it == m_GotTLSGotEntriesMap.end() ? nullptr : it->second;
444  }
445  llvm_unreachable("Unexpected relocation");
446}
447
448void MipsGOT::recordLocalEntry(const ResolveInfo* pInfo,
449                               Relocation::DWord pAddend,
450                               Fragment* pEntry) {
451  GotEntryKey key;
452  key.m_GOTPage = m_CurrentGOTPart;
453  key.m_pInfo = pInfo;
454  key.m_Addend = pAddend;
455  m_GotLocalEntriesMap[key] = pEntry;
456}
457
458Fragment* MipsGOT::lookupLocalEntry(const ResolveInfo* pInfo,
459                                    Relocation::DWord pAddend) {
460  GotEntryKey key;
461  key.m_GOTPage = m_CurrentGOTPart;
462  key.m_pInfo = pInfo;
463  key.m_Addend = pAddend;
464  GotEntryMapType::iterator it = m_GotLocalEntriesMap.find(key);
465
466  if (it == m_GotLocalEntriesMap.end())
467    return NULL;
468
469  return it->second;
470}
471
472size_t MipsGOT::getLocalNum() const {
473  assert(!m_MultipartList.empty() && "GOT is empty!");
474  return m_MultipartList[0].m_LocalNum + MipsGOT0Num;
475}
476
477size_t MipsGOT::getGlobalNum() const {
478  return m_SymbolOrderMap.size();
479}
480
481//===----------------------------------------------------------------------===//
482// Mips32GOT
483//===----------------------------------------------------------------------===//
484Mips32GOT::Mips32GOT(LDSection& pSection) : MipsGOT(pSection) {
485}
486
487void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue) {
488  llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue);
489}
490
491uint64_t Mips32GOT::emit(MemoryRegion& pRegion) {
492  uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
493
494  uint64_t result = 0;
495  for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
496    Mips32GOTEntry* got = &(llvm::cast<Mips32GOTEntry>((*it)));
497    *buffer = static_cast<uint32_t>(got->getValue());
498    result += got->size();
499  }
500  return result;
501}
502
503Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent) {
504  return new Mips32GOTEntry(pValue, pParent);
505}
506
507size_t Mips32GOT::getEntrySize() const {
508  return Mips32GOTEntry::EntrySize;
509}
510
511void Mips32GOT::reserveHeader() {
512  createEntry(0, m_SectionData);
513  createEntry(Mips32ModulePtr, m_SectionData);
514}
515
516//===----------------------------------------------------------------------===//
517// Mips64GOT
518//===----------------------------------------------------------------------===//
519Mips64GOT::Mips64GOT(LDSection& pSection) : MipsGOT(pSection) {
520}
521
522void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue) {
523  llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue);
524}
525
526uint64_t Mips64GOT::emit(MemoryRegion& pRegion) {
527  uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
528
529  uint64_t result = 0;
530  for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
531    Mips64GOTEntry* got = &(llvm::cast<Mips64GOTEntry>((*it)));
532    *buffer = static_cast<uint64_t>(got->getValue());
533    result += got->size();
534  }
535  return result;
536}
537
538Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent) {
539  return new Mips64GOTEntry(pValue, pParent);
540}
541
542size_t Mips64GOT::getEntrySize() const {
543  return Mips64GOTEntry::EntrySize;
544}
545
546void Mips64GOT::reserveHeader() {
547  createEntry(0, m_SectionData);
548  createEntry(Mips64ModulePtr, m_SectionData);
549}
550
551}  // namespace mcld
552