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