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