• 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/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