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 
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 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 
isConsumed() const42 bool MipsGOT::GOTMultipart::isConsumed() const {
43   return m_LocalNum == m_ConsumedLocal && m_GlobalNum == m_ConsumedGlobal;
44 }
45 
consumeLocal()46 void MipsGOT::GOTMultipart::consumeLocal() {
47   assert(m_ConsumedLocal < m_LocalNum && "Consumed too many local GOT entries");
48   ++m_ConsumedLocal;
49   m_pLastLocal = m_pLastLocal->getNextNode();
50 }
51 
consumeGlobal()52 void MipsGOT::GOTMultipart::consumeGlobal() {
53   assert(m_ConsumedGlobal < m_GlobalNum &&
54          "Consumed too many global GOT entries");
55   ++m_ConsumedGlobal;
56   m_pLastGlobal = m_pLastGlobal->getNextNode();
57 }
58 
59 //===----------------------------------------------------------------------===//
60 // MipsGOT::LocalEntry
61 //===----------------------------------------------------------------------===//
LocalEntry(const ResolveInfo * pInfo,Relocation::DWord addend,bool isGot16)62 MipsGOT::LocalEntry::LocalEntry(const ResolveInfo* pInfo,
63                                 Relocation::DWord addend,
64                                 bool isGot16)
65     : m_pInfo(pInfo), m_Addend(addend), m_IsGot16(isGot16) {
66 }
67 
operator <(const LocalEntry & O) const68 bool MipsGOT::LocalEntry::operator<(const LocalEntry& O) const {
69   if (m_pInfo != O.m_pInfo)
70     return m_pInfo < O.m_pInfo;
71 
72   if (m_Addend != O.m_Addend)
73     return m_Addend < O.m_Addend;
74 
75   return m_IsGot16 < O.m_IsGot16;
76 }
77 
78 //===----------------------------------------------------------------------===//
79 // MipsGOT
80 //===----------------------------------------------------------------------===//
MipsGOT(LDSection & pSection)81 MipsGOT::MipsGOT(LDSection& pSection)
82     : GOT(pSection), m_pInput(NULL), m_CurrentGOTPart(0) {
83 }
84 
getGPDispAddress() const85 uint64_t MipsGOT::getGPDispAddress() const {
86   return addr() + MipsGOTGpOffset;
87 }
88 
reserve(size_t pNum)89 void MipsGOT::reserve(size_t pNum) {
90   for (size_t i = 0; i < pNum; ++i)
91     createEntry(0, m_SectionData);
92 }
93 
hasGOT1() const94 bool MipsGOT::hasGOT1() const {
95   return !m_MultipartList.empty();
96 }
97 
hasMultipleGOT() const98 bool MipsGOT::hasMultipleGOT() const {
99   return m_MultipartList.size() > 1;
100 }
101 
finalizeScanning(OutputRelocSection & pRelDyn)102 void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn) {
103   for (MultipartListType::iterator it = m_MultipartList.begin();
104        it != m_MultipartList.end();
105        ++it) {
106     reserveHeader();
107     it->m_pLastLocal = &m_SectionData->back();
108     reserve(it->m_LocalNum);
109     it->m_pLastGlobal = &m_SectionData->back();
110     reserve(it->m_GlobalNum);
111 
112     if (it == m_MultipartList.begin()) {
113       // Reserve entries in the second part of the primary GOT.
114       // These entries correspond to the global symbols in all
115       // non-primary GOTs.
116       reserve(getGlobalNum() - it->m_GlobalNum);
117     } else {
118       // Reserve reldyn entries for R_MIPS_REL32 relocations
119       // for all global entries of secondary GOTs.
120       // FIXME: (simon) Do not count local entries for non-pic.
121       size_t count = it->m_GlobalNum + it->m_LocalNum;
122       for (size_t i = 0; i < count; ++i)
123         pRelDyn.reserveEntry();
124     }
125   }
126 }
127 
dynSymOrderCompare(const LDSymbol * pX,const LDSymbol * pY) const128 bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const {
129   SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX);
130   SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY);
131 
132   if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end())
133     return itX->second < itY->second;
134 
135   return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end();
136 }
137 
initGOTList()138 void MipsGOT::initGOTList() {
139   m_SymbolOrderMap.clear();
140 
141   m_MultipartList.clear();
142   m_MultipartList.push_back(GOTMultipart());
143 
144   m_MultipartList.back().m_Inputs.insert(m_pInput);
145 
146   m_MergedGlobalSymbols.clear();
147   m_InputGlobalSymbols.clear();
148   m_MergedLocalSymbols.clear();
149   m_InputLocalSymbols.clear();
150 }
151 
changeInput()152 void MipsGOT::changeInput() {
153   m_MultipartList.back().m_Inputs.insert(m_pInput);
154 
155   for (LocalSymbolSetType::iterator it = m_InputLocalSymbols.begin(),
156                                     end = m_InputLocalSymbols.end();
157        it != end;
158        ++it)
159     m_MergedLocalSymbols.insert(*it);
160 
161   m_InputLocalSymbols.clear();
162 
163   for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(),
164                                      end = m_InputGlobalSymbols.end();
165        it != end;
166        ++it)
167     m_MergedGlobalSymbols.insert(it->first);
168 
169   m_InputGlobalSymbols.clear();
170 }
171 
isGOTFull() const172 bool MipsGOT::isGOTFull() const {
173   uint64_t gotCount = MipsGOT0Num + m_MultipartList.back().m_LocalNum +
174                       m_MultipartList.back().m_GlobalNum;
175 
176   gotCount += 1;
177 
178   return gotCount * getEntrySize() > MipsGOTSize;
179 }
180 
split()181 void MipsGOT::split() {
182   m_MergedLocalSymbols.clear();
183   m_MergedGlobalSymbols.clear();
184 
185   size_t uniqueCount = 0;
186   for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(),
187                                            end = m_InputGlobalSymbols.end();
188        it != end;
189        ++it) {
190     if (it->second)
191       ++uniqueCount;
192   }
193 
194   m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size();
195   m_MultipartList.back().m_GlobalNum -= uniqueCount;
196   m_MultipartList.back().m_Inputs.erase(m_pInput);
197 
198   m_MultipartList.push_back(
199       GOTMultipart(m_InputLocalSymbols.size(), m_InputGlobalSymbols.size()));
200   m_MultipartList.back().m_Inputs.insert(m_pInput);
201 }
202 
initializeScan(const Input & pInput)203 void MipsGOT::initializeScan(const Input& pInput) {
204   if (m_pInput == NULL) {
205     m_pInput = &pInput;
206     initGOTList();
207   } else {
208     m_pInput = &pInput;
209     changeInput();
210   }
211 }
212 
finalizeScan(const Input & pInput)213 void MipsGOT::finalizeScan(const Input& pInput) {
214 }
215 
reserveLocalEntry(ResolveInfo & pInfo,int reloc,Relocation::DWord pAddend)216 bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo,
217                                 int reloc,
218                                 Relocation::DWord pAddend) {
219   LocalEntry entry(&pInfo, pAddend, reloc == llvm::ELF::R_MIPS_GOT16);
220 
221   if (m_InputLocalSymbols.count(entry))
222     // Do nothing, if we have seen this symbol
223     // in the current input already.
224     return false;
225 
226   if (m_MergedLocalSymbols.count(entry)) {
227     // We have seen this symbol in previous inputs.
228     // Remember that it exists in the current input too.
229     m_InputLocalSymbols.insert(entry);
230     return false;
231   }
232 
233   if (isGOTFull())
234     split();
235 
236   m_InputLocalSymbols.insert(entry);
237 
238   ++m_MultipartList.back().m_LocalNum;
239   return true;
240 }
241 
reserveGlobalEntry(ResolveInfo & pInfo)242 bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo) {
243   if (m_InputGlobalSymbols.count(&pInfo))
244     return false;
245 
246   if (m_MergedGlobalSymbols.count(&pInfo)) {
247     m_InputGlobalSymbols[&pInfo] = false;
248     return false;
249   }
250 
251   if (isGOTFull())
252     split();
253 
254   m_InputGlobalSymbols[&pInfo] = true;
255   ++m_MultipartList.back().m_GlobalNum;
256 
257   if (!(pInfo.reserved() & MipsRelocator::ReserveGot)) {
258     m_SymbolOrderMap[pInfo.outSymbol()] = m_SymbolOrderMap.size();
259     pInfo.setReserved(pInfo.reserved() | MipsRelocator::ReserveGot);
260   }
261 
262   return true;
263 }
264 
isPrimaryGOTConsumed()265 bool MipsGOT::isPrimaryGOTConsumed() {
266   return m_CurrentGOTPart > 0;
267 }
268 
consumeLocal()269 Fragment* MipsGOT::consumeLocal() {
270   assert(m_CurrentGOTPart < m_MultipartList.size() &&
271          "GOT number is out of range!");
272 
273   if (m_MultipartList[m_CurrentGOTPart].isConsumed())
274     ++m_CurrentGOTPart;
275 
276   m_MultipartList[m_CurrentGOTPart].consumeLocal();
277 
278   return m_MultipartList[m_CurrentGOTPart].m_pLastLocal;
279 }
280 
consumeGlobal()281 Fragment* MipsGOT::consumeGlobal() {
282   assert(m_CurrentGOTPart < m_MultipartList.size() &&
283          "GOT number is out of range!");
284 
285   if (m_MultipartList[m_CurrentGOTPart].isConsumed())
286     ++m_CurrentGOTPart;
287 
288   m_MultipartList[m_CurrentGOTPart].consumeGlobal();
289 
290   return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal;
291 }
292 
getGPAddr(const Input & pInput) const293 uint64_t MipsGOT::getGPAddr(const Input& pInput) const {
294   uint64_t gotSize = 0;
295   for (MultipartListType::const_iterator it = m_MultipartList.begin(),
296                                          ie = m_MultipartList.end();
297        it != ie;
298        ++it) {
299     if (it->m_Inputs.count(&pInput))
300       break;
301 
302     gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum);
303     if (it == m_MultipartList.begin())
304       gotSize += getGlobalNum() - it->m_GlobalNum;
305   }
306 
307   return addr() + gotSize * getEntrySize() + MipsGOTGpOffset;
308 }
309 
getGPRelOffset(const Input & pInput,const Fragment & pEntry) const310 uint64_t MipsGOT::getGPRelOffset(const Input& pInput,
311                                  const Fragment& pEntry) const {
312   return addr() + pEntry.getOffset() - getGPAddr(pInput);
313 }
314 
recordGlobalEntry(const ResolveInfo * pInfo,Fragment * pEntry)315 void MipsGOT::recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry) {
316   GotEntryKey key;
317   key.m_GOTPage = m_CurrentGOTPart;
318   key.m_pInfo = pInfo;
319   key.m_Addend = 0;
320   m_GotGlobalEntriesMap[key] = pEntry;
321 }
322 
lookupGlobalEntry(const ResolveInfo * pInfo)323 Fragment* MipsGOT::lookupGlobalEntry(const ResolveInfo* pInfo) {
324   GotEntryKey key;
325   key.m_GOTPage = m_CurrentGOTPart;
326   key.m_pInfo = pInfo;
327   key.m_Addend = 0;
328   GotEntryMapType::iterator it = m_GotGlobalEntriesMap.find(key);
329 
330   if (it == m_GotGlobalEntriesMap.end())
331     return NULL;
332 
333   return it->second;
334 }
335 
recordLocalEntry(const ResolveInfo * pInfo,Relocation::DWord pAddend,Fragment * pEntry)336 void MipsGOT::recordLocalEntry(const ResolveInfo* pInfo,
337                                Relocation::DWord pAddend,
338                                Fragment* pEntry) {
339   GotEntryKey key;
340   key.m_GOTPage = m_CurrentGOTPart;
341   key.m_pInfo = pInfo;
342   key.m_Addend = pAddend;
343   m_GotLocalEntriesMap[key] = pEntry;
344 }
345 
lookupLocalEntry(const ResolveInfo * pInfo,Relocation::DWord pAddend)346 Fragment* MipsGOT::lookupLocalEntry(const ResolveInfo* pInfo,
347                                     Relocation::DWord pAddend) {
348   GotEntryKey key;
349   key.m_GOTPage = m_CurrentGOTPart;
350   key.m_pInfo = pInfo;
351   key.m_Addend = pAddend;
352   GotEntryMapType::iterator it = m_GotLocalEntriesMap.find(key);
353 
354   if (it == m_GotLocalEntriesMap.end())
355     return NULL;
356 
357   return it->second;
358 }
359 
getLocalNum() const360 size_t MipsGOT::getLocalNum() const {
361   assert(!m_MultipartList.empty() && "GOT is empty!");
362   return m_MultipartList[0].m_LocalNum + MipsGOT0Num;
363 }
364 
getGlobalNum() const365 size_t MipsGOT::getGlobalNum() const {
366   return m_SymbolOrderMap.size();
367 }
368 
369 //===----------------------------------------------------------------------===//
370 // Mips32GOT
371 //===----------------------------------------------------------------------===//
Mips32GOT(LDSection & pSection)372 Mips32GOT::Mips32GOT(LDSection& pSection) : MipsGOT(pSection) {
373 }
374 
setEntryValue(Fragment * entry,uint64_t pValue)375 void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue) {
376   llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue);
377 }
378 
emit(MemoryRegion & pRegion)379 uint64_t Mips32GOT::emit(MemoryRegion& pRegion) {
380   uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
381 
382   uint64_t result = 0;
383   for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
384     Mips32GOTEntry* got = &(llvm::cast<Mips32GOTEntry>((*it)));
385     *buffer = static_cast<uint32_t>(got->getValue());
386     result += got->size();
387   }
388   return result;
389 }
390 
createEntry(uint64_t pValue,SectionData * pParent)391 Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent) {
392   return new Mips32GOTEntry(pValue, pParent);
393 }
394 
getEntrySize() const395 size_t Mips32GOT::getEntrySize() const {
396   return Mips32GOTEntry::EntrySize;
397 }
398 
reserveHeader()399 void Mips32GOT::reserveHeader() {
400   createEntry(0, m_SectionData);
401   createEntry(Mips32ModulePtr, m_SectionData);
402 }
403 
404 //===----------------------------------------------------------------------===//
405 // Mips64GOT
406 //===----------------------------------------------------------------------===//
Mips64GOT(LDSection & pSection)407 Mips64GOT::Mips64GOT(LDSection& pSection) : MipsGOT(pSection) {
408 }
409 
setEntryValue(Fragment * entry,uint64_t pValue)410 void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue) {
411   llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue);
412 }
413 
emit(MemoryRegion & pRegion)414 uint64_t Mips64GOT::emit(MemoryRegion& pRegion) {
415   uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
416 
417   uint64_t result = 0;
418   for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
419     Mips64GOTEntry* got = &(llvm::cast<Mips64GOTEntry>((*it)));
420     *buffer = static_cast<uint64_t>(got->getValue());
421     result += got->size();
422   }
423   return result;
424 }
425 
createEntry(uint64_t pValue,SectionData * pParent)426 Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent) {
427   return new Mips64GOTEntry(pValue, pParent);
428 }
429 
getEntrySize() const430 size_t Mips64GOT::getEntrySize() const {
431   return Mips64GOTEntry::EntrySize;
432 }
433 
reserveHeader()434 void Mips64GOT::reserveHeader() {
435   createEntry(0, m_SectionData);
436   createEntry(Mips64ModulePtr, m_SectionData);
437 }
438 
439 }  // namespace mcld
440