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/MemoryRegion.h>
15 #include <mcld/Support/MsgHandling.h>
16 #include <mcld/Target/OutputRelocSection.h>
17
18 #include "MipsGOT.h"
19 #include "MipsRelocator.h"
20
21 namespace {
22 const size_t MipsGOT0Num = 1;
23 const size_t MipsGOTGpOffset = 0x7FF0;
24 const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF;
25 }
26
27 using namespace mcld;
28
29 //===----------------------------------------------------------------------===//
30 // MipsGOTEntry
31 //===----------------------------------------------------------------------===//
MipsGOTEntry(uint64_t pContent,SectionData * pParent)32 MipsGOTEntry::MipsGOTEntry(uint64_t pContent, SectionData* pParent)
33 : GOT::Entry<4>(pContent, pParent)
34 {}
35
36 //===----------------------------------------------------------------------===//
37 // MipsGOT::GOTMultipart
38 //===----------------------------------------------------------------------===//
GOTMultipart(size_t local,size_t global)39 MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global)
40 : m_LocalNum(local),
41 m_GlobalNum(global),
42 m_ConsumedLocal(0),
43 m_ConsumedGlobal(0),
44 m_pLastLocal(NULL),
45 m_pLastGlobal(NULL)
46 {
47 }
48
isConsumed() const49 bool MipsGOT::GOTMultipart::isConsumed() const
50 {
51 return m_LocalNum == m_ConsumedLocal &&
52 m_GlobalNum == m_ConsumedGlobal;
53 }
54
consumeLocal()55 void MipsGOT::GOTMultipart::consumeLocal()
56 {
57 assert(m_ConsumedLocal < m_LocalNum &&
58 "Consumed too many local GOT entries");
59 ++m_ConsumedLocal;
60 m_pLastLocal = llvm::cast<MipsGOTEntry>(m_pLastLocal->getNextNode());
61 }
62
consumeGlobal()63 void MipsGOT::GOTMultipart::consumeGlobal()
64 {
65 assert(m_ConsumedGlobal < m_GlobalNum &&
66 "Consumed too many global GOT entries");
67 ++m_ConsumedGlobal;
68 m_pLastGlobal = llvm::cast<MipsGOTEntry>(m_pLastGlobal->getNextNode());
69 }
70
71 //===----------------------------------------------------------------------===//
72 // MipsGOT
73 //===----------------------------------------------------------------------===//
MipsGOT(LDSection & pSection)74 MipsGOT::MipsGOT(LDSection& pSection)
75 : GOT(pSection),
76 m_pInput(NULL),
77 m_CurrentGOTPart(0)
78 {
79 }
80
getGPDispAddress() const81 SizeTraits<32>::Address MipsGOT::getGPDispAddress() const
82 {
83 return addr() + MipsGOTGpOffset;
84 }
85
reserve(size_t pNum)86 void MipsGOT::reserve(size_t pNum)
87 {
88 for (size_t i = 0; i < pNum; i++) {
89 new MipsGOTEntry(0, m_SectionData);
90 }
91 }
92
hasGOT1() const93 bool MipsGOT::hasGOT1() const
94 {
95 return !m_MultipartList.empty();
96 }
97
hasMultipleGOT() const98 bool MipsGOT::hasMultipleGOT() const
99 {
100 return m_MultipartList.size() > 1;
101 }
102
finalizeScanning(OutputRelocSection & pRelDyn)103 void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn)
104 {
105 for (MultipartListType::iterator it = m_MultipartList.begin();
106 it != m_MultipartList.end(); ++it) {
107 reserve(MipsGOT0Num);
108 it->m_pLastLocal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
109 reserve(it->m_LocalNum);
110 it->m_pLastGlobal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
111 reserve(it->m_GlobalNum);
112
113 if (it == m_MultipartList.begin())
114 // Reserve entries in the second part of the primary GOT.
115 // These entries correspond to the global symbols in all
116 // non-primary GOTs.
117 reserve(getGlobalNum() - it->m_GlobalNum);
118 else {
119 // Reserve reldyn entries for R_MIPS_REL32 relocations
120 // for all global entries of secondary GOTs.
121 // FIXME: (simon) Do not count local entries for non-pic.
122 size_t count = it->m_GlobalNum + it->m_LocalNum;
123 for (size_t i = 0; i < count; ++i)
124 pRelDyn.reserveEntry();
125 }
126 }
127 }
128
dynSymOrderCompare(const LDSymbol * pX,const LDSymbol * pY) const129 bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const
130 {
131 SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX);
132 SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY);
133
134 if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end())
135 return itX->second < itY->second;
136
137 return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end();
138 }
139
emit(MemoryRegion & pRegion)140 uint64_t MipsGOT::emit(MemoryRegion& pRegion)
141 {
142 uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
143
144 uint64_t result = 0;
145 for (iterator it = begin(), ie = end();
146 it != ie; ++it, ++buffer) {
147 MipsGOTEntry* got = &(llvm::cast<MipsGOTEntry>((*it)));
148 *buffer = static_cast<uint32_t>(got->getValue());
149 result += got->size();
150 }
151 return result;
152 }
153
initGOTList()154 void MipsGOT::initGOTList()
155 {
156 m_SymbolOrderMap.clear();
157
158 m_MultipartList.clear();
159 m_MultipartList.push_back(GOTMultipart());
160
161 m_MultipartList.back().m_Inputs.insert(m_pInput);
162
163 m_MergedGlobalSymbols.clear();
164 m_InputGlobalSymbols.clear();
165 m_MergedLocalSymbols.clear();
166 m_InputLocalSymbols.clear();
167 }
168
changeInput()169 void MipsGOT::changeInput()
170 {
171 m_MultipartList.back().m_Inputs.insert(m_pInput);
172
173 for (SymbolSetType::iterator it = m_InputLocalSymbols.begin(),
174 end = m_InputLocalSymbols.end();
175 it != end; ++it)
176 m_MergedLocalSymbols.insert(*it);
177
178 m_InputLocalSymbols.clear();
179
180 for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(),
181 end = m_InputGlobalSymbols.end();
182 it != end; ++it)
183 m_MergedGlobalSymbols.insert(it->first);
184
185 m_InputGlobalSymbols.clear();
186 }
187
isGOTFull() const188 bool MipsGOT::isGOTFull() const
189 {
190 uint64_t gotCount = MipsGOT0Num +
191 m_MultipartList.back().m_LocalNum +
192 m_MultipartList.back().m_GlobalNum;
193
194 gotCount += 1;
195
196 return (gotCount * mcld::MipsGOTEntry::EntrySize) > MipsGOTSize;
197 }
198
split()199 void MipsGOT::split()
200 {
201 m_MergedLocalSymbols.clear();
202 m_MergedGlobalSymbols.clear();
203
204 size_t uniqueCount = 0;
205 for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(),
206 end = m_InputGlobalSymbols.end();
207 it != end; ++it) {
208 if (it->second)
209 ++uniqueCount;
210 }
211
212 m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size();
213 m_MultipartList.back().m_GlobalNum -= uniqueCount;
214 m_MultipartList.back().m_Inputs.erase(m_pInput);
215
216 m_MultipartList.push_back(GOTMultipart(m_InputLocalSymbols.size(),
217 m_InputGlobalSymbols.size()));
218 m_MultipartList.back().m_Inputs.insert(m_pInput);
219 }
220
initializeScan(const Input & pInput)221 void MipsGOT::initializeScan(const Input& pInput)
222 {
223 if (m_pInput == NULL) {
224 m_pInput = &pInput;
225 initGOTList();
226 }
227 else {
228 m_pInput = &pInput;
229 changeInput();
230 }
231 }
232
finalizeScan(const Input & pInput)233 void MipsGOT::finalizeScan(const Input& pInput)
234 {
235 }
236
reserveLocalEntry(ResolveInfo & pInfo)237 bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo)
238 {
239 if (pInfo.type() != ResolveInfo::Section) {
240 if (m_InputLocalSymbols.count(&pInfo))
241 return false;
242
243 if (m_MergedLocalSymbols.count(&pInfo)) {
244 m_InputLocalSymbols.insert(&pInfo);
245 return false;
246 }
247 }
248
249 if (isGOTFull())
250 split();
251
252 if (pInfo.type() != ResolveInfo::Section)
253 m_InputLocalSymbols.insert(&pInfo);
254
255 ++m_MultipartList.back().m_LocalNum;
256 return true;
257 }
258
reserveGlobalEntry(ResolveInfo & pInfo)259 bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo)
260 {
261 if (m_InputGlobalSymbols.count(&pInfo))
262 return false;
263
264 if (m_MergedGlobalSymbols.count(&pInfo)) {
265 m_InputGlobalSymbols[&pInfo] = false;
266 return false;
267 }
268
269 if (isGOTFull())
270 split();
271
272 m_InputGlobalSymbols[&pInfo] = true;
273 ++m_MultipartList.back().m_GlobalNum;
274
275 if (!(pInfo.reserved() & MipsRelocator::ReserveGot)) {
276 m_SymbolOrderMap[pInfo.outSymbol()] = m_SymbolOrderMap.size();
277 pInfo.setReserved(pInfo.reserved() | MipsRelocator::ReserveGot);
278 }
279
280 return true;
281 }
282
isPrimaryGOTConsumed()283 bool MipsGOT::isPrimaryGOTConsumed()
284 {
285 return m_CurrentGOTPart > 0;
286 }
287
consumeLocal()288 MipsGOTEntry* MipsGOT::consumeLocal()
289 {
290 assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
291
292 if (m_MultipartList[m_CurrentGOTPart].isConsumed())
293 ++m_CurrentGOTPart;
294
295 m_MultipartList[m_CurrentGOTPart].consumeLocal();
296
297 return m_MultipartList[m_CurrentGOTPart].m_pLastLocal;
298 }
299
consumeGlobal()300 MipsGOTEntry* MipsGOT::consumeGlobal()
301 {
302 assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
303
304 if (m_MultipartList[m_CurrentGOTPart].isConsumed())
305 ++m_CurrentGOTPart;
306
307 m_MultipartList[m_CurrentGOTPart].consumeGlobal();
308
309 return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal;
310 }
311
getGPAddr(const Input & pInput) const312 SizeTraits<32>::Address MipsGOT::getGPAddr(const Input& pInput) const
313 {
314 uint64_t gotSize = 0;
315 for (MultipartListType::const_iterator it = m_MultipartList.begin();
316 it != m_MultipartList.end(); ++it) {
317 if (it->m_Inputs.count(&pInput))
318 break;
319
320 gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum);
321 if (it == m_MultipartList.begin())
322 gotSize += getGlobalNum() - it->m_GlobalNum;
323 }
324
325 return addr() + gotSize * MipsGOTEntry::EntrySize + MipsGOTGpOffset;
326 }
327
getGPRelOffset(const Input & pInput,const MipsGOTEntry & pEntry) const328 SizeTraits<32>::Offset MipsGOT::getGPRelOffset(const Input& pInput,
329 const MipsGOTEntry& pEntry) const
330 {
331 SizeTraits<32>::Address gpAddr = getGPAddr(pInput);
332 return addr() + pEntry.getOffset() - gpAddr;
333 }
334
recordEntry(const ResolveInfo * pInfo,MipsGOTEntry * pEntry)335 void MipsGOT::recordEntry(const ResolveInfo* pInfo, MipsGOTEntry* pEntry)
336 {
337 GotEntryKey key;
338 key.m_GOTPage = m_CurrentGOTPart;
339 key.m_pInfo = pInfo;
340 m_GotEntriesMap[key] = pEntry;
341 }
342
lookupEntry(const ResolveInfo * pInfo)343 MipsGOTEntry* MipsGOT::lookupEntry(const ResolveInfo* pInfo)
344 {
345 GotEntryKey key;
346 key.m_GOTPage= m_CurrentGOTPart;
347 key.m_pInfo = pInfo;
348 GotEntryMapType::iterator it = m_GotEntriesMap.find(key);
349
350 if (it == m_GotEntriesMap.end())
351 return NULL;
352
353 return it->second;
354 }
355
getLocalNum() const356 size_t MipsGOT::getLocalNum() const
357 {
358 assert(!m_MultipartList.empty() && "GOT is empty!");
359 return m_MultipartList[0].m_LocalNum + MipsGOT0Num;
360 }
361
getGlobalNum() const362 size_t MipsGOT::getGlobalNum() const
363 {
364 return m_SymbolOrderMap.size();
365 }
366