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 //===----------------------------------------------------------------------===// 32 MipsGOTEntry::MipsGOTEntry(uint64_t pContent, SectionData* pParent) 33 : GOT::Entry<4>(pContent, pParent) 34 {} 35 36 //===----------------------------------------------------------------------===// 37 // MipsGOT::GOTMultipart 38 //===----------------------------------------------------------------------===// 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 49 bool MipsGOT::GOTMultipart::isConsumed() const 50 { 51 return m_LocalNum == m_ConsumedLocal && 52 m_GlobalNum == m_ConsumedGlobal; 53 } 54 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 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 //===----------------------------------------------------------------------===// 74 MipsGOT::MipsGOT(LDSection& pSection) 75 : GOT(pSection), 76 m_pInput(NULL), 77 m_CurrentGOTPart(0) 78 { 79 } 80 81 SizeTraits<32>::Address MipsGOT::getGPDispAddress() const 82 { 83 return addr() + MipsGOTGpOffset; 84 } 85 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 93 bool MipsGOT::hasGOT1() const 94 { 95 return !m_MultipartList.empty(); 96 } 97 98 bool MipsGOT::hasMultipleGOT() const 99 { 100 return m_MultipartList.size() > 1; 101 } 102 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 129 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 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 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 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 188 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 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 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 233 void MipsGOT::finalizeScan(const Input& pInput) 234 { 235 } 236 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 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 283 bool MipsGOT::isPrimaryGOTConsumed() 284 { 285 return m_CurrentGOTPart > 0; 286 } 287 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 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 312 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 328 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 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 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 356 size_t MipsGOT::getLocalNum() const 357 { 358 assert(!m_MultipartList.empty() && "GOT is empty!"); 359 return m_MultipartList[0].m_LocalNum + MipsGOT0Num; 360 } 361 362 size_t MipsGOT::getGlobalNum() const 363 { 364 return m_SymbolOrderMap.size(); 365 } 366