• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/MsgHandling.h>
15 #include <mcld/Target/OutputRelocSection.h>
16 
17 #include "MipsGOT.h"
18 #include "MipsRelocator.h"
19 
20 namespace {
21   const uint32_t Mips32ModulePtr = 1 << 31;
22   const uint64_t Mips64ModulePtr = 1ull << 63;
23   const size_t MipsGOT0Num = 2;
24   const size_t MipsGOTGpOffset = 0x7FF0;
25   const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF;
26 }
27 
28 using namespace mcld;
29 
30 //===----------------------------------------------------------------------===//
31 // MipsGOT::GOTMultipart
32 //===----------------------------------------------------------------------===//
GOTMultipart(size_t local,size_t global)33 MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global)
34   : m_LocalNum(local),
35     m_GlobalNum(global),
36     m_ConsumedLocal(0),
37     m_ConsumedGlobal(0),
38     m_pLastLocal(NULL),
39     m_pLastGlobal(NULL)
40 {
41 }
42 
isConsumed() const43 bool MipsGOT::GOTMultipart::isConsumed() const
44 {
45   return m_LocalNum == m_ConsumedLocal &&
46          m_GlobalNum == m_ConsumedGlobal;
47 }
48 
consumeLocal()49 void MipsGOT::GOTMultipart::consumeLocal()
50 {
51   assert(m_ConsumedLocal < m_LocalNum &&
52          "Consumed too many local GOT entries");
53   ++m_ConsumedLocal;
54   m_pLastLocal = m_pLastLocal->getNextNode();
55 }
56 
consumeGlobal()57 void MipsGOT::GOTMultipart::consumeGlobal()
58 {
59   assert(m_ConsumedGlobal < m_GlobalNum &&
60          "Consumed too many global GOT entries");
61   ++m_ConsumedGlobal;
62   m_pLastGlobal = m_pLastGlobal->getNextNode();
63 }
64 
65 //===----------------------------------------------------------------------===//
66 // MipsGOT::LocalEntry
67 //===----------------------------------------------------------------------===//
LocalEntry(const ResolveInfo * pInfo,Relocation::DWord addend,bool isGot16)68 MipsGOT::LocalEntry::LocalEntry(const ResolveInfo* pInfo,
69                                 Relocation::DWord addend, bool isGot16)
70   : m_pInfo(pInfo),
71     m_Addend(addend),
72     m_IsGot16(isGot16)
73 {
74 }
75 
operator <(const LocalEntry & O) const76 bool MipsGOT::LocalEntry::operator<(const LocalEntry &O) const
77 {
78   if (m_pInfo != O.m_pInfo)
79     return m_pInfo < O.m_pInfo;
80 
81   if (m_Addend != O.m_Addend)
82     return m_Addend < O.m_Addend;
83 
84   return m_IsGot16 < O.m_IsGot16;
85 }
86 
87 //===----------------------------------------------------------------------===//
88 // MipsGOT
89 //===----------------------------------------------------------------------===//
MipsGOT(LDSection & pSection)90 MipsGOT::MipsGOT(LDSection& pSection)
91   : GOT(pSection),
92     m_pInput(NULL),
93     m_CurrentGOTPart(0)
94 {
95 }
96 
getGPDispAddress() const97 uint64_t MipsGOT::getGPDispAddress() const
98 {
99   return addr() + MipsGOTGpOffset;
100 }
101 
reserve(size_t pNum)102 void MipsGOT::reserve(size_t pNum)
103 {
104   for (size_t i = 0; i < pNum; i++)
105     createEntry(0, m_SectionData);
106 }
107 
hasGOT1() const108 bool MipsGOT::hasGOT1() const
109 {
110   return !m_MultipartList.empty();
111 }
112 
hasMultipleGOT() const113 bool MipsGOT::hasMultipleGOT() const
114 {
115   return m_MultipartList.size() > 1;
116 }
117 
finalizeScanning(OutputRelocSection & pRelDyn)118 void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn)
119 {
120   for (MultipartListType::iterator it = m_MultipartList.begin();
121        it != m_MultipartList.end(); ++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 
128     if (it == m_MultipartList.begin())
129       // Reserve entries in the second part of the primary GOT.
130       // These entries correspond to the global symbols in all
131       // non-primary GOTs.
132       reserve(getGlobalNum() - it->m_GlobalNum);
133     else {
134       // Reserve reldyn entries for R_MIPS_REL32 relocations
135       // for all global entries of secondary GOTs.
136       // FIXME: (simon) Do not count local entries for non-pic.
137       size_t count = it->m_GlobalNum + it->m_LocalNum;
138       for (size_t i = 0; i < count; ++i)
139         pRelDyn.reserveEntry();
140     }
141   }
142 }
143 
dynSymOrderCompare(const LDSymbol * pX,const LDSymbol * pY) const144 bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const
145 {
146   SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX);
147   SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY);
148 
149   if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end())
150     return itX->second < itY->second;
151 
152   return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end();
153 }
154 
initGOTList()155 void MipsGOT::initGOTList()
156 {
157   m_SymbolOrderMap.clear();
158 
159   m_MultipartList.clear();
160   m_MultipartList.push_back(GOTMultipart());
161 
162   m_MultipartList.back().m_Inputs.insert(m_pInput);
163 
164   m_MergedGlobalSymbols.clear();
165   m_InputGlobalSymbols.clear();
166   m_MergedLocalSymbols.clear();
167   m_InputLocalSymbols.clear();
168 }
169 
changeInput()170 void MipsGOT::changeInput()
171 {
172   m_MultipartList.back().m_Inputs.insert(m_pInput);
173 
174   for (LocalSymbolSetType::iterator it = m_InputLocalSymbols.begin(),
175                                     end = m_InputLocalSymbols.end();
176        it != end; ++it)
177     m_MergedLocalSymbols.insert(*it);
178 
179   m_InputLocalSymbols.clear();
180 
181   for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(),
182                                      end = m_InputGlobalSymbols.end();
183        it != end; ++it)
184     m_MergedGlobalSymbols.insert(it->first);
185 
186   m_InputGlobalSymbols.clear();
187 }
188 
isGOTFull() const189 bool MipsGOT::isGOTFull() const
190 {
191   uint64_t gotCount = MipsGOT0Num +
192                       m_MultipartList.back().m_LocalNum +
193                       m_MultipartList.back().m_GlobalNum;
194 
195   gotCount += 1;
196 
197   return gotCount * getEntrySize() > MipsGOTSize;
198 }
199 
split()200 void MipsGOT::split()
201 {
202   m_MergedLocalSymbols.clear();
203   m_MergedGlobalSymbols.clear();
204 
205   size_t uniqueCount = 0;
206   for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(),
207                                            end = m_InputGlobalSymbols.end();
208        it != end; ++it) {
209     if (it->second)
210       ++uniqueCount;
211   }
212 
213   m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size();
214   m_MultipartList.back().m_GlobalNum -= uniqueCount;
215   m_MultipartList.back().m_Inputs.erase(m_pInput);
216 
217   m_MultipartList.push_back(GOTMultipart(m_InputLocalSymbols.size(),
218                                          m_InputGlobalSymbols.size()));
219   m_MultipartList.back().m_Inputs.insert(m_pInput);
220 }
221 
initializeScan(const Input & pInput)222 void MipsGOT::initializeScan(const Input& pInput)
223 {
224   if (m_pInput == NULL) {
225     m_pInput = &pInput;
226     initGOTList();
227   }
228   else {
229     m_pInput = &pInput;
230     changeInput();
231   }
232 }
233 
finalizeScan(const Input & pInput)234 void MipsGOT::finalizeScan(const Input& pInput)
235 {
236 }
237 
reserveLocalEntry(ResolveInfo & pInfo,int reloc,Relocation::DWord pAddend)238 bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo, int reloc,
239                                 Relocation::DWord pAddend)
240 {
241   LocalEntry entry(&pInfo, pAddend, reloc == llvm::ELF::R_MIPS_GOT16);
242 
243   if (m_InputLocalSymbols.count(entry))
244     // Do nothing, if we have seen this symbol
245     // in the current input already.
246     return false;
247 
248   if (m_MergedLocalSymbols.count(entry)) {
249     // We have seen this symbol in previous inputs.
250     // Remember that it exists in the current input too.
251     m_InputLocalSymbols.insert(entry);
252     return false;
253   }
254 
255   if (isGOTFull())
256     split();
257 
258   m_InputLocalSymbols.insert(entry);
259 
260   ++m_MultipartList.back().m_LocalNum;
261   return true;
262 }
263 
reserveGlobalEntry(ResolveInfo & pInfo)264 bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo)
265 {
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 
isPrimaryGOTConsumed()288 bool MipsGOT::isPrimaryGOTConsumed()
289 {
290   return m_CurrentGOTPart > 0;
291 }
292 
consumeLocal()293 Fragment* MipsGOT::consumeLocal()
294 {
295   assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
296 
297   if (m_MultipartList[m_CurrentGOTPart].isConsumed())
298     ++m_CurrentGOTPart;
299 
300   m_MultipartList[m_CurrentGOTPart].consumeLocal();
301 
302   return m_MultipartList[m_CurrentGOTPart].m_pLastLocal;
303 }
304 
consumeGlobal()305 Fragment* MipsGOT::consumeGlobal()
306 {
307   assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
308 
309   if (m_MultipartList[m_CurrentGOTPart].isConsumed())
310     ++m_CurrentGOTPart;
311 
312   m_MultipartList[m_CurrentGOTPart].consumeGlobal();
313 
314   return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal;
315 }
316 
getGPAddr(const Input & pInput) const317 uint64_t MipsGOT::getGPAddr(const Input& pInput) const
318 {
319   uint64_t gotSize = 0;
320   for (MultipartListType::const_iterator it = m_MultipartList.begin();
321                                          it != m_MultipartList.end(); ++it) {
322     if (it->m_Inputs.count(&pInput))
323       break;
324 
325     gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum);
326     if (it == m_MultipartList.begin())
327       gotSize += getGlobalNum() - it->m_GlobalNum;
328   }
329 
330   return addr() + gotSize * getEntrySize() + MipsGOTGpOffset;
331 }
332 
getGPRelOffset(const Input & pInput,const Fragment & pEntry) const333 uint64_t MipsGOT::getGPRelOffset(const Input& pInput,
334                                  const Fragment& pEntry) const
335 {
336   return addr() + pEntry.getOffset() - getGPAddr(pInput);
337 }
338 
recordGlobalEntry(const ResolveInfo * pInfo,Fragment * pEntry)339 void MipsGOT::recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry)
340 {
341   GotEntryKey key;
342   key.m_GOTPage = m_CurrentGOTPart;
343   key.m_pInfo = pInfo;
344   key.m_Addend = 0;
345   m_GotGlobalEntriesMap[key] = pEntry;
346 }
347 
lookupGlobalEntry(const ResolveInfo * pInfo)348 Fragment* MipsGOT::lookupGlobalEntry(const ResolveInfo* pInfo)
349 {
350   GotEntryKey key;
351   key.m_GOTPage= m_CurrentGOTPart;
352   key.m_pInfo = pInfo;
353   key.m_Addend = 0;
354   GotEntryMapType::iterator it = m_GotGlobalEntriesMap.find(key);
355 
356   if (it == m_GotGlobalEntriesMap.end())
357     return NULL;
358 
359   return it->second;
360 }
361 
recordLocalEntry(const ResolveInfo * pInfo,Relocation::DWord pAddend,Fragment * pEntry)362 void MipsGOT::recordLocalEntry(const ResolveInfo* pInfo,
363                                Relocation::DWord pAddend,
364                                Fragment* pEntry)
365 {
366   GotEntryKey key;
367   key.m_GOTPage = m_CurrentGOTPart;
368   key.m_pInfo = pInfo;
369   key.m_Addend = pAddend;
370   m_GotLocalEntriesMap[key] = pEntry;
371 }
372 
lookupLocalEntry(const ResolveInfo * pInfo,Relocation::DWord pAddend)373 Fragment* MipsGOT::lookupLocalEntry(const ResolveInfo* pInfo,
374                                     Relocation::DWord pAddend)
375 {
376   GotEntryKey key;
377   key.m_GOTPage= m_CurrentGOTPart;
378   key.m_pInfo = pInfo;
379   key.m_Addend = pAddend;
380   GotEntryMapType::iterator it = m_GotLocalEntriesMap.find(key);
381 
382   if (it == m_GotLocalEntriesMap.end())
383     return NULL;
384 
385   return it->second;
386 }
387 
getLocalNum() const388 size_t MipsGOT::getLocalNum() const
389 {
390   assert(!m_MultipartList.empty() && "GOT is empty!");
391   return m_MultipartList[0].m_LocalNum + MipsGOT0Num;
392 }
393 
getGlobalNum() const394 size_t MipsGOT::getGlobalNum() const
395 {
396   return m_SymbolOrderMap.size();
397 }
398 
399 //===----------------------------------------------------------------------===//
400 // Mips32GOT
401 //===----------------------------------------------------------------------===//
Mips32GOT(LDSection & pSection)402 Mips32GOT::Mips32GOT(LDSection& pSection)
403   : MipsGOT(pSection)
404 {}
405 
setEntryValue(Fragment * entry,uint64_t pValue)406 void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue)
407 {
408   llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue);
409 }
410 
emit(MemoryRegion & pRegion)411 uint64_t Mips32GOT::emit(MemoryRegion& pRegion)
412 {
413   uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
414 
415   uint64_t result = 0;
416   for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
417     Mips32GOTEntry* got = &(llvm::cast<Mips32GOTEntry>((*it)));
418     *buffer = static_cast<uint32_t>(got->getValue());
419     result += got->size();
420   }
421   return result;
422 }
423 
createEntry(uint64_t pValue,SectionData * pParent)424 Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent)
425 {
426   return new Mips32GOTEntry(pValue, pParent);
427 }
428 
getEntrySize() const429 size_t Mips32GOT::getEntrySize() const
430 {
431   return Mips32GOTEntry::EntrySize;
432 }
433 
reserveHeader()434 void Mips32GOT::reserveHeader()
435 {
436   createEntry(0, m_SectionData);
437   createEntry(Mips32ModulePtr, m_SectionData);
438 }
439 
440 //===----------------------------------------------------------------------===//
441 // Mips64GOT
442 //===----------------------------------------------------------------------===//
Mips64GOT(LDSection & pSection)443 Mips64GOT::Mips64GOT(LDSection& pSection)
444   : MipsGOT(pSection)
445 {}
446 
setEntryValue(Fragment * entry,uint64_t pValue)447 void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue)
448 {
449   llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue);
450 }
451 
emit(MemoryRegion & pRegion)452 uint64_t Mips64GOT::emit(MemoryRegion& pRegion)
453 {
454   uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
455 
456   uint64_t result = 0;
457   for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
458     Mips64GOTEntry* got = &(llvm::cast<Mips64GOTEntry>((*it)));
459     *buffer = static_cast<uint64_t>(got->getValue());
460     result += got->size();
461   }
462   return result;
463 }
464 
createEntry(uint64_t pValue,SectionData * pParent)465 Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent)
466 {
467   return new Mips64GOTEntry(pValue, pParent);
468 }
469 
getEntrySize() const470 size_t Mips64GOT::getEntrySize() const
471 {
472   return Mips64GOTEntry::EntrySize;
473 }
474 
reserveHeader()475 void Mips64GOT::reserveHeader()
476 {
477   createEntry(0, m_SectionData);
478   createEntry(Mips64ModulePtr, m_SectionData);
479 }
480