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 //===----------------------------------------------------------------------===// 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 43 bool MipsGOT::GOTMultipart::isConsumed() const 44 { 45 return m_LocalNum == m_ConsumedLocal && 46 m_GlobalNum == m_ConsumedGlobal; 47 } 48 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 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 //===----------------------------------------------------------------------===// 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 76 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 //===----------------------------------------------------------------------===// 90 MipsGOT::MipsGOT(LDSection& pSection) 91 : GOT(pSection), 92 m_pInput(NULL), 93 m_CurrentGOTPart(0) 94 { 95 } 96 97 uint64_t MipsGOT::getGPDispAddress() const 98 { 99 return addr() + MipsGOTGpOffset; 100 } 101 102 void MipsGOT::reserve(size_t pNum) 103 { 104 for (size_t i = 0; i < pNum; i++) 105 createEntry(0, m_SectionData); 106 } 107 108 bool MipsGOT::hasGOT1() const 109 { 110 return !m_MultipartList.empty(); 111 } 112 113 bool MipsGOT::hasMultipleGOT() const 114 { 115 return m_MultipartList.size() > 1; 116 } 117 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 144 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 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 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 189 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 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 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 234 void MipsGOT::finalizeScan(const Input& pInput) 235 { 236 } 237 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 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 288 bool MipsGOT::isPrimaryGOTConsumed() 289 { 290 return m_CurrentGOTPart > 0; 291 } 292 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 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 317 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 333 uint64_t MipsGOT::getGPRelOffset(const Input& pInput, 334 const Fragment& pEntry) const 335 { 336 return addr() + pEntry.getOffset() - getGPAddr(pInput); 337 } 338 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 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 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 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 388 size_t MipsGOT::getLocalNum() const 389 { 390 assert(!m_MultipartList.empty() && "GOT is empty!"); 391 return m_MultipartList[0].m_LocalNum + MipsGOT0Num; 392 } 393 394 size_t MipsGOT::getGlobalNum() const 395 { 396 return m_SymbolOrderMap.size(); 397 } 398 399 //===----------------------------------------------------------------------===// 400 // Mips32GOT 401 //===----------------------------------------------------------------------===// 402 Mips32GOT::Mips32GOT(LDSection& pSection) 403 : MipsGOT(pSection) 404 {} 405 406 void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue) 407 { 408 llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue); 409 } 410 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 424 Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent) 425 { 426 return new Mips32GOTEntry(pValue, pParent); 427 } 428 429 size_t Mips32GOT::getEntrySize() const 430 { 431 return Mips32GOTEntry::EntrySize; 432 } 433 434 void Mips32GOT::reserveHeader() 435 { 436 createEntry(0, m_SectionData); 437 createEntry(Mips32ModulePtr, m_SectionData); 438 } 439 440 //===----------------------------------------------------------------------===// 441 // Mips64GOT 442 //===----------------------------------------------------------------------===// 443 Mips64GOT::Mips64GOT(LDSection& pSection) 444 : MipsGOT(pSection) 445 {} 446 447 void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue) 448 { 449 llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue); 450 } 451 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 465 Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent) 466 { 467 return new Mips64GOTEntry(pValue, pParent); 468 } 469 470 size_t Mips64GOT::getEntrySize() const 471 { 472 return Mips64GOTEntry::EntrySize; 473 } 474 475 void Mips64GOT::reserveHeader() 476 { 477 createEntry(0, m_SectionData); 478 createEntry(Mips64ModulePtr, m_SectionData); 479 } 480